こんにちは🐱
カスタマーサクセス部の山本です。
興味深い機能を教えてもらったので、調査してみました!!
- Terraform で管理している AWS 環境における、 ECS のタスク定義
- ignore_changes 属性を使った際に困ること
- Terraform のコード(tf) 以外の方法で更新した ECS タスク定義について、 Terraform に認識させる track_latest オプション
- まとめ
Terraform で管理している AWS 環境における、 ECS のタスク定義
ECS サービスや ECS タスクのデプロイは、他の AWS サービス、例えば CodePipeline などを利用して行う場合があります。
参考:チュートリアル: を使用した Amazon ECS 標準デプロイ CodePipeline - AWS CodePipeline
その際に、ECS のタスク定義は、Terraform のコード(tf) 以外の方法で更新されることになります。
初期構築時に ECS のタスク定義を Terraform のコード(tf) で作成したものの、後から CodePipeline などでデプロイパイプラインを作って、それ以降の更新は パイプライン が担うという場合です。
そういった場合に、Terraform のコード(tf)では、ignore_changes
属性を ECS タスク定義に付与し、terraform apply
の更新対象から外すと良いでしょう。そのように運用しているケースも多いかと思います。
ignore_changes
属性を付与することで、Terraform apply
した場合にも、タスク定義は更新しません。
ignore_changes
に関する参考記事もあるので参照ください。
【Terraform】plan / apply と状態ファイル (tfstate) の関係 - サーバーワークスエンジニアブログ
コード例:
resource "aws_ecs_task_definition" "latest-trial" { family = "task1" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 2048 memory = 4096 container_definitions = jsonencode([ { name = "task" image = "public.ecr.aws/nginx/nginx:1.25" essenntial = "true" portMappings = [{ name = "nginx-80-tcp" containerPort = 80 protocol = "tcp" appProtocol = "http" }] } ]) lifecycle { ignore_changes = [container_definitions]} }
lifecycle { ignore_changes = [container_definitions]}
この部分で、タスク定義内のコンテナ定義 ( container_definitions ) (7-19行目)が、terraform apply
の更新対象から外れるように記載しています。
ignore_changes
属性を使った際に困ること
aws_ecs_task_definition
に関する issue を読むと、「パイプラインなど、Terraform のコード(tf) 以外の方法で更新した ECS タスク定義を Terraform にも認識させたい」という意見が多く見られました。
確かに、ignore_changes
属性を付与すると「パイプラインなど、Terraform のコード(tf) 以外の方法で更新を行うことになったため、Terraform のコード(tf) では ECS タスク定義のリソースを管理しない。」ということになります。
コードを用いてITインフラを管理する(IaC の)目的は、必要に応じて環境を簡単に再作成するためだったり、構成の同じ新しい環境を迅速にデプロイするためです。
Terraform で管理しないインフラリソースがあると、そのリソースは別の方法で作成することになり、インフラ環境を再作成する時の品質や、新しいインフラ環境の迅速なデプロイに影響が出ます。
Terraform のコード(tf) 以外の方法で更新した ECS タスク定義について、 Terraform に認識させる track_latest
オプション
そもそも ECS のタスク定義はどのように更新されるか
ECS のタスク定義で既存のリビジョンの設定内容を変更するには、新しいリビジョンを作成する必要があります。
これは Terraform でも、CodePipeline でも、マネジメントコンソールでも同じです。
例えば、CodePipeline で Blue/Green デプロイを構成している場合には、新しいリビジョンのタスク定義を使ってデプロイします。もし、ロールバックを行う場合には、以前のタスク定義のリビジョンに戻すという方式をとります。
文字通り、リビジョンを管理できるので、ECSサービスやタスクの状態を戻したり、次の状態に進めるのに便利です。
ECS の タスク定義 (aws_ecs_task_definition) を plan / apply した時のデフォルト動作
Terraformでは、コード (tf) に記載した 1 つのリソース (resource) と、Terraform が環境上に作成したリソースを 1 対 1 でマッピングして、状態管理しています。
そのため、terraform plan
では、「コード (tf)」 と「実環境上にある、Terraform で作成した タスク定義のリビジョン」の差分を比較し、コード (tf)を適用する計画を作ります。
差分がある場合、terraform apply
では、「実環境上にある、Terraform で作成した タスク定義のリビジョン」を削除し、「コード (tf)」を元に新しいリビジョンを作成します。
このように状態管理をしているため、「Terraform のコード(tf) 以外の方法で更新した ECS タスク定義のリビジョン」を、 Terraform に認識させることはできません。
(今回のアップデート)ECS のタスク定義 (aws_ecs_task_definition) に追加になった track_latest
オプション
2024/2/15 に aws_ecs_task_definition
リソースに、track_latest
オプションが追加になりました。
参考:terraform-provider-aws/CHANGELOG.md at main · hashicorp/terraform-provider-aws · GitHub
resource/aws_ecs_task_definition: Add track_latest argument
track_latest = true
を指定すると、terraform plan
の実行時には、
「コード (tf)」と 「実環境上にある 同じ ECS のタスク定義の最新リビジョン」 を比較します。
track_latest - (Optional) Whether should track latest task definition or the one created with the resource. Default is false.
track_latest
オプションを試す
以下、track_latest
オプションを有効にしたサンプルコードです。track_latest = true
resource "aws_ecs_task_definition" "latest-trial" { family = "task1" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 2048 memory = 4096 container_definitions = jsonencode([ { name = "task" image = "public.ecr.aws/nginx/nginx:1.25" essenntial = "true" portMappings = [{ name = "nginx-80-tcp" containerPort = 80 protocol = "tcp" appProtocol = "http" }] } ]) track_latest = true # lifecycle { ignore_changes = [container_definitions]} }
上記のサンプルコードを用いて、 cpu = 2048 、memory = 4096 のタスク定義を作成しました。
また、「Terraform のコード(tf) 以外の方法で更新した ECS タスク定義のリビジョン」を作ります。
サンプルコードで作成したタスク定義から、AWS マネジメントコンソールで cpu = 512 、memory = 1024 の新しいリビジョンを作りました。
この状態で terraform plan
を実行すると、「実環境上にある 同じ ECS のタスク定義の最新リビジョン」 である cpu = 512 、memory = 1024 のタスク定義を、元々のサンプル「コード(tf)」にあるcpu = 2048 、memory = 4096 に更新しようとします。
このように、Terraform の「コード(tf)」に書いたタスク定義の内容 と 「実環境上にある 同じ ECS のタスク定義の最新リビジョン」 を比較してくれます。
では、上記の比較を元にコード側を修正します。 コードの差分については自分で直す必要があります。 cpu = 512 、memory = 1024 にします。
resource "aws_ecs_task_definition" "latest-trial" { family = "task1" requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = 512 memory = 1024 container_definitions = jsonencode([ { name = "task" image = "public.ecr.aws/nginx/nginx:1.25" essenntial = "true" portMappings = [{ name = "nginx-80-tcp" containerPort = 80 protocol = "tcp" appProtocol = "http" }] } ]) track_latest = true # lifecycle { ignore_changes = [container_definitions]} }
terraform plan
を実行すると、"No changes. "(変更なし)と出ました。
「コード (tf)」と 「実環境上にある 同じ ECS のタスク定義の最新リビジョン」が揃ったためです。
その後にterraform apply
を実行しても、"No changes. "(変更なし)と出ました。
豆知識(本筋からは外れるので、この見出しは読まなくて大丈夫です。)
細かい話、上で"No changes. "(変更なし)となったterraform apply
では tfstate ファイルが更新されています。
「コード(tf)」を「実環境上にある 同じ ECS のタスク定義の最新リビジョン」 に合わせて、変更した結果、tfstate ファイルだけが、初回にサンプルコード(tf)を terraform apply
した状態で残っていたためです。
terraform apply
の前に、terraform plan -refresh-only
を実行した結果です。
「実環境上にある 同じ ECS のタスク定義の最新リビジョン」を元に tfstate ファイルを更新する計画を表示しています。
terraform apply
の後に、terraform plan -refresh-only
を実行した結果です。
terraform apply
で「実環境上にある 同じ ECS のタスク定義の最新リビジョン」を元に tfstate ファイルを更新したため "No changes. "(変更なし)と出ました。
-refresh-only
については以下の記事も参照ください。
【Terraform】plan / apply と状態ファイル (tfstate) の関係 - サーバーワークスエンジニアブログ
track_latest
オプションの注意点、その1
track_latest
オプションでは、「コード (tf)」と 「実環境上にある 同じ ECS のタスク定義の最新リビジョン」を比較します。
Terraform のコード(tf) 以外の方法で更新した ECS タスク定義を、 Terraform に認識させることができます。
しかし、例えば、「CodePipeline で Blue/Green デプロイをして、ロールバックを行った結果、タスク定義の最新バージョンを現在は使っていない。
」という状況では、terraform plan
をして比較しても、嬉しくないでしょう。
記事内で紹介した以下の部分ですね。
例えば、CodePipeline で Blue/Green デプロイを構成している場合には、新しいリビジョンのタスク定義を使ってデプロイします。もし、ロールバックを行う際には、以前のタスク定義のリビジョンに戻すという形をとります。
そのため、track_latest
オプションを有効にする際には「最新だけど使っていないタスク定義」は「登録解除」する必要があります。
track_latest
オプションの注意点、その2
通常、Terraformでは、コード (tf) に記載した 1 つのリソース (resource) と、Terraform が環境上に作成したリソースを 1 対 1 でマッピングして、状態管理しています。
しかし、track_latest
オプションでは、「コード (tf)」と 「実環境上にある 同じ ECS のタスク定義の最新リビジョン」を比較します
track_latest
オプションは Terraform の通常の状態管理とは異なる管理をする、特殊な機能だということです。
理解した上で、慎重に使う必要があります。
そのためなのか、デフォルトは false (無効)です。
まとめ
ECS のタスク定義 (aws_ecs_task_definition) に追加になった track_latest
オプションについて解説しました。
この機能によって、パイプラインなど、「Terraform のコード(tf) 以外の方法で更新した ECS タスク定義」を、 Terraform に認識させることができます。
Terraform のコード(tf)からできる限り ignore_changes 属性を減らして、コードを用いたインフラ環境の再利用性や一貫性を高めたい場合には、有用なオプションだと感じました。
一方で、Terraform の通常の状態管理とは異なる管理をする、少し特殊な機能ですので、理解した上で、慎重に使う必要があります。
便利な機能であるものの、デフォルトは false (無効)です。
上手に使っていきたいですね。
併せて読みたい
【Terraform】plan / apply と状態ファイル (tfstate) の関係 - サーバーワークスエンジニアブログ
山本 哲也 (記事一覧)
カスタマーサクセス部のエンジニア。2024 Japan AWS Top Engineers に選んでもらいました。
今年の目標は Advanced Networking – Specialty と Machine Learning - Specialty を取得することです。
山を走るのが趣味です。今年の目標は 100 km と 100 mile を完走することです。 100 km は Gran Trail みなかみで完走しました。OSJ koumi 100 で 100 mile 砕け散りました。どこかで 100 mile やりたいです。
基本的にのんびりした性格です。座右の銘は「いつか着く」