こんにちは、技術一課の加藤です。
先々週ごろにLambda上でAWSCLIを動かしてS3 Syncする – サーバーワークスエンジニアブログというブログを書きました。
この記事ではAWS CLIをローカルインストールしてPythonのコード上から呼び出すという実装をしています
ですがそもそもAWS CLIはCLIコマンドで呼び出すもの。Pythonからサブプロセスを切ってコマンドを叩くのはやや冗長な気がします。
ならbashから直接呼ぶ方が中間層がなくてスマートなのでは…?
ということで、カスタムランタイムを使ってbashから直接AWS CLIを呼び出してみることにしました。
前提
今回はカスタムランタイムでAWS CLIを動かすのが主題なので、処理はAQWS CLIのバージョン出力にとどめます。S3 Syncなどしたい場合は、 aws —version
の箇所を任意のコードに変更してください。
またカスタムランタイム自体の説明については、公式をご覧ください。
カスタム AWS Lambda ランタイム - AWS Lambda
簡単に言えば、あらゆる言語をLambdaで動かせるよ、というものになります。
手順
AWS CLIをLayerにおき、ハンドラー関数から呼ぶ構成にします。
- bootstrapファイルを作成
- bootstrapファイルをLayerとして登録
- ハンドラー関数を書いたfunction.shファイルを作成
- Lambdaを作成
bootstrapファイルを作成
bootstrapファイルはカスタムランタイムのエントリポイントとなり、必ず用意する必要があるファイルになります。このファイルでAWS CLIのインストールとメイン関数の呼び出しを行います。
#!/bin/sh # エラー停止の設定 set -euo pipefail # tmpフォルダ内にawscliを配置するためHOMEとPATHを設定 export HOME="/tmp" export PATH="$HOME/.local/bin:$PATH" # pipをインストール cd /tmp curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py python get-pip.py --user # pipを用いてawscliをインストール pip install awscli --user # ハンドラー関数を読み込み source $LAMBDA_TASK_ROOT/"$(echo $_HANDLER | cut -d. -f1).sh" # ループ処理 while true do HEADERS="$(mktemp)" # イベントを取得 EVENT_DATA=$(curl -sS -LD "$HEADERS" -X GET "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next") # リクエストIDを取得 REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS" | tr -d '[:space:]' | cut -d: -f2) # ハンドラー関数を実行 RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA") # レスポンスを返す curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$RESPONSE" done
bootstrapファイルをLayerとして登録
作成したbootstrapファイルをLayerとして登録します。以下はbashのコマンドになります。
$ chmod 755 bootstrap $ zip awscli.zip bootstrap $ aws lambda publish-layer-version --layer-name awscli --zip-file fileb://awscli.zip
ハンドラー関数を書いたfunction.shファイルを作成
次に実際にAWS CLIを使って処理を行うハンドラー関数を作成します。
先述の通り今回はバージョン出力のみを行いますが、実際にはS3 Syncなど行いたい処理をここに書いていくことになります。
function handler () { # aws --versionの結果をRESPONSEに格納 RESPONSE=$(aws --version 2>&1) echo $RESPONSE }
Lambdaを作成
ハンドラー関数を作ったので、Lambdaをデプロイしてみます。
Lambdaの実行用ロールを用意しておいてください。
$ chmod 755 function.zip $ zip function.zip function.zip $ aws lambda create-function --function-name lambda-cli \ --handler function.handler \ --runtime provided \ --role <RoleArn> \ --zip-file fileb://function.zip \ --layers arn:aws:lambda:ap-northeast-1:<AWSAccountID>:layer:awscli:1
では実行してみます。
$ aws lambda invoke --function-name lambda-cli response.txt { "StatusCode": 200, "ExecutedVersion": "$LATEST" } $ cat response.txt aws-cli/1.16.144 Python/2.7.12 Linux/4.14.88-90.76.amzn2.x86_64 botocore/1.12.134
無事、aws cliのバージョンを取得することができました。
他のメソッドも試して遊んでみてください。
おわりに
前回に引き続き、Lambda上でAWS CLIを呼ぶというややアクロバティックな実装をご紹介しました。
利用場面はかなり限られるとは思いますし、本番稼働するシステムに組み込むのはやや微妙な気がします。
とはいえやってできないものではないことがわかりましたので、もし必要になった場合は参考にしてみてください。