Terraform で Amazon ECS タスク定義を作りつつ,アプリケーションのライフサイクルとして GitHub Actions などの「Terraform 以外で」イメージタグを差し替えて Amazon ECS タスク定義を更新(正確には更新ではなくリビジョン追加)する運用を選択することがあると思う.さらにデプロイを繰り返すと使わなくなった Amazon ECS タスク定義が増えるため,定期的に「登録解除 (INACTIVE)」をすることもあると思う.ちなみに2023年2月からは削除もできるようになっているけど〜 \( 'ω')/
track_latest
とは
しかし Amazon ECS タスク定義を登録解除すると Terraform でリソースを追跡できず,terraform plan を実行すると Amazon ECS タスク定義を作り直そうとしてしまう.少し前置きは長くなったけど,2024年2月16日にリリースされた Terraform AWS Provider v5.37.0 で aws_ecs_task_definition に新しく track_latest
オプションが追加された❗️
track_latest - (Optional) Whether should track latest task definition or the one created with the resource. Default is false.
この track_latest
を使うと Terraform 側は常に「最新の」Amazon ECS タスク定義を追跡して比較してくれるため,Amazon ECS タスク定義の作り直しがなくなり,運用しやすくなる可能性がある👏
とは言え実際に試さないとイメージが沸かず,プルリクエストに書いてあるシナリオを参考に試してみた.
デフォルト or track_latest = false
の場合
Step.1
今回はイメージの例として amazonlinux のタグを 2.0.20231218.0
→ 2.0.20240109.0
→ 2.0.20240131.0
と更新する流れを試す.まずは Terraform で Amazon ECS タスク定義(リビジョン1)を作る.
resource "aws_ecs_task_definition" "sandbox_track_latest_false" { family = "sandbox-track-latest-false" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "256" memory = "512" container_definitions = jsonencode([ { name = "amazonlinux", image = "amazonlinux:2.0.20231218.0" } ]) }
Step.2
次は Terraform 以外(今回は AWS CLI を使う)でイメージタグを更新した Amazon ECS タスク定義を2個を作る(リビジョン2・リビジョン3).この状態でアプリケーションとして稼働する最新の Amazon ECS タスク定義は「リビジョン3」となる.
$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240109.0.json $ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240131.0.json
📝 taskdefinition-2.0.20240109.0.json
{ "family": "sandbox-track-latest-false", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "containerDefinitions": [ { "name": "amazonlinux", "image": "amazonlinux:2.0.20240109.0" } ] }
📝 taskdefinition-2.0.20240131.0.json
{ "family": "sandbox-track-latest-false", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "containerDefinitions": [ { "name": "amazonlinux", "image": "amazonlinux:2.0.20240131.0" } ] }
Step.3
ここで使わなくなった Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除する.
$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-false:1 $ aws ecs deregister-task-definition --task-definition sandbox-track-latest-false:2
Step.4
最後に terraform plan を実行すると Amazon ECS タスク定義を作り直そうとする😨 ちなみに個人用の Terraform Cloud のキャプチャを載せている.
track_latest = true
の場合
Step.1
基本的には同じだけど,名前を sandbox-track-latest-true
に変更して,track_latest = true
も設定した.まずは Terraform で Amazon ECS タスク定義(リビジョン1)を作る.
resource "aws_ecs_task_definition" "sandbox_track_latest_true" { family = "sandbox-track-latest-true" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "256" memory = "512" track_latest = true container_definitions = jsonencode([ { name = "amazonlinux", image = "amazonlinux:2.0.20231218.0" } ]) }
Step.2
Step.2 も基本的には同じ.Amazon ECS タスク定義を2個作る(リビジョン2・リビジョン3).
$ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240109.0.json $ aws ecs register-task-definition --cli-input-json fileb://taskdefinition-2.0.20240131.0.json
📝 taskdefinition-2.0.20240109.0.json
{ "family": "sandbox-track-latest-true", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "containerDefinitions": [ { "name": "amazonlinux", "image": "amazonlinux:2.0.20240109.0" } ] }
📝 taskdefinition-2.0.20240131.0.json
{ "family": "sandbox-track-latest-true", "networkMode": "awsvpc", "requiresCompatibilities": [ "FARGATE" ], "cpu": "256", "memory": "512", "containerDefinitions": [ { "name": "amazonlinux", "image": "amazonlinux:2.0.20240131.0" } ] }
Step.3
ここで使わなくなった Amazon ECS タスク定義(リビジョン1・リビジョン2)を登録解除する.
$ aws ecs deregister-task-definition --task-definition sandbox-track-latest-true:1 $ aws ecs deregister-task-definition --task-definition sandbox-track-latest-true:2
Step.4
track_latest = true
を設定してると Step.4 から挙動が変わってくる💡ここで terraform plan を実行すると Amazon ECS タスク定義を作り直しではなく「最新の」Amazon ECS タスク定義を追跡して比較してくれる.実際に containerDefinitions.image
の値を最新の amazonlinux:2.0.20240131.0
から,Terraform コードで指定している amazonlinux:2.0.20231218.0
に戻すような差分が出ている❗️
次に Terraform コードを修正して最新の Amazon ECS タスク定義と一致させる📝
resource "aws_ecs_task_definition" "sandbox_track_latest_true" { family = "sandbox-track-latest-true" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "256" memory = "512" track_latest = true container_definitions = jsonencode([ { name = "amazonlinux", image = "amazonlinux:2.0.20240131.0" } ]) }
もう一度 terraform plan を実行すると No changes で差分なしになる👌
なるほどー \( 'ω')/
まとめ
2024年2月16日にリリースされた Terraform AWS Provider v5.37.0 で追加された aws_ecs_task_definition
の新しいオプション track_latest
オプションを試してみた❗️ドキュメントを読むだけではイメージが沸かず,実際に試してみて良かった.とは言え track_latest = true
を設定するとアプリケーションを頻繁にデプロイするときに変更の追随も大変そうなので ignore_changes
で変更を無視する運用も引き続き残りそう.まずは track_latest = true
の存在を覚えておこうー💡