CLIを使ってECSのタスク定義更新を楽にする方法
こんにちは、インフラエンジニアの土肥です。
なるべくGUIでの手動設定を避けるために、CLIからタスク定義の更新を行いたいと思ったとき少し工夫が必要でしたのでご紹介します。
やりたいこと
- 既存タスク定義情報のJSONをコマンドで取得
- 必要な部分を変更
- 新しいリビジョンをコマンドで作成
という流れをやりたかったのですが、コマンドで取得したJSONはそのままでは登録出来ないので整形する手順を入れてあげる必要があります。
難易度が高いものではないですがこの記事を読んだ方の手間を少しでも削減するために記載します。
やったこと
前提として更新対象のタスク定義は作成済みの状態で作業しています。
- 既存タスク定義情報のJSONを
describe-task-definitionで取得 - 結果を
jqで整形 - 必要な部分の変更
register-task-definitionで新しいリビジョンを作成
既存のタスク定義を取得
タグを設定している場合は—includeオプションの指定が必要です。
オプションを付けないとタグが設定されていても空配列で結果が返ってきてしまいます。
$ aws ecs describe-task-definition --task-definition aitp-sample --include TAGS > task_def_org.jsonそのまま登録してみる
取得したJSONをそのま登録できると嬉しいのですが、そもそもJSONの書式が異なるためエラーになります。
$ aws ecs register-task-definition --cli-input-json file://task_def_org.json
Parameter validation failed:
Missing required parameter in input: "family"
Missing required parameter in input: "containerDefinitions"
Unknown parameter in input: "taskDefinition", must be one of: family, taskRoleArn, executionRoleArn, networkMode, containerDefinitions, volumes, placementConstraints, requiresCompatibilities, cpu, memory, tags, pidMode, ipcMode, proxyConfiguration, inferenceAccelerators, ephemeralStorage結果をjqで整形
登録時に不要なキーが含まれていることと、JSONの書式が異なっていることがエラーの原因ですので登録可能な書式に整形します。
タグを含める場合は以下のようなコマンドになります。
$ jq '{ "containerDefinitions": .taskDefinition.containerDefinitions, "family": .taskDefinition.family, "executionRoleArn": .taskDefinition.executionRoleArn, "networkMode": .taskDefinition.networkMode, "volumes": .taskDefinition.volumes, "placementConstraints": .taskDefinition.placementConstraints, "requiresCompatibilities": .taskDefinition.requiresCompatibilities, "cpu": .taskDefinition.cpu, "memory": .taskDefinition.memory, "tags": .tags }' task_def_org.json > task_def.jsonタグを含めない場合はtaskDefinitionの中に全て必要なキーが含まれているので少し短くできます。
$ jq '.taskDefinition | del (.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' task_def_org.json > no_tag_task_def.json変更箇所を編集する
今回は環境変数を追加します。
$ git diff
diff --git a/task_def.json b/task_def.json
index cab97e7..37840a7 100644
--- a/task_def.json
+++ b/task_def.json
@@ -18,6 +18,10 @@
{
"name": "env",
"value": "env-sample"
+ },
+ {
+ "name": "dbhost",
+ "value": "hogehoge"
}
],
"mountPoints": [],gitで管理出来て変更のチェックがしやすいのも利点ですね。
登録する
最後にregister-task-definitionコマンドで登録して完了です。
$ aws ecs register-task-definition --cli-input-json file://task_def.json
{
"taskDefinition": {
"taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:******:task-definition/aitp-sample:2",
"containerDefinitions": [
{
"name": "sample-container",
"image": "nginx:latest",
"cpu": 0,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"entryPoint": [],
"command": [],
"environment": [
{
"name": "env",
"value": "env-sample"
},
{
"name": "dbhost",
"value": "hogehoge"
}
],
-- 省略 --最後に
更新のたびに同じコマンドを実行するので、スクリプトやMakefileでまとめてしまうとさらに運用が楽になるかと思います。
JQ='{ "containerDefinitions": .taskDefinition.containerDefinitions, \
"family": .taskDefinition.family, "executionRoleArn": .taskDefinition.executionRoleArn, \
"networkMode": .taskDefinition.networkMode, "volumes": .taskDefinition.volumes, \
"placementConstraints": .taskDefinition.placementConstraints, \
"requiresCompatibilities": .taskDefinition.requiresCompatibilities, \
"cpu": .taskDefinition.cpu, "memory": .taskDefinition.memory, "tags": .tags }'
fetch:
aws ecs describe-task-definition --task-definition aitp-sample --include TAGS | jq $(JQ) > task_def.json
reg:
aws ecs register-task-definition --cli-input-json file://task_def.json