AWS Lambda-backed カスタムリソースを利用するとAWS CloudFormationが対応していないリソースを管理することができて便利なのですが、AWS Lambdaで利用できるAWS SDK(ここではPythonのboto3)のバージョンが最新じゃない場合に困ることがあります。
AWS Lambda-backed カスタムリソース – AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html
そんなときにどうしたら良いものか悩んでいたのですが、AWS Lambda Layersが利用できるみたいだったので試してみました。
前提
- AWSアカウントがある
- AWS CLIが利用できる
- AWS Lambda、Lambda Layers、CloudFormationの作成権限がある
AWS Lambda Layersに最新のAWS SDKのLayerを作成する
AWS Lambda Layersで最新のAWS SDKを利用する方法は下記を参考にさせてもらいました。(感謝
Lambda Layers で最新の AWS SDK を使用する – Qiita
https://qiita.com/hayao_k/items/b9750cc8fa69d0ce91b0
> mkdir 任意のディレクトリ > cd 任意のディレクトリ > mkdir python > pip install -t ./python boto3 > zip -r python.zip ./python > aws lambda publish-layer-version \ --layer-name boto3 \ --zip-file fileb://python.zip \ --compatible-runtimes python3.7 { "Content": { "Location": "https://prod-04-2014-layers.s3.amazonaws.com/snapshots/(略)", "CodeSha256": "JZM5sEEyGBPgips+y+F0/X5rHXJIPkcLYeazyXiLkTk=", "CodeSize": 8572137 }, "LayerArn": "arn:aws:lambda:us-east-1:xxxxxxxxxxxx:layer:boto3", "LayerVersionArn": "arn:aws:lambda:us-east-1:xxxxxxxxxxxx:layer:boto3:1", "Description": "", "CreatedDate": "2019-06-21T08:57:29.995+0000", "Version": 1, "CompatibleRuntimes": [ "python3.7" ] }
AWS CloudFormationのテンプレートを作成する
AWS Lambda-backedカスタムリソースでboto3
のバージョンを確認するテンプレートを作成します。
比較のためにLayer利用する/しないのリソースを準備します。
> touch cfn-template.yaml
cfn-template.yaml
Resources: NonUseLambdaLayer: Type: Custom::CustomResource Properties: ServiceToken: !GetAtt NonUseLambdaLayerFunction.Arn UseLambdaLayer: Type: Custom::CustomResource Properties: ServiceToken: !GetAtt UseLambdaLayerFunction.Arn # 標準のboto3を利用 NonUseLambdaLayerFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt FunctionExecutionRole.Arn Code: ZipFile: !Sub | import cfnresponse import boto3 def handler(event, context): print(boto3.__version__) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) Runtime: python3.7 # Lambda Layerのboto3を利用 UseLambdaLayerFunction: Type: AWS::Lambda::Function Properties: Handler: index.handler Role: !GetAtt FunctionExecutionRole.Arn Code: ZipFile: !Sub | import cfnresponse import boto3 def handler(event, context): print(boto3.__version__) cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) Runtime: python3.7 Layers: - arn:aws:lambda:us-east-1:xxxxxxxxxxxx:layer:boto3:1 FunctionExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "arn:aws:logs:*:*:*"
AWS CLIからCloudFormationのスタックを作成します。Lambda関数実行用のロールを作成するので、--capabilities CAPABILITY_IAM
オプションを指定します。
> aws cloudformation create-stack \ --stack-name cfn-lambda-backed-test \ --template-body file://cfn-template.yaml \ --capabilities CAPABILITY_IAM { "StackId": "arn:aws:cloudformation:us-east-1:xxxxxxxxxxxx:stack/cfn-lambda-backed-test/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }
スタック作成できたらリソース一覧からAWS Lambdaの関数名を取得します。
> aws cloudformation list-stack-resources \ --stack-name cfn-lambda-backed-test { "StackResourceSummaries": [ { "LogicalResourceId": "FunctionExecutionRole", "PhysicalResourceId": "cfn-lambda-backed-test-FunctionExecutionRole-XXXXXXXXXXXX", "ResourceType": "AWS::IAM::Role", "LastUpdatedTimestamp": "2019-06-24T07:25:29.253Z", "ResourceStatus": "CREATE_COMPLETE", "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" } }, { "LogicalResourceId": "NonUseLambdaLayer", "PhysicalResourceId": "2019/06/24/[$LATEST]8e94b0b2ffc54b00acf35a004e68c522", "ResourceType": "Custom::CustomResource", "LastUpdatedTimestamp": "2019-06-24T07:25:37.368Z", "ResourceStatus": "CREATE_COMPLETE", "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" } }, { "LogicalResourceId": "NonUseLambdaLayerFunction", "PhysicalResourceId": "cfn-lambda-backed-te-NonUseLambdaLayerFunctio-XXXXXXXXXXXXX", "ResourceType": "AWS::Lambda::Function", "LastUpdatedTimestamp": "2019-06-24T07:25:32.817Z", "ResourceStatus": "CREATE_COMPLETE", "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" } }, { "LogicalResourceId": "UseLambdaLayer", "PhysicalResourceId": "2019/06/24/[$LATEST]200facdec8cb4d77ac3dd5f333ceb848", "ResourceType": "Custom::CustomResource", "LastUpdatedTimestamp": "2019-06-24T07:25:41.716Z", "ResourceStatus": "CREATE_COMPLETE", "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" } }, { "LogicalResourceId": "UseLambdaLayerFunction", "PhysicalResourceId": "cfn-lambda-backed-test-UseLambdaLayerFunction-XXXXXXXXXXXXX", "ResourceType": "AWS::Lambda::Function", "LastUpdatedTimestamp": "2019-06-24T07:25:36.240Z", "ResourceStatus": "CREATE_COMPLETE", "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" } } ] }
リソースが取得できたらLambda関数のログからboto3
のバージョンを確認します。
上記リソースリストにあるResourceType
がAWS::Lambda::Function
のPhysicalResourceId
が関数名になります。
スタック作成時のログを確認しても良いのですが、ここでは簡単にしたかったので関数を実行して確認します。
# 標準のboto3 > aws lambda invoke \ --function-name cfn-lambda-backed-te-NonUseLambdaLayerFunctio-XXXXXXXXXXXX \ --log-type Tail \ outputfile.txt \ --query 'LogResult' | tr -d '"' | base64 -D START RequestId: 859e7e0b-4041-4fa6-bf61-84a31bd72cc9 Version: $LATEST 1.9.42 responseUrl = event['ResponseURL']e 15, in sendCCESS, {}) END RequestId: 859e7e0b-4041-4fa6-bf61-84a31bd72cc9 REPORT RequestId: 859e7e0b-4041-4fa6-bf61-84a31bd72cc9 Duration: 54.69 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 56 MB # Lambda Layerのboto3 > aws lambda invoke \ --function-name cfn-lambda-backed-test-UseLambdaLayerFunction-XXXXXXXXXXXXX \ --log-type Tail \ outputfile.txt \ --query 'LogResult' | tr -d '"' | base64 -D START RequestId: 2e422fb4-95ae-4274-b9a5-4ced212a78ec Version: $LATEST 1.9.173 responseUrl = event['ResponseURL']e 15, in sendCCESS, {}) END RequestId: 2e422fb4-95ae-4274-b9a5-4ced212a78ec REPORT RequestId: 2e422fb4-95ae-4274-b9a5-4ced212a78ec Duration: 28.95 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 35 MB
Layerを利用している関数で最新のAWS SDKを利用できることが確認できました。
まとめ
AWS Lambda LayersへのLayer作成部分もスタックに含めることができればよいのですが、Zipファイルを事前にS3へ上げるなりの準備が必要で、そうなるとS3のリソースを事前に作成しなきゃ。。。
など、、、
どうしても1アクションで完結しなさそうだったので、Layer作成は手動ですることにしました。
もう少し考えればうまくまとまりそうな気がしてますが、今のところはこれで満足です。
参考
AWS Lambda-backed カスタムリソース – AWS CloudFormation
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.htm
Lambda Layers で最新の AWS SDK を使用する – Qiita
https://qiita.com/hayao_k/items/b9750cc8fa69d0ce91b0
元記事はこちら
「AWS CloudFormationのAWS Lambda-backedカスタムリソースで最新のAWS SDKを利用する」