コンテナイメージを使用して、トランスパイルされた TypeScript コードを Lambda にデプロイする - AWS Lambda

コンテナイメージを使用して、トランスパイルされた TypeScript コードを Lambda にデプロイする

TypeScript コードを Node.js コンテナイメージとして AWS Lambda 関数にデプロイできます。AWS は、コンテナイメージのビルドに役立つ Node.js のベースイメージを提供します。これらのベースイメージには、Lambda でイメージを実行するために必要な言語ランタイムおよびその他のコンポーネントがプリロードされています。AWS は、コンテナイメージの構築に役立つ各ベースイメージの Dockerfile を提供します。

コミュニティベースイメージまたはプライベートエンタープライズベースイメージを使用する場合は、ベースイメージに Node.js ランタイムインターフェイスクライアント (RIC) を追加して、Lambda と互換性を持たせる必要があります。

Lambda は、ローカルでテストするためのランタイムインターフェイスエミュレータを提供します。Node.js の AWS ベースイメージには、ランタイムインターフェイスエミュレータが含まれています。Alpine Linux や Debian イメージなどの代替ベースイメージを使用する場合は、エミュレーターをイメージにビルドすることもできますし、ローカルマシンにインストールすることもできます。

Node.js ベースイメージを使用して TypeScript 関数コードをビルドおよびパッケージ化する

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

AWS ベースイメージから Lambda のイメージを作成するには
  1. ローカルマシンで、新しい関数のプロジェクトディレクトリを作成します。

  2. npm または任意のパッケージマネージャーを使用して、新しい Node.js プロジェクトを作成します。

    npm init
  3. @types/aws-lambda および esbuild のパッケージを開発環境の依存関係として追加します。@types/aws-lambda パッケージには Lambda の型定義が含まれています。

    npm install -D @types/aws-lambda esbuild
  4. ビルドスクリプトpackage.json ファイルに追加します。

    "scripts": { "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js" }
  5. index.ts という名前のファイルを作成します。その新しいファイルに次のサンプルコードを追加します。これは Lambda 関数のコードです。関数は hello world のメッセージを返します。

    注記

    import ステートメントは、@types/aws-lambda から型定義をインポートします。aws-lambda NPM パッケージはインポートされません。これは関連性のないサードパーティーのツールです。詳細については、「DefinitelyTyped GitHub リポジトリ」の「aws-lambda」を参照してください。

    import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda'; export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => { console.log(`Event: ${JSON.stringify(event, null, 2)}`); console.log(`Context: ${JSON.stringify(context, null, 2)}`); return { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }; };
  6. 次の設定で新しい Dockerfile を作成します。

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

    • CMD 引数を設定して、Lambda 関数ハンドラを指定します。

    次の Dockerfile の例では、「マルチステージビルド」が使用されます。最初のステップでは、TypeScript コードを JavaScript にトランスパイルします。2 番目のステップでは、JavaScript ファイルと本番環境の依存関係のみを含むコンテナイメージを生成します。

    この例の Dockerfile には USER 命令が含まれていないことに注意してください。コンテナイメージを Lambda にデプロイすると、最小特権のアクセス許可を付与したデフォルトの Linux ユーザーを Lambda が自動的に定義します。これは標準の Docker 動作とは異なります。標準の動作とは、USER 命令を指定しなかったときに root ユーザーのデフォルトとなる動作のことです。

    例 Dockerfile
    FROM public.ecr.aws/lambda/nodejs:22 as builder WORKDIR /usr/app COPY package.json index.ts ./ RUN npm install RUN npm run build FROM public.ecr.aws/lambda/nodejs:22 WORKDIR ${LAMBDA_TASK_ROOT} COPY --from=builder /usr/app/dist/* ./ CMD ["index.handler"]
  7. 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 イメージの名前とタグです。これは、docker build コマンドに指定したイメージの名前とタグです。

    • <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 コマンドを使用する必要があります。次の例では、--publish オプションが最新のコンテナイメージを使用して関数の新しいバージョンを作成しています。

aws lambda update-function-code \ --function-name hello-world \ --image-uri 111122223333.dkr.ecr.us-east-1.amazonaws.com/hello-world:latest \ --publish