概要
ALB の後ろで動く Amazon ECS のサービスを新しいバージョンに更新するとき、「利用者のアクセスを止めたくない」「でも追加の設備やコストは増やしたくない」という条件はよくあります。ECS には、サービスを更新するときのデプロイ方式として ローリング更新、ブルー/グリーン、リニア、カナリア があり、どれを選ぶかで、止まらずに入れ替わるか、新旧を並べて検証できるか、何を追加で用意するかが変わります。
この記事では、4 つのデプロイ方式の仕組みと、それぞれに必要なリソース・向いている場面を整理します。実践では、ALB 配下の Fargate のサービスをローリング更新で新しいタスク定義に切り替え、ALB へのアクセスがエラーを出さずに v1 から v2 へ入れ替わる様子を確かめます。

クラウドおさる見張り台の当番猿を交代させるとき、全員いっぺんに降ろしたら山が無防備になるでござる。新しい当番が上がってから古い当番が降りる。その交代の仕方を ECS で確かめるでござるよ。
この記事のメリット
- ECS のローリング更新で、タスクがどの順番で入れ替わるかを説明できるようになる
- 最小実行タスク(
minimumHealthyPercent)と最大実行タスク(maximumPercent)の決め方が分かる - ブルー/グリーン・リニア・カナリアに必要なリソースと、ローリング更新との違いを整理できる
- 「無停止・低コスト」「本番前に検証」「少しずつ移行」などの要件から、デプロイ方式を選べるようになる
執筆者とキャラクター紹介
執筆者:土肥(とひ)
株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。


クラウドおさる



はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。



基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。



猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。
技術解説
サービスの更新とデプロイ
ECS のサービスは、指定したタスク定義からタスクを決まった数(必要なタスク数)だけ動かし続けます。サービスのタスク定義のリビジョンやコンテナイメージを変えて更新すると、ECS は デプロイ を開始し、動いているタスクを新しい設定のタスクに置き換えます。どう置き換えるかを決めるのがデプロイ方式です。
| デプロイ方式 | 入れ替え方 |
|---|---|
| ローリング更新 | 古いタスクを少しずつ新しいタスクに置き換える。ALB のターゲットグループは 1 つのまま |
| ブルー/グリーン | 新しいリビジョン(グリーン)を古いリビジョン(ブルー)と並べて起動し、検証してから本番のトラフィックを一度に切り替える |
| リニア | グリーンを起動し、本番のトラフィックを同じ割合ずつ(例: 10% ずつ)段階的に移す |
| カナリア | グリーンを起動し、まず一部(例: 10%)だけを移して様子を見てから、残りを一度に移す |
ブルー/グリーン・リニア・カナリアは、以前は AWS CodeDeploy と組み合わせて実現していましたが、現在は ECS の機能として直接使えます(CodeDeploy を使う方式も残っていますが、ECS のドキュメントでは ECS のブルー/グリーンデプロイの利用が推奨されています)。
ローリング更新の進み方
ローリング更新で一度に増やしたり減らしたりするタスクの数は、サービスのデプロイ設定の 2 つの値で決まります。
| 設定 | 意味 | 計算 |
|---|---|---|
最小実行タスク %(minimumHealthyPercent) | デプロイ中に、正常な状態で動いていなければならないタスク数の下限 | 必要なタスク数 × 割合(切り上げ) |
最大実行タスク %(maximumPercent) | デプロイ中に、同時に動かしてよいタスク数の上限 | 必要なタスク数 × 割合(切り捨て) |
たとえば必要なタスク数が 2、最小 100%・最大 200% なら、ECS は古いタスク 2 つを動かしたまま新しいタスクを 2 つ起動します。新しいタスクが ALB のターゲットグループに登録され、ヘルスチェックに合格してから、古いタスクをターゲットグループから外し(登録解除の遅延の間に処理中のリクエストを終わらせる)、停止します。常に正常なタスクが 2 つ以上いるので、利用者のアクセスは止まりません。
逆に最小を 0% にすると、ECS は新しいタスクを起動する前に古いタスクを全部止められます。タスク数の上限を増やさずに済みますが、入れ替えの間はサービスが止まります。



最小 100%・最大 200% は「新しい当番が全員見張り台に上がってから、古い当番が降りる」交代でござるな。見張り台の席(タスクの上限)に余裕があるぶん、山はずっと見張られているのでござる。
新しいタスクが起動に失敗し続けたときに備えて、デプロイサーキットブレーカー をオンにしておくと、ECS がデプロイを失敗と判定し、ロールバックを選んでいれば最後に成功したリビジョンに戻します。アプリケーションのメトリクスで失敗を判定したいときは、CloudWatch アラームをデプロイに関連付ける方法もあります。
ブルー/グリーン・リニア・カナリアに必要なもの
3 つの方式は、ブルーとグリーンのサービスリビジョンを同時に動かし、ロードバランサー側でトラフィックの向き先を切り替えます。ALB を使う場合は、次のリソースを用意します。
| リソース | 内容 |
|---|---|
| ターゲットグループ 2 つ | ブルー用のプライマリターゲットグループと、グリーン用の代替ターゲットグループ |
| 本番リスナーとリスナールール | ECS がルールを書き換えてトラフィックの向き先(割合)を切り替える |
| テストリスナー(任意) | 本番のトラフィックを移す前に、別のポートでグリーンを検証する |
| インフラストラクチャの IAM ロール | ECS がロードバランサーのリソースを操作するためのロール |
切り替えの後は ベイク時間 の間ブルーを残しておき、問題があればすぐにブルーへ戻せます。各段階で Lambda 関数による検証や一時停止を差し込む ライフサイクルフック も使えます。その代わり、デプロイ中はブルーとグリーンの両方のタスクが動くので、リソースの使用量が最大で 2 倍になります。


デプロイ方式の選び方
| 要件 | 向いている方式 |
|---|---|
| ほぼ無停止で、追加の設備なしに、もっとも低コストで更新したい | ローリング更新(最小 100% など、正常なタスクを残す設定) |
| 本番のトラフィックを流す前に新しいバージョンを検証し、問題があればすぐ戻したい | ブルー/グリーン |
| 本番のトラフィックを少しずつ増やしながら、段階ごとに様子を見たい | リニア |
| まず一部の利用者だけで新しいバージョンを試し、問題がなければ残りを一度に移したい | カナリア |



「止めたくない」だけで、すぐにブルー/グリーンやカナリアを選ぶのは早合点でござる。ターゲットグループ 2 つやリスナールール、IAM ロールの用意が要るのでござる。「コストを抑えて」と言われたら、まずローリング更新でござるぞ。
実践
ALB 配下の Fargate のサービス soa-web-svc は、タスク定義 soa-web のリビジョン 1(ページに soa-web v1 と表示する)で 2 つのタスクを動かしています。CloudShell から ALB に 1 秒ごとにアクセスし続けながら、タスク定義のリビジョン 2(soa-web v2 と表示する)を作ってローリング更新し、エラーを出さずに入れ替わることを確かめます。
前提条件
- リージョン:
ap-northeast-1(東京) - 以下のリソースが作成済みであること
まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。
| リソース種別 | リソース名 | 内容 | 作り方の参考 |
|---|---|---|---|
| VPC | soa-ecs-vpc | パブリックサブネット 2 つ(ap-northeast-1a / ap-northeast-1c) | Amazon VPC で仮想ネットワークを構築しサブネットを設定する |
| Application Load Balancer | soa-ecs-alb | インターネット向け。リスナー HTTP:80 で soa-ecs-tg に転送 | ─ |
| ターゲットグループ | soa-ecs-tg | ターゲットタイプ IP、ヘルスチェックのパス /、登録解除の遅延 30 秒 | ─ |
| ECS クラスター | soa-ecs-cluster | Fargate | Amazon ECS と Fargate でコンテナを動かす |
| タスク定義 | soa-web(リビジョン 1) | Apache httpd のコンテナ 1 つ(0.25 vCPU / 0.5 GB)。環境変数 APP_VERSION の値(v1)をページに表示する | 同上 |
| ECS サービス | soa-web-svc | 必要なタスク数 2、ローリング更新、最小実行タスク 100%・最大実行タスク 200%、デプロイサーキットブレーカー(ロールバックあり)、soa-ecs-tg に登録 | 同上 |
※「Amazon ECS と Fargate でコンテナを動かす」の手順はロードバランサーを使わずパブリック IP で公開しています。この記事ではサービスを ALB のターゲットグループに登録します。
作成・変更するリソース一覧
| リソース種別 | リソース名 | 用途 |
|---|---|---|
| タスク定義のリビジョン | soa-web(リビジョン 2) | APP_VERSION を v2 にした新しいバージョン |
| ECS サービスの更新 | soa-web-svc | リビジョン 2 へのローリング更新 |
手順 1: サービスのデプロイ設定を確認する
AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに ECS と入力し、「Elastic Container Service」を選択します。
左側ナビゲーションの「クラスター」から soa-ecs-cluster を選択し、「サービス」タブで soa-web-svc を選択します。サービスの「デプロイ」タブを開き、「デプロイ設定」セクションで以下を確認します。
- デプロイ戦略: ローリングアップデート
- 最小および最大実行タスク: 最小 100% および最大 200%
- デプロイサーキットブレーカー: オン


「タスク」タブを開き、タスク定義 soa-web:1 のタスクが 2 つ「実行中」になっていることも確認します。
手順 2: ALB へのアクセスを流し続ける
上部の検索バーに EC2 と入力し、「EC2」を選択します。左側ナビゲーションの「ロードバランシング」→「ロードバランサー」で soa-ecs-alb を選択し、「DNS 名」を控えます。
コンソール下部の「CloudShell」をクリックして CloudShell を開き、次のコマンドを実行します。<ALB の DNS 名> は控えた値に置き換えます。1 秒ごとに ALB へアクセスし、時刻・HTTP ステータスコード・ページの内容を表示し続けます。
ALB=<ALB の DNS 名>
while true; do
code=$(curl -s -m 3 -o /tmp/body -w '%{http_code}' "http://$ALB/")
echo "$(date +%T) $code $(cat /tmp/body)"
sleep 1
done200 <h1>soa-web v1</h1> の行が 1 秒ごとに増えていきます。このタブは開いたまま、次の手順へ進みます。
手順 3: タスク定義の新しいリビジョンを作る
ECS のコンソールに戻り、左側ナビゲーションの「タスク定義」→ soa-web を選択します。リビジョン 1 を開き、右上の「アクション」→「新しいリビジョンの作成」を選択します。
「コンテナ – 1」の「環境変数 – オプション」で、キー APP_VERSION の値を v1 から v2 に変更します。その他の項目は変更せず、画面下部の「作成」をクリックします。


soa-web:2 が作成されたことを確認します。
手順 4: サービスをローリング更新する
「クラスター」→ soa-ecs-cluster →「サービス」タブで soa-web-svc を選択し、「サービスを更新」をクリックします。以下を設定します。
- タスク定義のリビジョン: 入力欄に
2と入力し、候補の「2(最新)」を選択 - 折りたたまれている「デプロイオプション」を展開し、デプロイ戦略が「ローリングアップデート」のままであることを確認(タイルで「ブルー/グリーン」「Canary」「リニア」も選べます)
- その他の項目はデフォルトのまま


「更新」をクリックします。サービスの「デプロイ」タブに移り、デプロイが始まります。
手順 5: タスクの入れ替わりを確かめる
soa-web-svc の「タスク」タブを開き、画面を数回更新します。最大実行タスク 200% の範囲で、古いタスクを残したまま soa-web:2 のタスクが 2 つ起動し、ALB のターゲットに登録されてから soa-web:1 のタスクが止まります。入れ替えは 2〜3 分で終わるので、新旧 4 つが同時に「実行中」の瞬間は見逃しやすいです。終わった後は、soa-web:2 が 2 つ「実行中」、soa-web:1 が 2 つ「停止済み」で並びます。


「イベント」タブを開くと、新しいタスクの起動、ターゲットの登録、古いタスクの接続のドレイン、古いタスクの停止の順にイベントが記録され、最後にサービスが定常状態に達したことが分かります。イベントのメッセージは英語で、ドレインは has begun draining connections on 1 tasks のように表示されます。


手順 6: アクセスが途切れなかったことを確かめる
CloudShell のタブに戻ります。soa-web v1 の行の後に v1 と v2 が混ざる時間があり、やがて soa-web v2 だけになります。その間、ステータスコードはすべて 200 で、タイムアウトや 502 / 503 の行はありません。


Ctrl + C でコマンドを止めます。



v1 と v2 が混ざる時間があるのが、ローリング更新の特徴でござる。新旧を混ぜたくない、本番の前に v2 だけを試したいなら、そこでブルー/グリーンやカナリアの出番になるのでござるな。
まとめ
| デプロイ方式 | トラフィックの移し方 | 追加で要るもの | 向いている場面 |
|---|---|---|---|
| ローリング更新 | タスクを少しずつ入れ替える。新旧が混ざる時間がある | なし(ターゲットグループ 1 つ) | 無停止で、もっとも低コストに更新したい |
| ブルー/グリーン | 検証してから一度に切り替える | ターゲットグループ 2 つ・リスナールール・IAM ロール | 本番前の検証とすばやいロールバック |
| リニア | 同じ割合ずつ段階的に移す | 同上 | 段階ごとに様子を見ながら移したい |
| カナリア | 一部だけ移して様子を見てから、残りを一度に移す | 同上 | 一部の利用者で先に試したい |
- ローリング更新の入れ替えの速さと安全さは、最小実行タスク %(下限)と最大実行タスク %(上限)で決まる
- 最小 100%・最大 200% なら、新しいタスクがヘルスチェックに合格してから古いタスクが外れるので、アクセスが止まらない
- 最小 0% は古いタスクを先に止められるが、入れ替えの間はサービスが止まる
- デプロイサーキットブレーカーや CloudWatch アラームで、失敗したデプロイをロールバックできる
- ブルー/グリーン・リニア・カナリアは ECS の機能として使え、デプロイ中はブルーとグリーンが両方動くためリソースが最大で 2 倍になる



「止めずに」と「安く」が並んだらローリング更新、「本番前に検証」ならブルー/グリーン、「少しずつ」ならリニアかカナリアでござる。要件の言葉と、追加で要るものの重さを結びつけて覚えるでござるよ。
参照先
- タスクを置き換えて Amazon ECS サービスをデプロイする – Amazon Elastic Container Service
- Amazon ECS デプロイサーキットブレーカーが障害を検出する方法 – Amazon Elastic Container Service
- Amazon ECS ブルー/グリーンデプロイ – Amazon Elastic Container Service
- Amazon ECS リニアデプロイ – Amazon Elastic Container Service
- Amazon ECS カナリアデプロイ – Amazon Elastic Container Service
- ブルー/グリーンデプロイ、リニアデプロイおよびカナリアデプロイ用の Application Load Balancer リソース – Amazon Elastic Container Service
- Amazon ECS 用の CodeDeploy ブルー/グリーンデプロイ – Amazon Elastic Container Service
- Amazon ECS サービスを更新する – Amazon Elastic Container Service















