ecspresso導入時のtfstate競合問題|Terraformと役割を分けるべき理由

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Terraform > ecspresso導入時のtfstate競合問題|Terraformと役割を分けるべき理由
「ecspressoを導入してECSのデプロイを自動化したのに、翌日にterraform applyを実行したらタスク定義が古いバージョンに戻ってしまった。」

ECSのデプロイワークフローにecspressoを組み込んだ直後、こうした「tfstateと本番の食い違い」に直面するチームは多くあります。原因はシンプルです。TerraformもecspressoもどちらもECSのリソースに触れるのに、それぞれの担当領域を分けていないためです。

この記事では、ecspresso導入時に起きるtfstate競合問題の実態と、lifecycleブロックを使った根本解決策、そしてTerraformとecspressoそれぞれが「何を担当すべきか」の設計指針を、具体的なHCL設定例とともに解説します。

動作確認環境: Terraform 1.9 / ecspresso v2.4 / AWS provider 5.x

この記事のポイント

・ecspressoがデプロイしたタスク定義リビジョンはtfstateと食い違いが生じる
・lifecycle { ignore_changes }でecspresso管轄フィールドをTerraformから切り離せる
・Terraformはインフラ基盤を、ecspressoはECSデプロイをそれぞれ担うのが正しい設計
・terraform state showでtfstateの現在値を確認してから設計を決める


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

ecspressoとTerraformは「何を管理するか」が根本的に違う

TerraformはHCLで記述したリソース定義をtfstateと突き合わせて差分を管理するツールです。一方ecspressoは、ECSサービスのデプロイに特化したCLIツールで、ecs.json(サービス定義)とecs-task-def.json(タスク定義)を読み込んでECS APIを直接操作します。

問題の本質は、この2つのツールが「重複してECSリソースに触れる」点にあります。

・Terraform:aws_ecs_task_definition・aws_ecs_serviceをtfstateで管理する
・ecspresso:タスク定義の新リビジョンを登録し、ECSサービスのタスク定義を更新する

ecspressoがmy-app:5(リビジョン5)にサービスを更新した後、Terraformのtfstateにはmy-app:3(リビジョン3)が残ります。この状態でterraform applyを実行すると、Terraformは「リビジョン3に戻すべき変更がある」と判断し、デプロイを巻き戻します。これがtfstate競合問題の正体です。

tfstate競合問題の実態|どんな場面で起きるか

1. ecspressoデプロイ後にterraform applyがタスク定義を上書きする

もっとも典型的なパターンです。CI/CDパイプラインでecspressoを使って新しいDockerイメージをデプロイした後、別のパイプラインやオペレーターがterraform applyを実行します。

# ecspressoでデプロイ(タスク定義 my-app:5 に更新) $ ecspresso deploy --config ecspresso.yml # terraform planで差分が出る(Terraformはtfstateのリビジョン3を正とする) $ terraform plan # aws_ecs_service.app will be updated in-place ~ resource "aws_ecs_service" "app" { ~ task_definition = "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/my-app:5" -> "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/my-app:3" }

terraform applyを実行するたびにリビジョン3に戻るため、ecspressoで進めたデプロイが無意味になります。

2. desired_countの競合

ecspressoは--desired-countオプションやサービス定義ファイルで実行タスク数を指定できます。オートスケーリングと組み合わせている場合、スケールアウト後のタスク数(例: 10台)をTerraformが定義値(例: 2台)に戻すという事故も起きます。

# Terraformのリソース定義(desired_count = 2 で固定) resource "aws_ecs_service" "app" { name = "my-app" cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.app.arn desired_count = 2 # オートスケール後に terraform apply で2に戻る }

3. terraform planが常に差分を出し続ける

上記2つの競合が起きると、terraform planを実行するたびに変更差分が表示され続けます。「planがクリーンにならない」状態はTerraformの運用ルールを守りにくくし、チーム全体の認知負荷を高めます。

根本解決策|lifecycle ignore_changesでフィールドを除外する

1. 競合するフィールドをignore_changesに列挙する

lifecycleブロックのignore_changesは、指定したフィールドをtfstate差分比較から除外します。ecspressoが管理するフィールドをここに列挙することで、Terraformとの競合を解消できます。

resource "aws_ecs_service" "app" { name = "my-app" cluster = aws_ecs_cluster.main.id task_definition = aws_ecs_task_definition.app.arn desired_count = 2 lifecycle { ignore_changes = [ task_definition, # ecspressoがリビジョンを更新するため desired_count, # オートスケーリング・ecspressoが変更するため ] } }

この設定を追加した後にterraform planを実行すると、ecspressoが更新したタスク定義リビジョンや実行タスク数は変更対象から除外され、planがクリーンになります。

2. aws_ecs_task_definitionの扱い方

ecspressoはecs-task-def.jsonでタスク定義を完全に管理します。Terraformでもaws_ecs_task_definitionリソースを宣言していると、二重管理になります。

設計の選択肢は2つです。

・A案:Terraformからタスク定義を完全に削除する(ecspressoに一本化)
・B案:Terraformはタスク定義の「初期バージョン」だけを管理し、以降のリビジョン更新はecspressoに委ねる

本番運用ではB案が現実的です。初回のterraform applyでタスク定義のリビジョン1を作成し、以降のデプロイはecspressoが担当します。Terraform側ではaws_ecs_serviceのみignore_changes = [task_definition]を設定します。

なお、TerraformとecspressoのECSデプロイ連携設計を体系的に学ぶには、TerraformのIaC設計コースも参考にしてください。

Terraform vs ecspresso|役割分担の設計指針

競合問題の根本対策は、2つのツールの担当領域を明確に分けることです。
管理ツール 担当リソース 変更タイミング
Terraform VPC・サブネット・セキュリティグループ・ECSクラスター・IAMロール・ALB・ECRリポジトリ・CloudWatchロググループ インフラ変更時(低頻度)
ecspresso ECSサービスのタスク定義リビジョン更新・desired_count・デプロイ戦略(rolling update) アプリデプロイ時(高頻度)
Terraformはインフラの「構造」を管理し、ecspressoはその上で動くサービスの「デプロイ」を管理するという分業です。

この設計にすることで得られるメリットは次のとおりです。

・terraform planがクリーンになる:デプロイのたびに差分が出なくなる
・デプロイ速度が上がる:terraform applyを経由せず ecspresso deploy で即時反映できる
・権限分離が明確になる:インフラ変更はTerraform管理者、デプロイはアプリチームという分業が可能
・ロールバックが容易になる:ecspressoのecspresso rollbackコマンドで直前のタスク定義リビジョンに戻せる

terraform state showでtfstateの実態を確認する

設計変更の前に、現在のtfstateが何を記録しているかを確認します。

# ECSサービスのtfstate内容を確認 $ terraform state show aws_ecs_service.app # aws_ecs_service.app: resource "aws_ecs_service" "app" { cluster = "arn:aws:ecs:ap-northeast-1:123456789012:cluster/my-cluster" desired_count = 2 id = "arn:aws:ecs:ap-northeast-1:123456789012:service/my-cluster/my-app" name = "my-app" task_definition = "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/my-app:3" ... }

task_definitionフィールドに表示されているリビジョンが本番で実際に動いているリビジョンと一致しているかを確認します。食い違いがある場合、ecspressoとTerraformの競合がすでに発生しています。

# AWS CLIで本番の実際のタスク定義リビジョンを確認 $ aws ecs describe-services \ --cluster my-cluster \ --services my-app \ --query "services[0].taskDefinition" \ --output text arn:aws:ecs:ap-northeast-1:123456789012:task-definition/my-app:5

tfstateが:3、本番が:5ならば競合が起きています。この状態でterraform applyを実行するとリビジョン3に巻き戻ります。

ignore_changesを設定した後にterraform applyを1回実行し、その後terraform planでdiff=0になることを確認してください。これで設定が正しく機能しています。

本記事のまとめ

問題 原因 解決策
terraform applyがタスク定義を巻き戻す tfstateが古いリビジョンを正として保持している aws_ecs_serviceにignore_changes = [task_definition]を追加
desired_countが定義値に戻る オートスケール・ecspressoの変更をTerraformが上書きする ignore_changes = [desired_count]を追加
terraform planが常に差分を出す TerraformとecspressoがECSリソースを二重管理している 役割分担を明確化してignore_changesで境界を宣言する
TerraformとecspressoはどちらもECSリソースに触れる可能性がありますが、「インフラ構造はTerraform・デプロイはecspresso」という役割分担をHCLのlifecycleブロックで明示することが、競合問題の根本解決です。

lifecycle { ignore_changes = [task_definition, desired_count] }の1設定で、terraform planが常にクリーンになり、ecspressoのデプロイが安全に機能します。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、TerraformによるIaCの設計・実装を現役エンジニアが手順を追って解説しています。ecspressoを含むデプロイツールとの連携設計も扱うコースです。詳しくはTerraformコース詳細ページをご確認ください。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。