この記事はReviCo Advent Calendar 2025の18日目の記事です。
昨日は、かなっぺさんの自分の仕事を子供に説明するということでした。
はじめに
はじめまして!ReviCo 開発2年目の しげ です。
今回は「ECSネイティブのB/G(Blue/Green)デプロイで、長年がんばってくれていた“古のバッチ”を(一部)駆逐した話」を書きます。
ReviCoの一部のリリースは、CodeDeploy とお手製バッチの合わせ技でB/Gデプロイしていました。
…が、2025年7月のアップデートで ECSの組み込み機能としてB/Gデプロイが可能になり、状況が一変。
「えっ、もうECSだけでできるの?あのバッチ、引退できるのでは?」
ということで、移行しました。
この記事では以下をお話しします。
- なぜ移行したのか(背景)
- 何を用意して、何に気をつけて移行したのか(移行手順)
- そして、やらかした話(供養)
- 最後にまとめ
なお、この記事は社内の取り組み紹介目的で、具体的なアカウントIDなどは伏せています。
背景
ECSネイティブB/Gが来た(2025年7月)
2025年7月のアップデートで、ECSの組み込み機能としてBlue/Greenデプロイ(以下ECSネイティブB/G)がサポートされました。
つまり、
- CodeDeployを前提にしなくても
- ECSがALBの切り替えやフックを面倒見てくれて
- “デプロイの途中で止める/検証する” といった制御もやりやすい
という未来がやってきたわけです。ありがたい。
これまでの仕組み:CodeDeploy + お手製バッチ
一方それまで、ソリューションのある部分のリリースは、ざっくりこういう流れでした。
- Azure Pipelinesから
- LambdaバッチでECRタグを
staging -> productionに付け替えて -
aws deploy create-deploymentでCodeDeployデプロイを作って - “承認待ち”で止めて動作確認して
-
aws deploy continue-deploymentでGreenへ切り替え
このフロー自体はちゃんと動いていました。
ただ、お手製バッチが古来からReviCoに存在しており、しかも Node 20未満の古めの実装でした。
動いているシステムに対して「動くからヨシ!」は強いのですが、同時にこう思いました。
- 保守しづらい(歴史を感じる)
- “デプロイの要”が自作バッチである怖さ
- そして何より「いつか誰かが直す」未来が見える
…ということで、ECSネイティブB/Gへ移行しつつ、この機にバッチもまとめて引退させることにしました。
移行手順
ここからは、移行にあたって「何を用意したか」「何に気をつけたか」「どうやって味見(動作確認)を実現したか」を中心に、実際のメモを元にまとめます。
※注意:本記事における「味見確認」について
ReviCo用語の「味見確認」は、グリーン環境に本番トラフィックを流す前に、テスト用の導線(Dark Canary)で先行して実施する 手動テスト を指します。
以降の記事中では、この意味で「味見確認」という言葉を使います。
1. まず理解したこと:ECSネイティブB/Gの“止めどころ”
ECSネイティブB/Gには、デプロイ中のタイミングでLambdaを呼べる lifecycle stages(フック) があります。
特に重要だったのはこのあたりです。
-
TEST_TRAFFIC_SHIFT/POST_TEST_TRAFFIC_SHIFT
テスト用トラフィックをGreenへ流して確認できるタイミング -
PRODUCTION_TRAFFIC_SHIFT/POST_PRODUCTION_TRAFFIC_SHIFT
本番トラフィックを切り替えるタイミング - ベイク時間(最大24時間)
本番切り替え後にBlueをすぐ消さないための猶予
「味見確認(=Green環境の手動動確)をしたい」のに、何もしないと
テストトラフィックをGreenへ流した直後に、そのまま本番切り替えも進む
となります。
よって、テスト→本番の間に意図的にデプロイを止める仕組みが必要でした。
2. 用意したもの(テスト環境での動作確認)
結論から言うと、テスト環境では「既存リソースの使い回し」があまり効かず、想像より“新規で足すもの”がありました。
ECSサービス
- CodeDeployコントローラー付きの既存ECSサービスは、そのまま編集してネイティブB/Gに移行できないケースがある
(少なくとも今回の前提では「既存を修正」ではなく「新規作成」が必要でした) - 新規でECSサービスを作成
- 例:
<solution>-<env>-service-bg
- 例:
ターゲットグループ(2つ必要)
B/Gなので当然ですが、ターゲットグループはBlue/Greenで2つ必要です。
- 例:
- Blue:
<solution>-<env>-tg-blue - Green:
<solution>-<env>-tg-green
- Blue:
既存サービスのターゲットグループを「まあ流用で…」とはいかなかったので、新規作成しました。
ALB(検証条件によっては新規)
同一ポートでの検証をしたい、既存ALBへの影響を避けたい、といった理由で ALBも別で作成しました。
- 例:
<solution>-<env>-alb-bg
リスナーとルール(テスト用の導線)
ECSネイティブB/Gでは、本番トラフィックとは別にGreenへ到達できる “テスト用導線” を用意できます。
いわゆる Dark Canary 的な仕組みです。
今回、テストルールの条件に HTTPヘッダー を使いました。
- 例:
x-environment: testgreen
これにより、エンドユーザーの通常アクセスとは別に、開発者だけがGreenへアクセスして味見できます。
Lambda関数(味見確認で“止める”ため)
味見確認を成立させるために、POST_TEST_TRAFFIC_SHIFT でデプロイを止めるLambdaを用意しました。
- 例:
<solution>-<env>-approve-bg-switch
このLambdaの方針はこうです。
- S3の特定バケットを見に行く
- 「承認用オブジェクト」が あれば
hookStatus=SUCCEEDED(デプロイ続行) -
なければ
hookStatus=IN_PROGRESS(デプロイ停止&定期リトライ)
IN_PROGRESS の場合は約30秒後に再実行されるため、
味見中はLambdaが繰り返し呼ばれますが、処理が軽ければコスト的にも現実的でした。
S3バケット(承認フラグ置き場)
- バケット名(例):
<company>-<env>-bluegreen-deploy
「承認ボタン」ではなく「S3オブジェクト」で止めるのは、若干手触りが独特ですが、仕組みとしてはシンプルでした。
IAMロール/ポリシー
必要な権限が複数方向に出てきます。
- フックLambdaがS3を見るための権限(Get/List)
- ECSがLambdaを実行するための権限
- ECSがALB(リスナー/ルール/ターゲット)を操作するための権限
ここは移行で一番ハマりやすいポイントだと思うので、
「とりあえず最小権限で、エラーを見ながら足す」よりは、AWSドキュメントの必要権限を先に確認して寄せる方が早かったです。
3. 何に留意したか(運用・設計面)
既存CodeDeploy用のALB/ターゲットグループは“そのまま使える”とは限らない
移行ドキュメントにもありますが、CodeDeployで使っていた構成を再利用する場合でも、前提や制約があります。
- 既存の使い回しを狙う場合は、早めに移行ガイドを確認して「再利用できる物/できない物」を切り分ける
- “まずテスト環境で新規構築して動かす”のが安全
ベイク時間の設計
本番切り替え後、Blueをすぐ落とすのではなく猶予(最大24h)を取れます。
切り戻しや障害検知の観点で、どれくらい必要かはチームで合意しておくのが良さそうです。
4. 味見確認(先行手動テスト)をどう実現したか
今回のキモです。
デプロイ〜味見確認〜本番切り替えの流れ
- デプロイ開始 → Greenが起動してHealthyになる
- テストトラフィックをGreenへ(
TEST_TRAFFIC_SHIFT) - テストトラフィックが100%になったら(
POST_TEST_TRAFFIC_SHIFT)
Lambdaフックでデプロイを止める(hookStatus=IN_PROGRESSで待機) - 開発者だけが
x-environment: testgreenを付与してGreenへアクセスし、動作確認(=味見確認) - 味見確認OKなら、Azure Pipelinesの承認(ManualValidation)を実施
- 承認されたら、パイプライン側のタスクが S3に「承認用オブジェクト」を自動配置(=デプロイ再開の合図)
- LambdaがS3を確認し、オブジェクトを検知したら
hookStatus=SUCCEEDEDを返す - デプロイ再開 → 本番トラフィックをGreenに切り替え → ベイク → Blueスケールイン
ポイントは、人がやるのは味見と承認だけに寄せたところです。
- 承認用オブジェクトの「置き忘れ」や「場所間違い」は地味に怖い
- “手動でS3に置く”運用は、どうしても属人化しがち
- なので、承認の後処理(S3オブジェクト配置)はパイプラインにやらせるのが精神衛生上とても良かったです
さらに言うと、パイプラインの中で
- 事前に「承認用オブジェクトが無い」ことを確認(あったら掃除 or 失敗にする)
- 承認後に所定のキーへ put-object する
のようにしておけば、意図しない“即続行”事故も避けやすくなります。
やらかしたこと
テスト環境で移行手順を確認していたときの話です。
「ある程度ものになったので、一度いらないリソースはお掃除しよう!」
とAWSコンソールを触っていたら、勢い余って
CloudFormation(CFn)で作ったリソースを、手で削除
してしまいました。
結果どうなったかというと、
- CFnが更新できない
- ロールバックもできない
- つまり スタックが詰む
- そしてテスト環境のECSサービスが崩壊
という、教科書みたいな事故が起きました。
最終的には、CFnを再適用してなんとかなったのですが、作業は深夜へ突入。
以下を守るべきでした。
- CFn管理リソースは手で消さない(戒め)
- “検証”ほど慎重に(検証は壊していいが、壊し方には作法がある)
おわりに
今回の移行をまとめると、こんな学びがありました。
- ECSネイティブB/Gは、CodeDeployなしでもB/G運用を組み立てられて強い
- lifecycle hook により「止めて検証する」設計がしやすい
- 味見確認(=本番トラフィック切り替え前の先行手動テスト)は、
POST_TEST_TRAFFIC_SHIFTで“明示的に止める”ことで実現できた- 承認用オブジェクトの配置・確認までAzure Pipelinesに組み込み、運用ミスを減らせた
- 一方で、ALB/ターゲットグループ/ECSサービス/IAMなど「周辺リソースの準備」が重要で、移行は事前設計が勝負
- そしてCFn管理リソースを手で消すと、深夜が確定する(重要)
「古のバッチ」は、過去の誰かががんばって作ってくれた資産であり、当時はそれが最適解だったはずです。
その上で、プラットフォーム側が進化した今、よりシンプルで保守しやすい形に置き換えられたのは良い変化でした。
少し長くなってしまいましたが、本記事は以上となります!
読んでくださってありがとうございました!
明日はむーたくんの記事です!
お楽しみに!