cloudpack あら便利カレンダー 2019 の記事となります。誕生秘話 はこちら。
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
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.html
Lambda Layers で最新の AWS SDK を使用する - Qiita
https://qiita.com/hayao_k/items/b9750cc8fa69d0ce91b0