この記事は セゾン情報システムズ Advent Calendar 2020 4日目の記事です。
はじめに
AWS re:Invent 2020 で AWS Lambda の Container イメージサポートが発表されました。
AWS Lambda now supports container images as a packaging format
https://aws.amazon.com/about-aws/whats-new/2020/12/aws-lambda-now-supports-container-images-as-a-packaging-format/
ついに AWS にも Cloud Run のようなものがきたか!と思ったそこのあなた
残念ながらあらゆるコンテナイメージを簡単に Lambda で動かすことができるという機能ではありません。
Lambda 関数をコンテナイメージとしてパッケージ化してデプロイできる機能であるため、
作成するコンテナイメージは Lambda Runtime APIを実装し、Lambda関数と互換性を持たせる必要があります。
AWS SAM CLI も v1.13.1 で コンテナイメージをサポートしています。
Release 1.13.1 - Support for Lambda Container Images
https://github.com/aws/aws-sam-cli/releases/tag/v1.13.1
やってみる
前述のとおり、AWS SAM CLI は v1.13.1 以上である必要があります。
$ sam --version
SAM CLI, version 1.13.1
プロジェクト作成
sam init
で利用できるプロジェクトテンプレートでパッケージタイプ Image
が
選択できるようになっています。
ここでは nodejs12.x のベースイメージを使用してサンプルプロジェクトを作成します。
$ sam init
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2
Which base image would you like to use?
1 - amazon/nodejs12.x-base
2 - amazon/nodejs10.x-base
3 - amazon/python3.8-base
4 - amazon/python3.7-base
5 - amazon/python3.6-base
6 - amazon/python2.7-base
7 - amazon/ruby2.7-base
8 - amazon/ruby2.5-base
9 - amazon/go1.x-base
10 - amazon/java11-base
11 - amazon/java8.al2-base
12 - amazon/java8-base
13 - amazon/dotnetcore3.1-base
14 - amazon/dotnetcore2.1-base
Base image: 1
Project name [sam-app]:
Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates
-----------------------
Generating application:
-----------------------
Name: sam-app
Base Image: amazon/nodejs12.x-base
Dependency Manager: npm
Output Directory: .
Next steps can be found in the README file at ./sam-app/README.md
作成されるファイルは以下のとおりです。
Dockerfile が作成されていることがわかります。
$ cd sam-app
$ tree
.
├── events
│ └── event.json
├── hello-world
│ ├── app.js
│ ├── Dockerfile
│ ├── package.json
│ └── tests
│ └── unit
│ └── test-handler.js
├── README.md
└── template.yaml
Dockerfile では AWS が提供しているベースイメージが指定されています。
AWS 提供のベースイメージであれば Lambda 関数を実行するために必要なランタイムと
その他のコンポーネントがプリロードされているため、Lambda 関数のコードとその依存関係を
追加するだけで問題ありません。
FROM public.ecr.aws/lambda/nodejs:12
COPY app.js package.json ./
RUN npm install
# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambdaHandler"]
独自コンテナイメージを Lambda 互換にするには Lambda Runtime APIを実装する一連の
ソフトウェアパッケージである Runtime Interface Clients (RIC) を
ベースイメージに追加する必要があります。
template.yaml
の内容は以下のとおりです。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
# ImageConfig:
# Uncomment this to override command here from the Dockerfile
# Command: ["app.lambdaHandler"]
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
Metadata:
DockerTag: nodejs12.x-v1
DockerContext: ./hello-world
Dockerfile: Dockerfile
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for Hello World function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
コンテナイメージでパッケージ化を行うには、PackageType: Image
を指定する必要があります。
指定は省略可能で、指定可能な値は Zip
or Image
です。
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-packagetype
Properties:
PackageType: Image
SAM CLI でコンテナイメージをビルドするには Metadata リソース属性で、
Dockerfile, Context, Tag などの情報を宣言します。
DockerBuildArgs エントリでビルド時の引数を指定することも可能です。
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-build.html#build-container-image
Metadata:
DockerTag: nodejs12.x-v1
DockerContext: ./hello-world
Dockerfile: Dockerfile
イメージのビルド
sam build コマンドでコンテナイメージをビルドします。
$ sam build
Building codeuri: . runtime: None metadata: {'DockerTag': 'nodejs12.x-v1', 'DockerContext': './hello-world', 'Dockerfile': 'Dockerfile'} functions: ['HelloWorldFunction']
Building image for HelloWorldFunction function
Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/4 : FROM public.ecr.aws/lambda/nodejs:12
---> ccbddaf00c51
Step 2/4 : COPY app.js package.json ./
---> fb16c5342f63
Step 3/4 : RUN npm install
---> Running in faa9eb4d503c
npm WARN deprecated debug@3.2.6: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)
npm WARN deprecated mkdirp@0.5.4: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
npm notice created a lockfile as package-lock.json. You should commit this file.
added 107 packages from 544 contributors and audited 107 packages in 5.755s
16 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
---> 8db6f5505058
Step 4/4 : CMD ["app.lambdaHandler"]
---> Running in 08e14cc877aa
---> 271c7f34a0c7
Successfully built 271c7f34a0c7
Successfully tagged helloworldfunction:nodejs12.x-v1
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
パッケージ化されたコンテナイメージが作成されました
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
helloworldfunction nodejs12.x-v1 271c7f34a0c7 3 minutes ago 471MB
ローカルテスト
コンテナイメージとしてパッケージ化された Lambda関数をローカルでテストするために
軽量のウェブサーバーである Lambda Runtime Interface Emulator(RIE)を使用することができます。
AWS 提供のベースイメージには RIE が組み込まれているため、ビルドしたイメージから
コンテナを作成するだけですぐにテストを実行できます。
$ docker run -d -p 9000:8080 helloworldfunction:nodejs12.x-v1
a510b1f8bf0fd5c0d7c6a3716ddaf96462452abcdff26285d1e8471c6e829cc8
$ curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
{"statusCode":200,"body":"{\"message\":\"hello world\"}"}
RIE は HTTP リクエストを JSON イベントに変換し、プロキシする役割であるため、
X-Ray や その他の Lambda 統合機能についてはサポートしていません。
独自のベースイメージを使用する場合、RIE をイメージに組み込んだり、
bind マウントした RIE を Entrypoint としてコンテナを起動することでテストを実行できます。
https://docs.aws.amazon.com/lambda/latest/dg/images-test.html#images-test-alternative
もちろん今回は SAM CLI を使用しているので、sam local invoke
によるテストも実行可能です。
$ sam local invoke
Invoking Container created from helloworldfunction:nodejs12.x-v1
Image was not found.
Building image.................
Skip pulling image and use local one: helloworldfunction:rapid-1.13.1.
START RequestId: 05284faf-5a20-46fc-a695-111eb3d0f085 Version: $LATEST
END RequestId: 05284faf-5a20-46fc-a695-111eb3d0f085
REPORT RequestId: 05284faf-5a20-46fc-a695-111eb3d0f085 Init Duration: 1.86 ms Duration: 96.09 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 128 MB
デプロイ
コンテナイメージを push するための リポジトリはあらかじめ作成しておく必要がありますが
イメージの push 自体は SAM CLI に任せることができます!
$ aws ecr create-repository --repository-name lambda-container-test
{
"repository": {
"repositoryUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-test",
"imageScanningConfiguration": {
"scanOnPush": false
},
"registryId": "123456789012",
"imageTagMutability": "MUTABLE",
"repositoryArn": "arn:aws:ecr:ap-northeast-1:123456789012:repository/lambda-container-test",
"repositoryName": "lambda-container-test",
"createdAt": 1606926983.0
}
}
sam deploy --guided
を実行します。Image Repository
に先ほど作成したリポジトリを指定することで
デプロイ時にイメージの push が自動で行われます。
$ sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Not found
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]:
AWS Region [us-east-1]: ap-northeast-1
Image Repository []: 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-test
Images that will be pushed:
helloworldfunction:nodejs12.x-v1 to 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-test:helloworldfunction-271c7f34a0c7-nodejs12.x-v1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: n
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment: Found!
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxxx
A different default S3 bucket can be set in samconfig.toml
Saved arguments to config file
Running 'sam deploy' for future deployments will use the parameters saved above.
The above parameters can be changed by modifying samconfig.toml
Learn more about samconfig.toml syntax at
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html
The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-test]
6d7acece320f: Pushed
105893862807: Pushed
3642f26c4fcb: Pushed
1807102b87b6: Pushed
120614c3628c: Pushed
0d8c48ae73f7: Pushed
e4f26f8be15f: Pushed
af6d16f2417e: Pushed
helloworldfunction-271c7f34a0c7-nodejs12.x-v1: digest: sha256:7a83998f07e54249948db91846abd9dbfecbe175181fe0876b5980a635b9e70f size: 1998
Deploying with following values
===============================
Stack name : sam-app
Region : ap-northeast-1
Confirm changeset : False
Deployment image repository : 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-container-test
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxxxxx
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
~~以降省略~~
作成された API Gateway にリクエストして、動作を確認します。
$ curl https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"hello world"}
成功しました。
Lambda のコンソール側でも関数コードがコンテナイメージとしてデプロイされていることを確認できます。
注意点など
-
CloudFormation のスタックを削除しても、ECR 側のイメージは削除されません。
-
コールドスタード時の実行時間
厳密な比較が行えていないので一概には言えないと思いますが、 zip のデプロイパッケージと比較すると
若干 Init Duration (初期化) に時間を要しているように伺えました。
- 課金期間
初期化時間も課金期間に含まれます。
カスタムランタイムと同じ扱いのようです。
Building a custom runtime
https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-build
Initialization counts towards billed execution time and timeout.
参考
New for AWS Lambda – Container Image Support
https://aws.amazon.com/jp/blogs/aws/new-for-aws-lambda-container-image-support/
AWS Lambda - Developer Guide
https://docs.aws.amazon.com/lambda/latest/dg/lambda-images.html
AWS Serverless Application Model - Developer Guide
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-build.html
以上です。
参考になれば幸いです。