Node.js Lambda 関数をコンテナイメージとともにデプロイする - AWS Lambda

Node.js Lambda 関数をコンテナイメージとともにデプロイする

Node.js Lambda 関数のコンテナイメージを構築するには 3 つの方法があります。

ヒント

Lambda コンテナ関数がアクティブになるまでの時間を短縮するには、「Docker ドキュメント」の「マルチステージビルドを使用する」を参照してください。効率的なコンテナイメージを構築するには、「Dockerfiles を記述するためのベストプラクティス」に従ってください。

このページでは、Lambda のコンテナイメージを構築、テスト、デプロイする方法について説明します。

Node.js の AWS ベースイメージ

AWS では、Node.js 用の以下のベースイメージが利用できます。

タグ ランタイム オペレーティングシステム Dockerfile 廃止

20

Node.js 20 Amazon Linux 2023 GitHub にある Node.js 20 用の Dockerfile

18

Node.js 18 Amazon Linux 2 GitHub にある Node.js 18 用の Dockerfile

16

Node.js 16 Amazon Linux 2 GitHub にある Node.js 16 用の Dockerfile

2024 年 6 月 12 日

Amazon ECR リポジトリ: gallery.ecr.aws/lambda/nodejs

Node.js 20 以降のベースイメージは、Amazon Linux 2023 の最小コンテナイメージに基づいています。以前のベースイメージでは Amazon Linux 2 が使用されています。AL2023 ランタイムには、デプロイのフットプリントが小さいことや、glibc などのライブラリのバージョンが更新されていることなど、Amazon Linux 2 に比べていくつかの利点があります。

AL2023 ベースのイメージでは、Amazon Linux 2 のデフォルトのパッケージマネージャである yum の代わりに microdnf (dnf としてシンボリックリンク) がパッケージマネージャとして使用されています。microdnfdnf のスタンドアロン実装です。AL2023 ベースのイメージに含まれるパッケージのリストについては、「Comparing packages installed on Amazon Linux 2023 Container Images」の「Minimal Container」列を参照してください。AL2023 と Amazon Linux 2 の違いの詳細については、AWS コンピューティングブログの「Introducing the Amazon Linux 2023 runtime for AWS Lambda」を参照してください。

注記

AWS Serverless Application Model (AWS SAM) を含む AL2023 ベースのイメージをローカルで実行するには、Docker バージョン 20.10.10 以降を使用する必要があります。

Node.js の AWS ベースイメージを使用する

このセクションの手順を完了するには、以下が必要です。

Node.js の AWS ベースイメージからコンテナイメージを作成する方法
  1. プロジェクト用のディレクトリを作成し、そのディレクトリに切り替えます。

    mkdir example cd example
  2. npm で新しい Node.js プロジェクトを作成します。インタラクティブな形式で提供されるデフォルトオプションを受け入れるには、Enter を押します。

    npm init
  3. index.js という名前の新しいファイルを作成します。テスト用に次のサンプル関数コードをファイルに追加することも、独自のコードを使用することもできます。

    例 CommonJS ハンドラー
    exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
  4. 関数が AWS SDK for JavaScript 以外のライブラリに依存している場合、「npm」を使用してパッケージに追加します。

  5. 次の設定で新しい Dockerfile を作成します。

    • FROM プロパティを「ベースイメージの URI」に設定します。

    • COPY コマンドを使用し、関数コードおよびランタイムの依存関係を {LAMBDA_TASK_ROOT} (Lambda 定義の環境変数) にコピーします。

    • CMD 引数を Lambda 関数ハンドラーに設定します。

    例 Dockerfile
    FROM public.ecr.aws/lambda/nodejs:20 # Copy function code COPY index.js ${LAMBDA_TASK_ROOT} # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile) CMD [ "index.handler" ]
  6. Docker イメージを「Docker の構築」コマンドで構築します。次の例では、イメージを docker-image と名付けて test タグを付けます。

    docker build --platform linux/amd64 -t docker-image:test .
    注記

    このコマンドは、ビルドマシンのアーキテクチャに関係なく、コンテナが Lambda の実行環境と互換性があることを確認する --platform linux/amd64 オプションを特定します。ARM64 命令セットアーキテクチャを使用して Lambda 関数を作成する場合は、代わりに --platform linux/arm64 オプションを使用するようにコマンドを変更してください。

  1. docker run コマンドを使用して、Docker イメージを起動します。この例では、docker-image はイメージ名、test はタグです。

    docker run --platform linux/amd64 -p 9000:8080 docker-image:test

    このコマンドはイメージをコンテナとして実行し、localhost:9000/2015-03-31/functions/function/invocations でローカルエンドポイントを作成します。

    注記

    ARM64 命令セットアーキテクチャ用に Docker イメージをビルドした場合は、--platform linux/amd64 の代わりに --platform linux/arm64 オプションを使用してください。

  2. 新しいターミナルウィンドウから、イベントをローカルエンドポイントにポストします。

    Linux/macOS

    Linux および macOS では、次の curl コマンドを実行します。

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

    このコマンドは、空のイベントで関数を呼び出し、応答を返します。サンプル関数コードではなく独自の関数コードを使用している場合は、JSON ペイロードを使用して関数を呼び出すことをお勧めします。例:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
    PowerShell

    PowerShell で次の Invoke-WebRequest コマンドを実行します。

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"

    このコマンドは、空のイベントで関数を呼び出し、応答を返します。サンプル関数コードではなく独自の関数コードを使用している場合は、JSON ペイロードを使用して関数を呼び出すことをお勧めします。例:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
  3. コンテナ ID を取得します。

    docker ps
  4. docker kill」コマンドを使用してコンテナを停止します。このコマンドでは、3766c4ab331c を前のステップのコンテナ ID で置き換えます。

    docker kill 3766c4ab331c
Amazon ECR にイメージをアップロードして Lambda 関数を作成するには
  1. get-login-password」コマンドを実行して Amazon ECR レジストリに Docker CLI を認証します。

    • --region 値を Amazon ECR リポジトリを作成する AWS リージョン に設定します。

    • 111122223333 を AWS アカウント ID に置き換えます。

    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
  2. create-repository」コマンドを使用して Amazon ECR にリポジトリを作成します。

    aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
    注記

    Amazon ECR リポジトリは Lambda 関数と同じ AWS リージョン に配置されている必要があります。

    成功すると、次のようなレスポンスが表示されます。

    { "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
  3. 前のステップの出力から repositoryUri をコピーします。

  4. docker tag」コマンドを実行して、最新バージョンとしてローカルイメージを Amazon ECR リポジトリにタグ付けします。このコマンドで:

    • docker-image:test をお使いの Docker イメージの名前およびタグで置き換えます。

    • <ECRrepositoryUri> を、コピーした repositoryUri に置き換えます。URI の末尾には必ず :latest を含めてください。

    docker tag docker-image:test <ECRrepositoryUri>:latest

    例:

    docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  5. docker push」コマンドを実行して Amazon ECR リポジトリにローカルイメージをデプロイします リポジトリ URI の末尾には必ず :latest を含めてください。

    docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  6. まだ作成済みでない場合、関数に「実行ロールの作成」を実行してください。次のステップではロールの Amazon リソースネーム (ARN) が必要です。

  7. Lambda 関数を作成します。ImageUri には、先ほど使用したリポジトリ URI を指定します。URI の末尾には必ず :latest を含めてください。

    aws lambda create-function \ --function-name hello-world \ --package-type Image \ --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --role arn:aws:iam::111122223333:role/lambda-ex
    注記

    イメージが Lambda 関数と同じリージョンに配置されていれば、別の AWS アカウントのイメージを使用して関数を作成することができます。詳細については、「 Amazon ECR クロスアカウント許可」を参照してください。

  8. 関数を呼び出します。

    aws lambda invoke --function-name hello-world response.json

    次のような結果が表示されます。

    { "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  9. 関数の出力を確認するには、response.json ファイルをチェックします。

関数コードを更新するには、イメージを再構築し、新しいイメージを Amazon ECR リポジトリにアップロードしてから、update-function-code コマンドを使用してイメージを Lambda 関数にデプロイする必要があります。

Lambda は、イメージタグを特定のイメージダイジェストに解決します。これは、関数のデプロイに使用されたイメージタグを Amazon ECR 内の新しいイメージを指すように変更しても、Lambda は新しいイメージを使用するように自動的に関数を更新しないことを意味します。新しいイメージを同じ Lambda 関数にデプロイするには、Amazon ECR のイメージタグが同じままであっても、update-function-code コマンドを使用する必要があります。

ランタイムインターフェイスクライアントで代替ベースイメージを使用する

OS 専用ベースイメージまたは代替のベースイメージを使用する場合、イメージにランタイムインターフェイスクライアントを含める必要があります。ランタイムインターフェイスクライアントは、Lambda と関数コード間の相互作用を管理する カスタムランタイムに Lambda ランタイム API を使用する を拡張します。

npm パッケージマネージャーを使用して、Node.js 用のランタイムインターフェイスクライアントをインストールします。

npm install aws-lambda-ric

Node.js のランタイムインターフェイスクライアントを GitHub からダウンロードすることもできます。ランタイムインターフェイスクライアントは、次の NodeJS バージョンをサポートしています。

  • 14.x

  • 16.x

  • 18.x

  • 20.x

次の例は、非 AWS ベースイメージを使用して、 Node.js 用のコンテナイメージを構築する方法について説明しています。buster ベースイメージを使用した Dockerfile の例を示します。Dockerfile には、ランタイムインターフェイスクライアントが含まれています。

このセクションの手順を完了するには、以下が必要です。

非 AWS ベースイメージからコンテナイメージを作成するには
  1. プロジェクト用のディレクトリを作成し、そのディレクトリに切り替えます。

    mkdir example cd example
  2. npm で新しい Node.js プロジェクトを作成します。インタラクティブな形式で提供されるデフォルトオプションを受け入れるには、Enter を押します。

    npm init
  3. index.js という名前の新しいファイルを作成します。テスト用に次のサンプル関数コードをファイルに追加することも、独自のコードを使用することもできます。

    例 CommonJS ハンドラー
    exports.handler = async (event) => { const response = { statusCode: 200, body: JSON.stringify('Hello from Lambda!'), }; return response; };
  4. 新しい Dockerfile を作成します。次の Dockerfile では、AWS ベースイメージの代わりに buster ベースイメージを使用します。Dockerfile には、イメージに Lambda との互換性を持たせるランタイムインターフェイスクライアントが含まれています。Dockerfile では、マルチステージビルドを使用します。第 1 段階では、関数の依存関係がインストールされた標準の Node.js 環境であるビルドイメージを作成します。第2段階では、関数コードとその依存関係を含むスリムなイメージを作成します。これにより、最終的なイメージサイズが小さくなります。

    • ベースイメージ識別子に FROM プロパティを設定します。

    • COPY コマンドを使用して、関数コードおよびランタイムの依存関係をコピーします。

    • ENTRYPOINT を、Docker コンテナの起動時に実行させるモジュールに設定します。この場合、モジュールはランタイムインターフェイスクライアントです。

    • CMD 引数を Lambda 関数ハンドラーに設定します。

    例 Dockerfile
    # Define custom function directory ARG FUNCTION_DIR="/function" FROM node:20-buster as build-image # Include global arg in this stage of the build ARG FUNCTION_DIR # Install build dependencies RUN apt-get update && \ apt-get install -y \ g++ \ make \ cmake \ unzip \ libcurl4-openssl-dev # Copy function code RUN mkdir -p ${FUNCTION_DIR} COPY . ${FUNCTION_DIR} WORKDIR ${FUNCTION_DIR} # Install Node.js dependencies RUN npm install # Install the runtime interface client RUN npm install aws-lambda-ric # Grab a fresh slim copy of the image to reduce the final size FROM node:20-buster-slim # Required for Node runtimes which use npm@8.6.0+ because # by default npm writes logs under /home/.npm and Lambda fs is read-only ENV NPM_CONFIG_CACHE=/tmp/.npm # Include global arg in this stage of the build ARG FUNCTION_DIR # Set working directory to function root directory WORKDIR ${FUNCTION_DIR} # Copy in the built dependencies COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR} # Set runtime interface client as default command for the container runtime ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"] # Pass the name of the function handler as an argument to the runtime CMD ["index.handler"]
  5. Docker イメージを「Docker の構築」コマンドで構築します。次の例では、イメージを docker-image と名付けて test タグを付けます。

    docker build --platform linux/amd64 -t docker-image:test .
    注記

    このコマンドは、ビルドマシンのアーキテクチャに関係なく、コンテナが Lambda の実行環境と互換性があることを確認する --platform linux/amd64 オプションを特定します。ARM64 命令セットアーキテクチャを使用して Lambda 関数を作成する場合は、代わりに --platform linux/arm64 オプションを使用するようにコマンドを変更してください。

ランタイムインターフェイスエミュレーターを使用して、イメージをローカルでテストします。エミュレーターはイメージに組み込むことも、次の手順を使用してローカルマシンにインストールすることもできます。

ローカルマシンにランタイムインターフェイスエミュレーターをインストールして実行するには
  1. プロジェクトディレクトリから次のコマンドを実行して、GitHub からランタイムインターフェイスエミュレーター (x86-64 アーキテクチャ) をダウンロードし、ローカルマシンにインストールします。

    Linux/macOS
    mkdir -p ~/.aws-lambda-rie && \ curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \ chmod +x ~/.aws-lambda-rie/aws-lambda-rie

    arm64 エミュレータをインストールするには、前のコマンドの GitHub リポジトリ URL を次のように置き換えます。

    https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
    PowerShell
    $dirPath = "$HOME\.aws-lambda-rie" if (-not (Test-Path $dirPath)) { New-Item -Path $dirPath -ItemType Directory } $downloadLink = "https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie" $destinationPath = "$HOME\.aws-lambda-rie\aws-lambda-rie" Invoke-WebRequest -Uri $downloadLink -OutFile $destinationPath

    arm64 エミュレーターをインストールするには、$downloadLink を次のように置き換えます。

    https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
  2. docker run コマンドを使用して、Docker イメージを起動します。次の点に注意してください。

    • docker-image はイメージ名、test はタグです。

    • /usr/local/bin/npx aws-lambda-ric index.handler は ENTRYPOINT で、その後に Dockerfile の CMD が続きます。

    Linux/macOS
    docker run --platform linux/amd64 -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \ --entrypoint /aws-lambda/aws-lambda-rie \ docker-image:test \ /usr/local/bin/npx aws-lambda-ric index.handler
    PowerShell
    docker run --platform linux/amd64 -d -v "$HOME\.aws-lambda-rie:/aws-lambda" -p 9000:8080 ` --entrypoint /aws-lambda/aws-lambda-rie ` docker-image:test ` /usr/local/bin/npx aws-lambda-ric index.handler

    このコマンドはイメージをコンテナとして実行し、localhost:9000/2015-03-31/functions/function/invocations でローカルエンドポイントを作成します。

    注記

    ARM64 命令セットアーキテクチャ用に Docker イメージをビルドした場合は、--platform linux/amd64 の代わりに --platform linux/arm64 オプションを使用してください。

  3. イベントをローカルエンドポイントにポストします。

    Linux/macOS

    Linux および macOS では、次の curl コマンドを実行します。

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

    このコマンドは、空のイベントで関数を呼び出し、応答を返します。サンプル関数コードではなく独自の関数コードを使用している場合は、JSON ペイロードを使用して関数を呼び出すことをお勧めします。例:

    curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
    PowerShell

    PowerShell で次の Invoke-WebRequest コマンドを実行します。

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"

    このコマンドは、空のイベントで関数を呼び出し、応答を返します。サンプル関数コードではなく独自の関数コードを使用している場合は、JSON ペイロードを使用して関数を呼び出すことをお勧めします。例:

    Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
  4. コンテナ ID を取得します。

    docker ps
  5. docker kill」コマンドを使用してコンテナを停止します。このコマンドでは、3766c4ab331c を前のステップのコンテナ ID で置き換えます。

    docker kill 3766c4ab331c
Amazon ECR にイメージをアップロードして Lambda 関数を作成するには
  1. get-login-password」コマンドを実行して Amazon ECR レジストリに Docker CLI を認証します。

    • --region 値を Amazon ECR リポジトリを作成する AWS リージョン に設定します。

    • 111122223333 を AWS アカウント ID に置き換えます。

    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.us-east-1.amazonaws.com
  2. create-repository」コマンドを使用して Amazon ECR にリポジトリを作成します。

    aws ecr create-repository --repository-name hello-world --region us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
    注記

    Amazon ECR リポジトリは Lambda 関数と同じ AWS リージョン に配置されている必要があります。

    成功すると、次のようなレスポンスが表示されます。

    { "repository": { "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world", "registryId": "111122223333", "repositoryName": "hello-world", "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world", "createdAt": "2023-03-09T10:39:01+00:00", "imageTagMutability": "MUTABLE", "imageScanningConfiguration": { "scanOnPush": true }, "encryptionConfiguration": { "encryptionType": "AES256" } } }
  3. 前のステップの出力から repositoryUri をコピーします。

  4. docker tag」コマンドを実行して、最新バージョンとしてローカルイメージを Amazon ECR リポジトリにタグ付けします。このコマンドで:

    • docker-image:test をお使いの Docker イメージの名前およびタグで置き換えます。

    • <ECRrepositoryUri> を、コピーした repositoryUri に置き換えます。URI の末尾には必ず :latest を含めてください。

    docker tag docker-image:test <ECRrepositoryUri>:latest

    例:

    docker tag docker-image:test 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  5. docker push」コマンドを実行して Amazon ECR リポジトリにローカルイメージをデプロイします リポジトリ URI の末尾には必ず :latest を含めてください。

    docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest
  6. まだ作成済みでない場合、関数に「実行ロールの作成」を実行してください。次のステップではロールの Amazon リソースネーム (ARN) が必要です。

  7. Lambda 関数を作成します。ImageUri には、先ほど使用したリポジトリ URI を指定します。URI の末尾には必ず :latest を含めてください。

    aws lambda create-function \ --function-name hello-world \ --package-type Image \ --code ImageUri=111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --role arn:aws:iam::111122223333:role/lambda-ex
    注記

    イメージが Lambda 関数と同じリージョンに配置されていれば、別の AWS アカウントのイメージを使用して関数を作成することができます。詳細については、「 Amazon ECR クロスアカウント許可」を参照してください。

  8. 関数を呼び出します。

    aws lambda invoke --function-name hello-world response.json

    次のような結果が表示されます。

    { "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  9. 関数の出力を確認するには、response.json ファイルをチェックします。

関数コードを更新するには、イメージを再構築し、新しいイメージを Amazon ECR リポジトリにアップロードしてから、update-function-code コマンドを使用してイメージを Lambda 関数にデプロイする必要があります。

Lambda は、イメージタグを特定のイメージダイジェストに解決します。これは、関数のデプロイに使用されたイメージタグを Amazon ECR 内の新しいイメージを指すように変更しても、Lambda は新しいイメージを使用するように自動的に関数を更新しないことを意味します。新しいイメージを同じ Lambda 関数にデプロイするには、Amazon ECR のイメージタグが同じままであっても、update-function-code コマンドを使用する必要があります。