概要
こんにちは。ニフティの山田です。
2025/07/17に、ECS組み込みBlue/Greenデプロイがリリースされました。
従来、ECSの組み込みデプロイ機能はローリングアップデートにしか対応しておらず、Blue/Greenデプロイを行うためにはCodeDeployを使用する必要がありました。
今回の変更によりECSだけでBlue/Greenデプロイが可能になったほか、CodeDeployによる制約がなくなりました。
これらの変更点について解説していきます。
💡 ALB + ECS構成の場合に従来と比べてどうなるかを解説します
CodeDeploy Blue/Greenデプロイと比べて変わること
単にCodeDepoloyが要らなくなる、という点以外にも仕様の違いはいくつかあります。
切り替え方法

(上記はテストリスナー(ルール)有効時のパターンですが、無効時はテストトラフィックのシフトはスキップされます)
基本的な動作原理はCodeDeployのものと同じですが、以下の点で異なります。
- 本番・テストトラフィックの管理がリスナー単位からリスナールール単位に変わった
- CodeDeploy Blue/Greenでテスト用アクセスを行うにはポートを変えるしかなかった
- ルールに変わったことにより、ヘッダなどの条件でも切り替えられるようになった
- 常にBlue/Green両方のターゲットグループへの参照を保持するようになった


ライフサイクルフック
CodeDeploy同様に、決められたタイミングにライフサイクルフックが設定されており、Lambdaを呼び出して処理を実行、必要に応じてデプロイを停止させることができます。
フックの種類
名前は異なっていますが、同等+αのフックが用意されています。
- CodeDeploy Blue/Green
- BeforeInstall / AfterInstall
- AfterAllowTestTraffic
- BeforeAllowTraffic / AfterAllowTraffic
- ECS Blue/Green
- PRE_SCALE_UP / POST_SCALE_UP
- TEST_TRAFFIC_SHIFT / POST_TEST_TRAFFIC_SHIFT
- PRODUCTION_TRAFFIC_SHIFT / POST_PRODUCTION_TRAFFIC_SHIFT
- REONCILE_SERVICE
フック戻り値の種類
フックで呼び出されたLambdaが返すことのできる値として、IN_PROGRESS
が追加になっています。
SUCCEEDED | 成功(デプロイ続行) |
---|---|
FAILED | 失敗(デプロイを停止してロールバック) |
IN_PROGRESS | 実行中 |
IN_PROGRESSを返した場合、30秒後にまたLambdaが呼び出されます。
別途ロングランの確認(ex. E2Eテスト)を呼び出し、その終了を待つ、といった場合に使用できます。
CodeDeployの制約からの開放
CodeDeployを使用する場合、ECSのDeploymentControllerとしてCODE_DEPLOY
を指定する必要があります。このモードではECS serviceの保つ機能が制限されるという問題がありました。
ex)
- networkConfigurationなど、一部のECS serviceの設定を直接更新できなくなり、CodeDeployでのデプロイで更新する必要がある
- このせいでデプロイ側でサービス定義を管理する必要があった
- ECSが持つサーキットブレーカーの機能は使えず、CodeDeploy側の機能で代替する必要がある
- ECS Service Connectが使えない
ECS Blue/GreenではECS
の指定になるため、この制約がなくなります。
以上、基本的にはECS Blue/Greenの方が使い勝手が良くなっています。
AWS公式としてもECS Blue/Greenを推奨しており、AWSコンソール上では既にECSサービスの新規構築時にCodeDeployが選択できなくなっているため、今後の構築にはECS Blue/Greenを使いたいところです。
(後述の注意点を要確認)
Terraformでの設定
💡 ECS Blue/Green対応は AWS Provider v6.4.0から入っていますが、不具合があるためv6.6.0以降を使ってください
https://github.com/hashicorp/terraform-provider-aws/issues/43552
考慮事項
ECS Blue/Greenではリスナールール単位でトラフィックを管理するようになったのだが、これによりTerraformでは設定できないパターンが発生してしまっている問題があります。
リスナーにルールが1つしかない場合、以下のように設定してきたかと思います。
1 2 3 4 5 6 7 8 9 10 11 |
resource "aws_lb_listener" "listener" { ... default_action { type = "forward" target_group { ... } } } |
ここでdefault_action
でデフォルトリスナールールのアクションを定義しますが、このルールのARNはTerraformで取得することができません。ECS Blue/Greenの設定時にARNが必要になるため、この設定は行えないことになります。
なので、default_actionはダミーの設定として実質使用せず、別途リスナールールを定義する必要があります。
なお、以下のようにdataで取得できないかも検証しましたが、priorityの値にdefaultを受け付けず失敗しました。
1 2 3 4 |
ata "aws_lb_listener_rule" "default" { listener_arn = aws_lb_listener.listener.arn priority = "default" } |
設定
ALB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
resource "aws_lb_listener" "listener" { ... # 基本的にこのルールには来ない想定 default_action { type = "fixed-response" fixed_response { content_type = "text/plain" message_body = "Not Found" status_code = "404" } } } # ARNを取得できるように、別途リスナールールを用意 # テスト用ルールを用意する場合は、別途もう1つ作る resource "aws_lb_listener_rule" "prd" { listener_arn = aws_lb_listener.listener.arn priority = 100 action { type = "forward" # CodeDeployと異なり、2つのTGを両方登録してweightで制御する forward { target_group { arn = aws_lb_target_group.blue.arn weight = 100 } target_group { arn = aws_lb_target_group.green.arn weight = 0 } } } # default_action代わりに使う場合は、必ずヒットする条件にしておく # 他のルールがある場合はpriorityとあわせて要調整 condition { path_pattern { values = ["*"] } } } |
- 上記考慮事項を踏まえ、
default_action
をダミーにして別途リスナールールを用意 - CodeDeployと異なり、ターゲットグループを2つとも登録しておく必要あり
- ターゲットグループ自体の設定は従来と変わらないので割愛
ECS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
resource "aws_ecs_service" "service" { ... deployment_controller { type = "ECS" } deployment_configuration { strategy = "BLUE_GREEN" bake_time_in_minutes = 1 # 切り替え後にGreen環境を残しておく時間(分)、要調整 } deployment_circuit_breaker { enable = true rollback = true } network_configuration { # ここは変わらず } load_balancer { target_group_arn = aws_lb_target_group.blue.arn container_name = "app" container_port = 8080 advanced_configuration { alternate_target_group_arn = aws_lb_target_group.green.arn production_listener_rule = aws_lb_listener_rule.prd.arn # テスト用リスナールールを用意する場合 # test_listener_rule = "<テスト用リスナールールARN>" role_arn = "<Blue/Green切り替え用のARN>" } } lifecycle { ignore_changes = [ task_definition, desired_count ] } depends_on = [ "<ALB>" ] } |
従来との主な違い
- deployment_controllerを
type = ECS
に設定したうえで、deployment_configurationでstrategy = BLUE_GREEN
を設定することでECS Blue/Greenの設定になる - load_balancerの設定に
advanced_configuration
が増える- alternate_target_group_arn: Green側のターゲットグループARN
- production_listener_rule: 本番用リスナールールARN
- test_listner_rule: テストリスナールールARN
- role_arn: Blue/Green切り替えに使われるRoleのARN(別途作成が必要)
必要なポリシー
- Assume Role Policy
12345678910111213{"Version": "2012-10-17","Statement": [{"Sid": "AllowAccessToECSForInfrastructureManagement","Effect": "Allow","Principal": {"Service": "ecs.amazonaws.com"},"Action": "sts:AssumeRole"}]}
- Policy
- AmazonECSInfrastructureRolePolicyForLoadBalancers
中身
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849{"Version": "2012-10-17","Statement": [{"Sid": "ELBReadOperations","Effect": "Allow","Action": ["elasticloadbalancing:DescribeListeners","elasticloadbalancing:DescribeRules","elasticloadbalancing:DescribeTargetGroups","elasticloadbalancing:DescribeTargetHealth"],"Resource": "*"},{"Sid": "TargetGroupOperations","Effect": "Allow","Action": ["elasticloadbalancing:RegisterTargets","elasticloadbalancing:DeregisterTargets"],"Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*"},{"Sid": "ALBModifyListeners","Effect": "Allow","Action": "elasticloadbalancing:ModifyListener","Resource": ["arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*"]},{"Sid": "NLBModifyListeners","Effect": "Allow","Action": "elasticloadbalancing:ModifyListener","Resource": ["arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*"]},{"Sid": "ALBModifyRules","Effect": "Allow","Action": "elasticloadbalancing:ModifyRule","Resource": ["arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*/*"]}]}
- AmazonECSInfrastructureRolePolicyForLoadBalancers
参考: Amazon ECS infrastructure IAM role for load balancers
(EFSをつけたり、Service Connectをつけたりしている場合は追加のポリシーが必要なので注意)
- Assume Role Policy
- 従来はecs_serviceのほとんどの項目を
ignore_changes
で無視する必要があったが、その必要はなくなる- デプロイで変わるtask_definition、オートスケールで変わるdesired_countだけignoreすればよい
- serviceはすべてTerraformで管理する形にできそう
- もちろん従来同様の管理方法にしてもよい
その他
- デプロイ時のRole(or User)に以下のポリシーが必要
12345678910111213{"Version": "2012-10-17","Statement": [{"Action": "iam:PassRole","Effect": "Allow","Resource": ["{上記role_arnに指定したarn}"],"Condition": {"StringEquals": {"iam:PassedToService": "ecs.amazonaws.com"}}}]}
CodeDeploy Blue/Greenからの切り替え
公式に移行方法が解説されています。
が、稼働中のシステムを移行させるのは正直困難だと思った方が良いです。
- 前述のように構成が一部変わっており、デプロイ前に変更しなければならない
- 切り戻しができない
- deploymentControllerをCODE_DEPLOY → ECSにはできるが、逆は不可能
切り戻せないのが致命的なのでインプレースでのアップデートは避けたほうが良く、やるならALB+ECSのセットをもう1つ作って切り替えるのがよいでしょう。
注意事項
リスナールールのforward以外のアクションが消滅する
💡 2025/08/01時点で本事象について暫定対応され、forward以外のアクションが設定されているとデプロイが失敗するようになりました
Blue/Greenデプロイ対象となるリスナールールには通常、forwardアクション1つだけがついている状態になっているはずです。
一方、authenticate-oidc
のように認証を付けた場合、アクションは2つになります。
ex) Terraformでの例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
resource "aws_lb_listener_rule" "prd" { ... action { type = "authenticate-oidc" ... } action { type = "forward" ... } } |
この状態でBlue/Greenデプロイを行うと、forward以外のactionが消滅します。上記ではauthenticate-oidcのアクションが消えてしまいます。
CodeDeploy Blue/Greenでは保持してくれるので、ECS Blue/Greenのみで発生する事象です。
Canaryリリースが未実装
CodeDeployと異なり、リリース戦略を選択するパラメータが存在せず、Canaryリリースができません。
そのうち実装されそうではありますが、現段階では一括リリースしかできません。
ecspressoの取り扱い
デプロイにecspressoを使用している場合のみ影響します。
ECS Blue/Greenに移行することにより、サービス定義を全てTerraformで管理できるようになり、デプロイでの書き換えが不要になりました。つまり、タスク定義のみのデプロイでよくなったということになります。
一方でecspressoはサービス定義・タスク定義をセットで管理することを前提としており、この恩恵を受けることができません。一応タスク定義のみでの実行は可能だが想定した使い方ではなく、サポート外と明言されています。
https://github.com/kayac/ecspresso/issues/871
このため、
- サービス定義をデプロイ側で管理する(Terraform側で変更しない)運用を継続する
- ecspressoでのデプロイをやめる
- サポート外と知りつつ(自己責任で)使う
の3択を迫られることとなります。
おわりに
今回は、2025/07/17にリリースされた、ECS組み込みBlue/Greenデプロイについて解説しました。
参考になれば幸いです。