この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS SAMを使ってLambdaとLambda Layerの管理をしています。LambdaではAutoPublishAlias
でaliasを付与しています。
このとき、Lambda Layerのコードだけを修正してデプロイしても、Lambdaが参照するLayerのバージョンは変更になりませんでした。
本記事では、状況を確認したあと、AutoPublishAlias
を未使用に変更し、Lambda Layerのコードのみを変更するとLambdaが参照するLayerのバージョンも追従することを確認します。
なお、AutoPublishAlias
が未使用の場合は、$LATEST
を参照するため大丈夫でした。
GitHubにIssuesがある
AWS SAMのGitHubには下記のIssuesがあります。どうやら不具合みたいです。
- Feature Request : When 'AWS::Serverless::LayerVersion' is updated then to publish a new version of the Lambda function · Issue #1777 · aws/serverless-application-model
- Change in Ref'd Parameter Values do not trigger Function Alias update via AutoPublishAlias · Issue #1640 · aws/serverless-application-model
最初にまとめ
本記の執筆時点において、「Lambda Layerだけを更新したとき、Lambdaが参照するLayerのバージョンを追従したい」ならば、下記いずれかとなりそうです。
AutoPublishAlias
を止めるAutoPublishAlias
を使い、関連するLambdaも何らかの修正を行う(Lambda自体もデプロイの対象とする)AutoPublishCodeSha256
を使って、「Lambdaa Layerのコード+Lambdaのコード」をzip化したハッシュ値をParametersでLambda毎に渡す- これをするぐらいなら、Lambda Layerの利用を止めて、デプロイパッケージにまとめたほうがシンプルだと思います
おすすめの方
AutoPublishAlias
とLambda LayerとLambdaのデプロイについて知りたい方
環境
項目 | バージョン |
---|---|
AWS SAM CLI | version 1.21.1 |
まずは再現確認をする
動作確認用のLambdaをデプロイする
sam init
sam init \
--runtime python3.8 \
--name lambda-layer-deploy-test \
--app-template hello-world \
--package-type Zip
SAMテンプレート
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: lambda-layer-deploy-test
Resources:
MessageLayer:
Type: AWS::Serverless::LayerVersion
Metadata:
BuildMethod: python3.8
Properties:
LayerName: my-layer
ContentUri: src/layer
CompatibleRuntimes:
- python3.8
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: lambda-layer-deploy-test-function
CodeUri: src/hello_world/
Handler: app.lambda_handler
Runtime: python3.8
AutoPublishAlias: dev
Layers:
- !Ref MessageLayer
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のコード
Lambda LayerのAPIを叩いて、メッセージをReturnしています。
app.py
import json
import my_layer
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': json.dumps({
'message': my_layer.hello(),
}),
}
Lambda Layerのコード
メッセージを返しています。
my_layer.py
def hello():
return 'hello'
デプロイ
sam build --use-container
sam deploy \
--stack-name Lambda-Layer-Deploy-Test-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIのエンドポイントを取得します。
$ aws cloudformation describe-stacks \
--stack-name Lambda-Layer-Deploy-Test-Stack \
--query 'Stacks[].Outputs'
[
[
{
"OutputKey": "HelloWorldApi",
"OutputValue": "https://jbp01lz74i.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/"
}
]
]
APIを叩くと、期待通りのResponseが得られます。
$ url https://jbp01lz74i.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello"}
API GatewayとLambdaの関係を確認する
作成したAPIのリソース情報を取得します。jbp01lz74i
部分は、API GatewayのIDです(URLの先頭部分)。そして、レスポンスのGET /hello
のリソースID(hm0sge
)をメモしておきます。
$ aws apigateway get-resources \
--rest-api-id jbp01lz74i \
--query items
[
{
"id": "gaaohbff76",
"path": "/"
},
{
"id": "hm0sge",
"parentId": "gaaohbff76",
"pathPart": "hello",
"path": "/hello",
"resourceMethods": {
"GET": {}
}
}
]
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。alias:dev
付きでlambda-layer-deploy-test-function:dev
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id jbp01lz74i \
--resource-id hm0sge \
--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-layer-deploy-test-function:dev/invocations"
]
Lambdaのエイリアスとバージョンを確認する
lambda-layer-deploy-test-function
には、$LATEST
と1
の2つのバージョンがあります。それぞれmy-layer:1
を参照しています。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-layer-deploy-test-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、my-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1",
}
]
]
Lambda Layerは、version:1
だけ存在しています。
$ aws lambda list-layer-versions \
--layer-name my-layer \
--query LayerVersions[*].[Version]
[
[
1
]
]
絵で整理すると下記です。
Lambda Layerのコードだけ変更する
Lambda Layerのコード
hello!
からhello world!!
に変更しました。
my_layer.py
def hello():
return 'hello world!!'
デプロイ
sam build --use-container
sam deploy \
--stack-name Lambda-Layer-Deploy-Test-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIを叩くと、変更前のLambda Layerの内容が取得できました。Lambda Layerを変更しても反映されませんでした。
$ url https://jbp01lz74i.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello"}
API GatewayとLambdaの関係を確認する
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。alias:dev
付きでlambda-layer-deploy-test-function:dev
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id jbp01lz74i \
--resource-id hm0sge \
--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-layer-deploy-test-function:dev/invocations"
]
Lambdaのエイリアスとバージョンを確認する
layer-deploy-test-function
には、$LATEST
と1
の2つのバージョンがあります。$LATEST
は、my-layer:2
の参照に変わりました。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-layer-deploy-test-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:2"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1"
]
]
]
alias:dev
は、Lambda Version:1
であり、my-layer:1
を参照しています。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function:dev \
--query Configuration.[Version,Layers]
[
"1",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1",
}
]
]
Lambda Layerは、version:1
とversion:2
が存在しています。
$ aws lambda list-layer-versions \
--layer-name my-layer \
--query LayerVersions[*].[Version]
[
[
2
],
[
1
]
]
絵で整理すると下記です。$LATEST
が参照しているLayerバージョンのみが更新されています。
Lambda Layerのみを変更してもデプロイしたい
まずは AutoPublishAlias をやめる
SAMテンプレート
AutoPublishAlias
をコメントアウトしています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: lambda-layer-deploy-test
Resources:
MessageLayer:
Type: AWS::Serverless::LayerVersion
Metadata:
BuildMethod: python3.8
Properties:
LayerName: my-layer
ContentUri: src/layer
CompatibleRuntimes:
- python3.8
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: lambda-layer-deploy-test-function
CodeUri: src/hello_world/
Handler: app.lambda_handler
Runtime: python3.8
# AutoPublishAlias: dev
Layers:
- !Ref MessageLayer
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/"
デプロイ
sam build --use-container
sam deploy \
--stack-name Lambda-Layer-Deploy-Test-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIを叩くと、最新のLambda Layerの内容が取得できました。
$ url https://jbp01lz74i.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello world!!"}
API GatewayとLambdaの関係を確認する
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。Aliasは無く、lambda-layer-deploy-test-function
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id jbp01lz74i \
--resource-id hm0sge \
--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-layer-deploy-test-function/invocations"
]
Lambdaのエイリアスとバージョンを確認する
layer-deploy-test-function
には、$LATEST
と1
の2つのバージョンがあります。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-layer-deploy-test-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:2"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1"
]
]
]
alias:dev
は無くなったので、ResourceNotFoundException
が発生しました。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function:dev \
--query Configuration.[Version,Layers]
An error occurred (ResourceNotFoundException) when calling the GetFunction operation: Function not found: arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-layer-deploy-test-function:dev
Lambda関数名からalias:dev
を無くすと、$LATEST
であることが分かります。$LATEST
は、my-layer:2
を参照しています。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function \
--query Configuration.[Version,Layers]
[
"$LATEST",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:2",
}
]
]
Lambda Layerは、version:1
とversion:2
が存在しています。
$ aws lambda list-layer-versions \
--layer-name my-layer \
--query LayerVersions[*].[Version]
[
[
2
],
[
1
]
]
絵で整理すると下記です。
Lambda Layerのコードだけ変更する
Lambda Layerのコード
hello world!!
からhello??
に変更しました。
my_layer.py
def hello():
return 'hello??'
デプロイ
sam build --use-container
sam deploy \
--stack-name Lambda-Layer-Deploy-Test-Stack \
--s3-bucket cm-fujii.genki-deploy \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
APIを叩くと、変更後のLambda Layerの内容が取得できました!
$ url https://jbp01lz74i.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello??"}
API GatewayとLambdaの関係を確認する
API GatewayのMethod情報を取得し、どのLambdaが呼ばれているのかを確認します。Aliasは無く、lambda-layer-deploy-test-function
が呼ばれています。
$ aws apigateway get-method \
--rest-api-id jbp01lz74i \
--resource-id hm0sge \
--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-layer-deploy-test-function/invocations"
]
Lambdaのエイリアスとバージョンを確認する
layer-deploy-test-function
には、$LATEST
と1
の2つのバージョンがあります。$LATEST
は、my-layer:3
の参照に変わりました。
$ aws lambda list-functions \
--function-version ALL \
--query Functions[?FunctionName==\'lambda-layer-deploy-test-function\'].[Version,Layers[*].Arn]
[
[
"$LATEST",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:3"
]
],
[
"1",
[
"arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1"
]
]
]
alias:dev
は無いので、ResourceNotFoundException
が発生します。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function:dev \
--query Configuration.[Version,Layers]
An error occurred (ResourceNotFoundException) when calling the GetFunction operation: Function not found: arn:aws:lambda:ap-northeast-1:123456789012:function:lambda-layer-deploy-test-function:dev
Lambda関数名からalias:dev
を無くすと、$LATEST
であることが分かります。$LATEST
は、my-layer:3
を参照しています。
$ aws lambda get-function \
--function-name lambda-layer-deploy-test-function \
--query Configuration.[Version,Layers]
[
"$LATEST",
[
{
"Arn": "arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:3",
}
]
]
Lambda Layerは、version:1
とversion:2
とversion:3
が存在しています。
$ aws lambda list-layer-versions \
--layer-name my-layer \
--query LayerVersions[*].[Version]
[
[
3
],
[
2
],
[
1
]
]
絵で整理すると下記です。$LATEST
が参照しているLayerバージョンが更新されました。
さいごに
かなりハマりました。AutoPublishAlias
とLambda Layerの組み合わせにご注意ください。
参考
- sam build - AWS Serverless Application Model
- レイヤーのビルド - AWS Serverless Application Model
- serverless-application-model/safe_lambda_deployments.rst at master · aws/serverless-application-model
- Feature Request : When 'AWS::Serverless::LayerVersion' is updated then to publish a new version of the Lambda function · Issue #1777 · aws/serverless-application-model
- Change in Ref'd Parameter Values do not trigger Function Alias update via AutoPublishAlias · Issue #1640 · aws/serverless-application-model