目的
apex で作成した Lambda function (python 2.7) をapex deploy
前に docker-lambda コンテナ上で動作確認するためのスクリプトを作る。
必要なもの(前提)
-
apex
- AWS Lambda のコードを apex で管理しているものとする
-
docker
- docker-lambda イメージ
- jq
-
AWS CLI の実行環境設定
-
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
- 環境変数にセット済み
-
動機
職場で運用中のAWSサービスの状態通知を行うため、AWS Lambda を活用しています。
Lambda function の作成/デプロイには apex を使用していますが、以下のように考えました。
-
apex deploy
前に, apex で作成した Lambda function の 動作テストを行いたい - AWS Lambda の動作環境を複製した
docker-lambda
イメージがある -
docker-lambda
コンテナ上で動作させ、通知先サービス(Slack等) に通知テストができそう - どの function 向けにも使えるよう,
docker-lambda
コンテナを実行するスクリプトを書けば良いのでは?
作成
docker-lambda
の Project Page にある Example を参考に, まず以下のように作成。
#!/bin/bash
SAMPLE_MESSAGE=`cat sample/test.json` # json形式のテストメッセージ
docker run --rm \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e SLACK_OPS_CHANNEL="#channel-name" \
-e SLACK_HOOK_URL="https://hooks.slack.com/services/xxx/xxx/xxx" \
-v $(pwd):/var/task lambci/lambda:python2.7 main.handle $SAMPLE_MESSAGE
-e
オプションで環境変数を docker-lambda
コンテナへ渡していますが、 apex では
AWS Lambda へ渡す環境変数を function.json
で既に持っています。
{
"description": "Notify the state of the instance to Slack",
"timeout": 10,
"memory": 128,
"role": "arn:aws:iam::xxxxxxxxxxxx:role/LambdaEC2Readonly",
"environment": {
"SLACK_OPS_CHANNEL": "#channel-name",
"SLACK_HOOK_URL": "https://hooks.slack.com/services/xxx/xxx/xxxxxxxx"
}
}
これを読み込むため、今回は jq を使って シェルスクリプトでdocker に渡す ことにしました。
jq の処理
参考にしたのはこちらの記事です。
まずは実行結果から。
% jq -r '.environment | to_entries | map("\(.key)=\(.value)") | join("\n")' function.json
SLACK_OPS_CHANNEL=#channel-name
SLACK_HOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxxxxxxx
オプション解説
次に引数指定したオプションを、順を追って見ていきます。
-
.environment
... json のenvironment
キーの値を読み込み
% jq -r '.environment' function.json
{
"SLACK_OPS_CHANNEL": "#channel-name",
"SLACK_HOOK_URL": "https://hooks.slack.com/services/xxx/xxx/xxxxxxxx"
}
-
to_entries
...key
,value
の各値を持った ハッシュ配列に変換
% jq -r '.environment | to_entries' function.json
[
{
"key": "SLACK_OPS_CHANNEL",
"value": "#channel-name"
},
{
"key": "SLACK_HOOK_URL",
"value": "https://hooks.slack.com/services/xxx/xxx/xxxxxxxx"
}
]
-
map("\(.key)=\(.value)")
... ハッシュ配列を.key=.value
形式の配列に変換
% jq -r '.environment | to_entries | map("\(.key)=\(.value)")' function.json
[
"SLACK_OPS_CHANNEL=#channel-name",
"SLACK_HOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxxxxxxx"
]
-
join("\n")
... 配列を改行コード区切りの文字列に変換
% jq -r '.environment | to_entries | map("\(.key)=\(.value)") | join("\n")' function.json
SLACK_OPS_CHANNEL=#channel-name
SLACK_HOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxxxxxxx
変換後の文字列は、スクリプトでの変数宣言と同じ形にしました。
これをファイルにリダイレクトすると、 後述の方法で docker
から読み込むことができます。
docker --env-file
オプション
先ほどの jq
実行結果をさらに、 .tmp.list
にリダイレクトしておきます。
% jq -r '~(中略)~' function.json > .tmp.list
SLACK_OPS_CHANNEL=#channel-name
SLACK_HOOK_URL=https://hooks.slack.com/services/xxx/xxx/xxxxxxxx
docker
の --env-file
オプションを使うことで、 .tmp.list
内の文字列を、 dockerの環境変数として 読み込むことができます。
% MESSAGE=`cat sample/test.json` && docker run --rm \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
--env-file .tmp.list \
-v $(pwd):/var/task lambci/lambda:python2.7 main.handle $MESSAGE
※便宜上、メッセージデータとなるjson を環境変数に入れる処理を行っています
詳しくは以下のドキュメントをご覧ください。
シェルスクリプト修正後
これらを踏まえて、最終的に以下のような形になりました。
#!/bin/bash
set -e
cd $(dirname "$0")
create_env_file() {
local env_json="function.json"
jq -r '.environment | to_entries | map("\(.key)=\(.value)") | join("\n")' $env_json > .tmp.list
}
remove_env_file() {
rm .tmp.list
}
create_env_file
docker run --rm \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
--env-file .tmp.list \
-v $(pwd):/var/task lambci/lambda:python2.7 main.handle "$@"
remove_env_file
実行例
目的の apex ソースディレクトリ内に docker-lambda.sh
を置いて、以下のように実行してください。
% MESSAGE=`cat ./sample_messages/test.json` && ./docker-lambda.sh $MESSAGE