業務でLambda Functionを利用する機会があり、せっかくなので気になっていたCustom Runtime、Layer、AWS SAM(Serverless Application Model)を使うことにしました。
その下調べをしたので、記録を残しておきます。
試したもの
それぞれの概要です。
今回はAWS CLIを使うためのCustom Runtimeを作成(クラメソさんの記事を参考に)、SAMを使ってLayer化するところまで実施しました。
なにがいいかって、LambdaでAWS CLIがそのまま動かせるので「シェルスクリプトしか書けないからLambda使えって言われても。。」なインフラ担当もLambdaデビューできちゃうところ。と、既存のシェルスクリプトを簡単に移行できちゃいそうなところ。※実行時間の制限:15分(2019/04/16現在)は考慮要。
作業
前提
今回使用したPCの環境です。
下準備
LambdaからS3にデータをアップロードする処理があるので、必要なリソースを準備をします。
S3 バケットを作成します。今回は「p-lambda-layer-awscli」という名称にしました。(バケット名はグローバルで一意である必要があるので、適宜書き換え。)
$ aws s3 mb s3://p-lambda-layer-awscli --region ap-northeast-1 --profile <profile-name> make_bucket: p-lambda-layer-awscli
LambdaがS3にアクセスするので、コンソールからIAM Role「Lambda-S3FullAccess」を作成します。
AWS CLIが使えるCustom Runtimeを作成
こちらの手順1、手順2を実行します。(上記のクラメソさん記事からリンク)
流れはざっくりこんな感じです。
- 01.build_deploy.sh
- 02.create_aws_layer.sh
実行してみます。
$ ./shell/01.build_deploy.sh Lambda-S3FullAccess p-lambda-layer-awscli <AWS CLIのprofile-name> adding: function.sh (stored 0%) adding: bootstrap (deflated 42%) { "FunctionName": "layer-creater", "FunctionArn": "arn:aws:lambda:ap-northeast-1:<Account ID>:function:layer-creater", "Runtime": "provided", "Role": "arn:aws:iam::<Account ID>:role/Lambda-S3FullAccess", "Handler": "function.handler", "CodeSize": 1043, "Description": "", "Timeout": 900, "MemorySize": 256, "LastModified": "2019-04-16T06:28:36.293+0000", "CodeSha256": "rKPZwQXwtqQTWPSnUKfRLDg5eHxQ3vPcGkJEcEayz/g=", "Version": "$LATEST", "Environment": { "Variables": { "S3_BUCKET": "p-lambda-layer-awscli" } }, "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "cab099e6-ceb5-4dac-bcc1-faed0452c899" } { "StatusCode": 202 } $ ./shell/02.create_aws_layer.sh p-lambda-layer-awscli <AWS CLIのprofile-name> download: s3://p-lambda-layer-awscli/provided.tgz to aws-cli-layer/provided.tgz ・・・ { "Content": { "Location": "https://awslambda-ap-ne-1-layers.s3.ap-northeast-1.amazonaws.com/snapshots/<Account ID>/aws-cli-layer-13637de3-c15f-4915-a212-0a18bf368726?versionId=XWPks5TjWf3ofzRmJTdhO8zQsWzsBcN2&X-Amz-Security-Token=AgoJb3JpZ2luX2VjEDYaDmFwLW5vcnRoZWFzdC0xIkcwRQIgFhXsJRXouon5uEdxpj%2FhOMZp686sEVlRZiQTKkBSzogCIQDbt2GJ4JGsIbQIAp36eSnao%2Bl6HfPjvjN1j3V%2F8S5ajSrtAwj%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDkxOTk4MDkyNTEzOSIM51W2l9dRkC5jtCRRKsED3YeVgrBNXLYStf2qgzPFNN2KqHlzQieaVSkMMl8SSU1CBQEhkhqKfC6otOV7BoG6isjNDwOWL3X4udi3VakgmTucpP0amB8%2BwTaquRQ321ENeMYavW1%2B7vWBk5q0G1cRG8az%2FiVOyWWrFAxg27Iy76CvqrNykX%2BydJqh10rXcEXWzlgeaoSjAeV1e3OR3ikTFlosnF6djZIDaHri4YG0D1%2Fy5yW7%2Fof%2FrSUVT8Y5nJTCvbD1NGkHhE03MXWcnocdvQadqsUkvUZ4lGE%2BJQMM%2F0VQnNjREu3iucxNQMiBDh2c7yntKtgW%2FD2J8jXqn9TP%2B%2Fv3u78CGbb4q1tdZGTcWHaaCYQk5SHGrw0TMOaji1hL6h8kf%2F8hZaE1MTfUlPEdZ7MSFfM24JujXQlhi6K2LBdHyaMQi4y%2FAOegq2m86p%2Ffam%2B9s5pWhtvRemL68ZRz3mr1j7Wi3GuvEQ%2B1Fv4qCZ5EMu3W%2Bat9ypYqtgFeClXcdBIP7UfRxgJLXbVXbaAFxV5yt7HPB6CFvAOQEuhZtbnIsXBc6xQk1aRH8vMj0FAiENy4EFCALKqDmPurfPKFXsPdf89G6QjtInP0HTPLG1Uwx%2BTV5QU6tAHcZkV2RO7hPJmxWBgG22GZX0kb0BXVFycasou%2FaliapZbc0Bbc4g45yewfBBz6TIuy9%2Bt%2BFe01DzKwFRYPY4y%2F37rG4mv%2BfEGiBWXjoYeEIWGA3UlTO81wG99PN22%2B3kC3Vapt99gHCHt%2BbimlrRNz8C%2FstD62Hz%2Ft%2BjKTZHVRL3P8xWmZFGMOAt1aFbuQEvoH%2FlypmXBHfbdiCs7kGDFi04QrKocJjBV7qgvACE8qgp6Rqrg%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20190416T064538Z&X-Amz-SignedHeaders=host&X-Amz-Expires=600&X-Amz-Credential=ASIA5MMZC4DJWO6HV3XU%2F20190416%2Fap-northeast-1%2Fs3%2Faws4_request&X-Amz-Signature=4b4c9499ce06f838f7ff7f94b315811d6a68337611f32c84f3c89088ef1c2c0d", "CodeSha256": "THTp3Fuyq2P8x+lRnf67berUV4sdMs7LRstuOT2b9Y8=", "CodeSize": 10610356 }, "LayerArn": "arn:aws:lambda:ap-northeast-1:<Account ID>:layer:aws-cli-layer", "LayerVersionArn": "arn:aws:lambda:ap-northeast-1:<Account ID>:layer:aws-cli-layer:1", "Description": "", "CreatedDate": "2019-04-16T06:45:46.357+0000", "Version": 1 }
※私の環境でうまく動作しない部分があったので、何点か修正しました。
- 01.build_deploy.sh
- 02.create_aws_layer.sh
- 上記と同じ理由で、aws lambda publish-layer-version に --region ap-northeast-1 を追加
これでLayerが作成されます。
ここでふと思ったのです。手元にLayerの元データ(aws-cli-layer.zip)があるし、SAMに組み込んだらAWS CLIを使ったシェルスクリプトLambda Functionがサクッと作れるのではないか、と。
SAMでLambda Function+Layer(AWS CLI)を作成
というわけで、SAMを試してみます。とりあえずデプロイできることを目標にしています。
aws-sam-cliという便利ツールがあるので、まずはHomebrewでインストールします。手順はこちら。
lambda-awscliというプロジェクトを作成します。
$ sam init -n lambda-awscli
諸々のテンプレートが作成されますが、ほとんど削除しちゃって、最終的には以下の構成。
各種ファイルの中身はこんな感じです。awscli.yamlでLayerの作成やLambda関数との紐付けを記述、実際に実行されるコードがfunction.sh(AWS CLIのバージョン出力など)。
# awscli.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
lambda_layer-awscli
Globals:
Function:
Timeout: 300
Resources:
LambdaAWSCLI:
Type: AWS::Serverless::Function
Properties:
CodeUri: function/
Handler: function.handler
Runtime: provided
Layers:
- !Ref LayerAWSCLI
LayerAWSCLI:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: awscli
Description: bash,awscli
ContentUri: runtime/
RetentionPolicy: Retain
# function.sh
function handler () {
RESPONSE=$(cat <<EOS
uname -a: $(uname -a)
bash version: $(bash --version)
awscli version: $(aws --version 2>&1)
EOS
)
echo $RESPONSE
}
sam packageでCloudFormationファイルを生成 & S3にアップロードし、sam deployでデプロイします。
$ sam package --template-file awscli.yaml --s3-bucket p-lambda-layer-awscli --output-template-file out.yaml --profile <profile-name>
Uploading to 04f9c35e4c311af1ba5f1f94ef3eaad2 10310668 / 10310668.0 (100.00%)
Successfully packaged artifacts and wrote output template to file out.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /Users/pirox/Documents/git/lambda-awscli/out.yaml --stack-name <YOUR STACK NAME>
作成されたout.yamlの中身。CodeUriやContentUriがS3にアップされたファイルのパスに書き換わっています。
# out.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'lambda_layer-awscli
'
Globals:
Function:
Timeout: 300
Resources:
LambdaAWSCLI:
Type: AWS::Serverless::Function
Properties:
CodeUri: s3://p-lambda-layer-awscli/cf26864049c0148728f76c2836005c2e
Handler: function.handler
Runtime: provided
Layers:
- Ref: LayerAWSCLI
LayerAWSCLI:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: awscli
Description: bash,awscli
ContentUri: s3://p-lambda-layer-awscli/04f9c35e4c311af1ba5f1f94ef3eaad2
RetentionPolicy: Retain
$ sam deploy --template-file out.yaml --stack-name lambda-awscli --capabilities CAPABILITY_IAM --profile <profile-name>
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - lambda-awscli
コンソールでCloudFormationを見てみます。できてる!
次にLambda。Layerできてる!!(何度か作成したので、画面キャプチャ取得時にはバージョンが3になってます)
Lambda FunctionもLayerにアタッチ(って言い方であってるのかな?)されてできてるー!!!
AWS CLIもバッチリ使えてます。(Python2系だった。。)
別でLambda Functionを作成する場合には、yamlファイルの中で今回作成したLayerと紐づければ使い回しができます。
業務での利用を考えると、Python3系にしておきたかったり、AWS CLIのバージョンアップについていきたかったり、いくつか課題がありそうです。
メモ
構築中に調べたこと。
Custom Runtime
カスタムランタイムを使用するには、関数のランタイムを
provided
に設定します。
bootstrap
という名前のファイルがデプロイパッケージにある場合、Lambda はそのファイルを実行します。ない場合、Lambda は関数のレイヤーにランタイムがないかどうかを確認します。ブートストラップファイルが見つからないか、実行可能でない場合、関数は呼び出し時にエラーを返します。
Custom Runtimeを使うには、bootstrapファイル内にモジュールのインストール処理を書く。(pip install --user awscli 等)
Layer
Layerがどこに紐づいているか知りたくて、whichコマンドを実行。
# Lambda関数でwhichコマンドを実行したログ
+++ which bash
++ echo /bin/bash
+++ which aws
++ echo /opt/bin/aws
ローカルのruntimeフォルダに配置したファイルが、そのままLambdaコンテナの/opt配下に配置されているようです。って公式ドキュメントにそのまま記載されていましたね。。
レイヤーは、関数実行環境の /opt ディレクトリに抽出されます。
LayerとLambda Functionは同一リージョンに配置する必要があるみたいです。東京リージョンのLambda FunctionにバージニアリージョンのLayerを紐付けようとしたらエラーになりました。
Layerにはバージョン管理の概念があるようで、ARNにもバージョン情報が含まれています。(バージョンARNと表記されています。)既存のLambda Functionのコードには手を加えずに、Layer(Runtime)のバージョンアップ運用が可能ですね。
また、version3を削除した後にLayerの更新(バージョンアップ)をした場合、新たに作成されるLayerはversion4になります。(3にはならない。)
Layerを紐付ける処理が必要になる分、実行速度は遅くなるのかな?と思いましたが、「Lambda Layersを使うとコールドスタートが高速化する」という検証結果があるようです。謎。
SAM
各種リソースの定義方法を覚えました。
# awscli.yaml
・・・
Resources:
LambdaAWSCLI:
Type: AWS::Serverless::Function
Properties:
CodeUri: function/
Handler: function.handler
Runtime: provided
Layers:
- !Ref LayerAWSCLI
LayerAWSCLI:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: awscli
Description: bash,awscli
ContentUri: runtime/
RetentionPolicy: Retain
Resource typesの書き方。
LayerのContentUriに記述したディレクトリに、Layerにしたいコンポーネントを格納しました(今回はAWS CLI)。
リソース名に使えるのは英数字のみです。ハイフンを使ってエラーが出ました。↓
Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state Status: FAILED.
Reason: Transform AWS::Serverless-2016-10-31 failed with: Invalid Serverless Application Specification document.
Number of errors found: 1.
Resource with id [lambda-awscli] is invalid.
Logical ids must be alphanumeric.
runtimeディレクトリにbin/のみを配置した場合はエラーが出たので、bootstrapの配置も必須みたいですね。
↓はリファレンス。