ECSネイティブBlue/Greenで同一ListenerRuleにカナリア用TGを同居できない理由と回避策
ECSネイティブBlue/Greenデプロイは、advanced_configuration で指定した ListenerRule の forward config を排他的に管理します。同一 ListenerRule 上にカナリア用の3つ目の Target Group を同居させようとすると、ECSが forward config を上書きして消してしまいます。
ECS純正のCANARY/LINEARデプロイは使えますが、自前のTGとの同居はできません。
やるなら ListenerRule を分けるか、DNS/CDN レイヤーで振り分ける必要があります。
ECSネイティブB/Gで加重ルーティングを組もうとした
2025年7月にGAになったECSネイティブBlue/Green、CodeDeployが不要になってかなり楽になったんですよね。で、これを使いつつ ALB の加重ルーティングでカナリアリリースも組めないかなと調べていたんですが、3つの非互換性にぶつかりました。
端的に言うと、ECSネイティブB/G は ListenerRule を「自分の持ち物」として排他管理していて、blue と green の2つの Target Group だけが存在する世界を前提にしています。3つ目の TG が入ってくることを想定していません。
ECSネイティブB/GとALB加重ルーティングが共存できない3つの理由
forward config が丸ごと上書きされる
デプロイ完了時に ECS が ListenerRule の forward config を更新するんですが、このとき primary と alternate の2つの TG だけで構成し直します。
つまりこういうことが起きます。
デプロイ前:
ListenerRule forward config:
blue-tg weight=80
green-tg weight=10
canary-tg weight=10 ← 自前の加重ルーティング用
デプロイ完了時:
ECS が ModifyRule を実行:
blue-tg weight=0
green-tg weight=100
canary-tg → 消滅 ← forward config から除外される
ECS は「知らない TG」を消しているわけじゃなくて、「知ってる TG だけで forward config を構成し直す」という動きをしています。結果として3つ目以降の TG が消えるんですよね。
アクティブTGがblue/green以外だとデプロイが失敗する
ListenerRule 上で weight > 0 の TG が blue でも green でもない場合、そもそもデプロイ自体が通りません。
canary-tg に weight=10 が付いている状態でデプロイ開始 ↓ ECS: 「ListenerRule上のアクティブTGが想定外」 ↓ deployment failed: Service deployment rolled back because of invalid networking configuration.
ECS はデプロイ開始時に ListenerRule の状態を検証していて、「blue=100/green=0」か「blue=0/green=100」のどちらか(トラフィックを受けるTGがちょうど1つ)でないと受け付けません。
60/40 のような中間状態も NG です。
Terraformで直しても次のデプロイで再上書きされる
「じゃあ Terraform で3 TG 構成に戻せばいいのでは」と思うかもしれませんが、次の ECS デプロイが走った瞬間にまた2 TG に上書きされます。
時系列: t1: terraform apply → ListenerRule = [blue, green, canary] ← 3TG構成 t2: ECS deploy → ListenerRule = [blue, green] ← 2TGに上書き t3: terraform plan → "canary-tg が消えてる" という drift を検出 t4: terraform apply → ListenerRule = [blue, green, canary] ← また3TG t5: ECS deploy → ListenerRule = [blue, green] ← また上書き ... 無限ループ
Terraform と ECS が ListenerRule の管理権を奪い合う形になります。ignore_changes で逃げても本質的な解決にはなりません。
ECSネイティブB/Gでカナリアリリースを実現する回避策
同一 ListenerRule 上での共存は設計として成立しないので、別のアプローチが必要です。
- ECS の
deploymentConfiguration.strategyをBLUE_GREENからLINEARまたはCANARYに変更する(5%ずつ、10分間隔など)。strategyの値はROLLING/BLUE_GREEN/LINEAR/CANARYのどれか1つを選ぶ排他的な指定。LINEAR/CANARY は 2025年10月30日 GA(B/G の 2025年7月17日 GAとは別)。なお LINEAR/CANARY でも ListenerRule は ECS 管理下に入る点は同じなので、3TG 同居の問題を回避する形であって、ListenerRule を自由に使えるようになるわけではない - ListenerRule を分ける。カナリア用の TG は別の ListenerRule(別のパスやヘッダー条件)に紐づけて、ECS B/G が管理する Rule とは完全に分離する
- ALB の前段に CloudFront や Route 53 の加重ルーティングを置いて、ALB レベルではなく DNS/CDN レベルで振り分ける
注意点
ECSネイティブB/Gを採用する場合、ListenerRule は ECS に「明け渡す」ものだと理解しておく必要があります。advanced_configuration に渡した ListenerRule は ECS の管理下に入るので、同じ Rule を Terraform や他のツールから触ろうとすると必ずコンフリクトします。
CrowdStrikeのタスク定義パッチングでも似たような話がありましたが、「誰がそのリソースのオーナーなのか」をはっきりさせておかないと、Terraform drift の無限ループにハマります。
まとめ
- ECSネイティブB/G は ListenerRule の forward config を排他的に管理する
- blue と green の2 TG しか存在できない。3つ目は消される、デプロイが拒否される、Terraform で直しても再上書きされる
- 加重カナリアをやるなら、ListenerRule を分けるか、レイヤーを変える(DNS/CDN)
- ListenerRule のオーナーシップを ECS に渡す前提で設計するのが正解
参考
- Amazon ECS blue/green deployments - AWS公式ドキュメント
- Application Load Balancer resources for blue/green, linear, and canary deployments
- AdvancedConfiguration - Amazon ECS API Reference
- Troubleshooting Amazon ECS blue/green deployments
- ECS Native Blue/Green is Here! With Strong Hooks and Dark Canary - DEV Community