先日えいやと書いた AWS Lambda のデプロイツール lambroll ですが、これと公開済みの bash layer を使うとかなり気軽に(雑な) shell script を Lambda で実行できて体験がよかったので書いておきます。
AWS Lambda のミニマルなデプロイツール lambroll を書いた - 酒日記 はてな支店
今回はとある理由で ECS のサービス内のタスクを定期的に入れ換えたかったので、aws ecs update-service
を一発実行する、という要件。やりたいことはただ aws-cli を一発叩くだけでできるのに、Lambda 化するには Node やら Go やらで SDK 使ってコードを書いて…というのがめんどくさいこと、よくあると思います。
まず適当にディレクトリを掘って、そこで lambroll init
で初期化します。
$ mkdir ecs-task-replacer
$ cd ecs-task-replacer
$ lambroll init --function-name ecs-task-replacer
2019/11/13 22:16:21 [info] lambroll v0.2.1
2019/11/13 22:16:23 [info] function ecs-task-replacer is not found
2019/11/13 22:16:23 [info] creating .lambdaignore
2019/11/13 22:16:23 [info] creating function.json
2019/11/13 22:16:23 [info] completed
関数が存在しないので、次のようなスケルトンの function.json が生成されます。
{
"FunctionName": "ecs-task-replacer",
"Handler": "index.handler",
"MemorySize": 128,
"Role": "arn:aws:iam::123456789012:role/YOUR_LAMBDA_ROLE_NAME",
"Runtime": "nodejs10.x",
"Timeout": 3
}
これを bash layer GitHub - gkrizek/bash-lambda-layer: Run Bash scripts in AWS Lambda via Layers を使うように書き換えます。
Layers, MemorySize, Runtime, Role, Timeout を適当に指定。この例のように aws-cli を使う場合、Memory が少ない(CPUも比例して少ない) と aws コマンドを起動するのに大変時間がかかるので、1コアをフルに使える 1.5GB を指定するのがよいです。
{
"FunctionName": "ecs-task-replacer",
"Handler": "index.handler",
"Layers": [
"arn:aws:lambda:ap-northeast-1:744348701589:layer:bash:8"
],
"MemorySize": 1536,
"Role": "arn:aws:iam::123456789012:role/lambda-function",
"Runtime": "provided",
"Timeout": 30
}
関数本体は index.sh というファイルに、event を jq で処理して aws-cli を叩くだけのを書きます。今回は event で ECS cluster と service を指定できるように {"cluster": "CLUSTER_NAME", "service": "SERVICE_NAME"}
という構造にしてみました。(決め打ちでいいならハードコードしちゃってもいいですね)
function handler {
set -e
EVENT=$1
SERVICE=$(echo "$EVENT" | jq -r .service)
CLUSTER=$(echo "$EVENT" | jq -r .cluster)
aws ecs update-service \
--cluster "$CLUSTER" \
--service "$SERVICE" \
--force-new-deployment
echo "{\"success\": true}" >&2
}
lambroll deploy
でデプロイします。
$ lambroll deploy
2019/11/14 08:40:52 [info] lambroll v0.2.1
2019/11/14 08:40:52 [info] starting deploy function ecs-task-replacer
2019/11/14 08:40:54 [info] creating zip archive from .
2019/11/14 08:40:54 [info] zip archive wrote 342 bytes
2019/11/14 08:40:54 [info] updating function configuration
2019/11/14 08:40:54 [info] updating function code
2019/11/14 08:41:00 [info] deployed version 2
2019/11/14 08:41:00 [info] updating alias set current to version 2
2019/11/14 08:41:01 [info] alias updated
2019/11/14 08:41:01 [info] completed
手元から実行するには lambroll invoke
を使って、標準入力に event を与えます。--log-tail を付けると実行した Lambda のログ(の最後の4KB)が出力されます。
$ echo '{"cluster":"default", "service":"example"}' | lambroll invoke --log-tail
2019/11/14 08:46:35 [info] lambroll v0.2.1
{"success": true}
2019/11/14 08:46:57 [info] StatusCode:200 ExecutionVersion:$LATEST
s reached a steady state."
},
{
"id": "8304a25b-8329-4099-903f-677013206fe8",
"createdAt": 1572800779.798,
"message": "(service example) has reached a steady state."
},
...(略)
"schedulingStrategy": "REPLICA",
"enableECSManagedTags": false,
"propagateTags": "NONE"
}
}
END RequestId: c821f023-0af2-48e5-ae21-c6f381e9ec65
REPORT RequestId: c821f023-0af2-48e5-ae21-c6f381e9ec65 Duration: 20484.06 ms Billed Duration: 20600 ms Memory Size: 128 MB Max Memory Used: 103 MB Init Duration: 44.74 ms
2019/11/14 08:46:57 [info] completed
おしまい。
定期実行するには CloudWatch Events でポチポチとスケジュールを定義してやればよいですね。
最初に IAM role を用意するところと、init で生成された function.json を書き換えるところが少しだけ手間ですが、そのあとは index.sh を書き換えて deploy して invoke するのに1コマンドずつ叩くだけです。
個人的には雑に cron で shell script を定期実行したいだけなのに、コード書いて Lambda 用意してって億劫だなあ、みたいなストレスがだいぶ減る気がします。どうぞお試しください。