この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
先日の下記アップデートを活用すれば、Lambda LayersとLambdaのデプロイをスッキリできそうだったので、実際に試してみました。
以前、AWS SAMでAutoPublishAlias
を使った際の動作を試してみたので、本記事でもAutoPublishAlias
を使った際の動作を確認します。
おすすめの方
- AWS SAMでDynamic referencesを使いたい方
- AutoPublishAliasとLambda LayerとLambdaのデプロイについて知りたい方
最初に結論
- Lambda Layersのみを更新すると、Lambda Layersは更新された
- しかし、Lambdaの新バージョン発行とエイリアス更新はされなかった
環境
項目 | バージョン |
---|---|
AWS SAM CLI | 1.21.1 |
3つのCloudFormationスタックを作成する
3つのCloudFormationスタックを作成します。
- Lambda Layersのみ
- API Gateway + Lambda (その1)
- API Gateway + Lambda (その2)
各Lambdaは、同じLambda Layersを参照します。
Lambda LayersとLambdaをデプロイする
sam init
3つのプロジェクトを作成します。
- sam-lambda-layers
- sam-lambda-1
- sam-lambda-2
sam init \
--runtime python3.8 \
--name sam-lambda-layers \
--app-template hello-world \
--package-type Zip
sam init \
--runtime python3.8 \
--name sam-lambda-1 \
--app-template hello-world \
--package-type Zip
sam init \
--runtime python3.8 \
--name sam-lambda-2 \
--app-template hello-world \
--package-type Zip
SAMテンプレート
Lambda Layers
Lambda LayersとSSMパラメータを作成しています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam-lambda-layers
Resources:
TestDeployLayer:
Type: AWS::Serverless::LayerVersion
Metadata:
BuildMethod: python3.8
Properties:
LayerName: test-deploy-layer
ContentUri: layer
CompatibleRuntimes:
- python3.8
TestDeployLayerSsmParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /Fujii/Test/MyLayer
Type: String
Value: !Ref TestDeployLayer
Lambda1 (Stack 1)
Lambdaを作成しています。Lambda Layersは、Dynamic ReferencesでSSMパラメータストアの最新バージョンを参照しています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam-lambda-1
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: lambda-deploy-sample-1-function
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.8
AutoPublishAlias: dev
Timeout: 10
Layers:
- '{{resolve:ssm:/Fujii/Test/MyLayer}}'
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
HelloWorldFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Outputs:
HelloWorldApi:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
Lambda2 (Stack 2)
Lambda関数名以外は、Stack1と同じです。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sam-lambda-2
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: lambda-deploy-sample-2-function
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.8
AutoPublishAlias: dev
Timeout: 10
Layers:
- '{{resolve:ssm:/Fujii/Test/MyLayer}}'
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
HelloWorldFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Outputs:
HelloWorldApi:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
ソースコード
Lambda Layers
my_layer.py
def hello():
return 'hello'
Lambda1 (Stack 1)
Lambda Layersのコードを呼んでいます。どちらのLambdaが実行されたのかが分かるように番号も明記しています。
app.py
import json
import my_layer
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"lambda": "1",
"message": my_layer.hello(),
}),
}
Lambda2 (Stack 2)
Lambda Layerのコードを呼んでいます。
app.py
import json
import my_layer
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"lambda": "2",
"message": my_layer.hello(),
}),
}
デプロイ
注意点
AWS SAM CLIは、本記事の作成時点において、Dynamic Referencesに対応していません。
- Unable to resolve SSM parameters in AWS::Serverless::Function Layers · Issue #2743 · aws/aws-sam-cli
そのため、Lambdaコード側でsam build
コマンドを実行すると、下記のエラーで失敗します。
$ sam build
Error: {{resolve:ssm:/Fujii/Test/MyLayer}} is an Invalid Layer Arn.
もし、外部ライブラリ等を使う場合は、Lambda Layersに含めると良いですね。
Lambda Layers
Lambda Layersでは、Dynamic Referencesを使っていないため、sam
コマンドが利用できます。
cd sam-lambda-layers
sam build --use-container
sam deploy \
--stack-name SAM-Lambda-Layers-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
Lambda1 (Stack 1)
Lambdaでは、Dynamic Referencesを使っているため、sam
コマンドではなくaws
コマンドを利用しています。
cd sam-lambda-1
aws cloudformation package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
aws cloudformation deploy \
--template-file packaged.yaml \
--stack-name SAM-Lambda-1-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
Lambda2 (Stack 2)
cd sam-lambda-2
aws cloudformation package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
aws cloudformation deploy \
--template-file packaged.yaml \
--stack-name SAM-Lambda-2-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIエンドポイントを取得する
$ aws cloudformation describe-stacks \
--stack-name SAM-Lambda-1-Stack \
--query 'Stacks[].Outputs'
[
[
{
"OutputKey": "HelloWorldApi",
"OutputValue": "https://rx536ihwd7.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/"
}
]
]
$ aws cloudformation describe-stacks \
--stack-name SAM-Lambda-2-Stack \
--query 'Stacks[].Outputs'
[
[
{
"OutputKey": "HelloWorldApi",
"OutputValue": "https://66yrzneyti.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/"
}
]
]
APIから情報取得する
バッチリですね。
$ curl https://rx536ihwd7.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"lambda": "1", "message": "hello"}
$ curl https://66yrzneyti.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"lambda": "2", "message": "hello"}
SSMパラメータストアの内容を確認する
test-deploy-layer:1
が格納されています。
$ aws ssm get-parameters \
--names /Fujii/Test/MyLayer \
--query Parameters[*].[Name,Type,Value,Version]
[
[
"/Fujii/Test/MyLayer",
"String",
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1",
1
]
]
API GatewayとLambdaの関係を確認する
Lambda1 (Stack 1)
作成したAPIのリソース情報を取得します。rx536ihwd7
部分は、API GatewayのIDです(URLの先頭部分)。そして、レスポンスのGET /helloのリソースID(rm8kns
)をメモしておきます。
$ aws apigateway get-resources \
--rest-api-id rx536ihwd7 \
--query items
[
{
"id": "rm8kns",
"parentId": "wtvajqmwx9",
"pathPart": "hello",
"path": "/hello",
"resourceMethods": {
"GET": {}
}
},
{
"id": "wtvajqmwx9",
"path": "/"
}
]
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。alias:dev
付きでlambda-deploy-sample-1-function:dev
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id rx536ihwd7 \
--resource-id rm8kns \
--http-method GET \
--query methodIntegration.[uri]
[
"arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-deploy-sample-1-function:dev/invocations"
]
Lambda2 (Stack 2)
もうひとつのAPIも確認します。
$ aws apigateway get-resources \
--rest-api-id 66yrzneyti \
--query items
[
{
"id": "gq0bdw",
"parentId": "quwnfgtni0",
"pathPart": "hello",
"path": "/hello",
"resourceMethods": {
"GET": {}
}
},
{
"id": "quwnfgtni0",
"path": "/"
}
]
alias:dev
付きでlambda-deploy-sample-2-function:dev
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id 66yrzneyti \
--resource-id gq0bdw \
--http-method GET \
--query methodIntegration.[uri]
[
"arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-deploy-sample-2-function:dev/invocations"
]
Lambdaのエイリアスとバージョンを確認する
Lambda1 (Stack 1)
$LATEST
と1
の2つのバージョンがあります。それぞれtest-deploy-layer:1
を参照しています。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-deploy-sample-1-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、test-deploy-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-deploy-sample-1-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1",
"CodeSize": 401
}
]
]
Lambda2 (Stack 2)
$LATEST
と1
の2つのバージョンがあります。それぞれtest-deploy-layer:1
を参照しています。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-deploy-sample-2-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、test-deploy-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-deploy-sample-2-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1",
"CodeSize": 401
}
]
]
Lambda Layersを確認する
Lambda Layersは、version:1
だけ存在しています。
$ aws lambda list-layer-versions \
--layer-name test-deploy-layer \
--query LayerVersions[*].[Version]
[
[
1
]
]
ここまでの関係を絵で整理する
Lambda Layersのコードだけ変更する
Lambda Layersのコード
hello
からhello world!!
に変更しました。
my_layer.py
def hello():
return 'hello world!!'
デプロイ
デプロイコマンドはすべて同じです。
Lambda Layers
cd sam-lambda-layers
sam build --use-container
sam deploy \
--stack-name SAM-Lambda-Layers-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
Lambda1
cd sam-lambda-1
aws cloudformation package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
aws cloudformation deploy \
--template-file packaged.yaml \
--stack-name SAM-Lambda-1-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
Lambda2
cd sam-lambda-2
aws cloudformation package \
--template-file template.yaml \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
aws cloudformation deploy \
--template-file packaged.yaml \
--stack-name SAM-Lambda-2-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIから情報取得する
Lambda Layersのデプロイは、反映されませんでした。
$ curl https://rx536ihwd7.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"lambda": "1", "message": "hello"}
$ curl https://66yrzneyti.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"lambda": "2", "message": "hello"}
SSMパラメータストアの内容を確認する
test-deploy-layer:2
が格納されています。
$ aws ssm get-parameters \
--names /Fujii/Test/MyLayer \
--query Parameters[*].[Name,Type,Value,Version]
[
[
"/Fujii/Test/MyLayer",
"String",
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:2",
2
]
]
API GatewayとLambdaの関係を確認する
Lambda1 (Stack 1)
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。alias:dev
付きでlambda-deploy-sample-1-function:dev
が呼ばれています。こちらは今まで通りですね。
$ aws apigateway get-method \
--rest-api-id rx536ihwd7 \
--resource-id rm8kns \
--http-method GET \
--query methodIntegration.[uri]
[
"arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-deploy-sample-1-function:dev/invocations"
]
Lambda2 (Stack 2)
もうひとつのAPIも同様です。
alias:dev
付きでlambda-deploy-sample-2-function:dev
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id 66yrzneyti \
--resource-id gq0bdw \
--http-method GET \
--query methodIntegration.[uri]
[
"arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-deploy-sample-2-function:dev/invocations"
]
Lambdaのエイリアスとバージョンを確認する
Lambda1 (Stack 1)
$LATEST
と1
の2つのバージョンがあります。$LATEST
はtest-deploy-layer:2
の参照に変わっていますが、1
はtest-deploy-layer:1
から変化していません。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-deploy-sample-1-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:2"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、test-deploy-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-deploy-sample-1-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1",
"CodeSize": 401
}
]
]
Lambda2 (Stack 2)
$LATEST
と1
の2つのバージョンがあります。$LATEST
はtest-deploy-layer:2
の参照に変わっていますが、1
はtest-deploy-layer:1
から変化していません。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-deploy-sample-2-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:2"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、test-deploy-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-deploy-sample-2-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:test-deploy-layer:1",
"CodeSize": 401
}
]
]
Lambda Layersを確認する
Lambda Layersは、version:1
とversion:2
が存在しています。増えました。
$ aws lambda list-layer-versions \
--layer-name test-deploy-layer \
--query LayerVersions[*].[Version]
[
[
2
],
[
1
]
]
ここまでの関係を絵で整理する
さいごに
AWS SAM CLIでDynamic referencesをサポートしていない部分でハマりました。どなたかの参考になれば幸いです。
参考
- 動的な参照を使用してテンプレート値を指定する - AWS CloudFormation
- 【アップデート】スタック間のパラメータ渡しが便利に!!CloudFormationのDynamic referencesでSSMパラメータの最新バージョンが参照可能になりました | DevelopersIO
- Lambda Layerだけを更新したとき、Lambdaが参照するLayerのバージョンが追従しないのでAutoPublishAliasを止めてみた話 | DevelopersIO
- Unable to resolve SSM parameters in AWS::Serverless::Function Layers · Issue #2743 · aws/aws-sam-cli