NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

改めてECSのデプロイ方法を整理する

こんにちは。梅原です。

今日はECSのデプロイタイプについて改めて整理します。
ECSのデプロイ方法は3つあります。

  • ローリングアップデート
  • Blue/Greenデプロイ
  • 外部デプロイ

の3つです。
この記事ではローリングアップデートとB/Gデプロイについて流れをおさらいします。
ECSの前段にALBを置いた構成を例にします。

ローリングアップデート

ローリングアップデートとは、稼働中のECSタスクをそのまま新しいタスクに置き換える方法です。一番オーソドックスなデプロイ方法なのではないでしょうか。
ECSのみでデプロイすることができ、設定箇所も主に後述する2つだけなので手軽にできます。ですがデプロイ中は新旧のタスクが混ざる状態となるため、アプリケーション上で意図しない動作が起こる可能性があるので注意が必要です。 どのくらいの割合で新しいタスクに置き換えていくかもminimumHealthyPercentmaximumPercentを設定することで制御できます。

  • minimumHealthyPercent

    デプロイ中に最低限維持されるタスクの数を割合で設定します。最低限のタスクを設定しておくことで、サービスは稼働したままデプロイすることができます。
    例えばタスク3つで稼働中のECSサービスにデプロイするときに
    minimumHealthyPercentに100%を設定すると、正常なタスク数は「3つ」維持されます。
    minimumHealthyPercentに33%を設定すると、正常なタスク数は33%の切り上げされた「1つ」は維持され、残り2つはdrainingになった後に新しいタスクがデプロイされます。

  • maximumPercent

    デプロイ中の旧タスクと新タスクの合計値の最大を割合で設定します。
    例えばタスク3つで稼働中のECSサービスにデプロイするときに
    maximumPercentに200%を設定すると、デプロイ中に最大で200%の「6つ」のタスクをデプロイすることができます。 maximumPercentに166%を設定すると、デプロイ中に最大で166%の切り捨てされた「4つ」をデプロイできます。

つまりminimumHealthyPercentに100%、maximumPercentに166%を設定すると、稼働中のタスクとデプロイ中のタスク数は最低でも3台維持、最大でも4台となるので、1台ずつ段階的なデプロイすることができます。 ここの設定値は、デプロイにかかる時間やコストなどの制約に関わってくるので、満たすべき要件に応じて調整が必要です。

ローリングアップデートの流れを見る

  1. デプロイ前
    まず旧コンテナが3つある状態でデプロイしていきます。

  2. デプロイ開始
    旧コンテナが存在するターゲットグループに新コンテナがデプロイされ、コンテナがRunning状態になり、ターゲットグループのヘルスチェックが問題ないとトラフィックが新コンテナにも流れていきます。

  3. 旧コンテナの削除
    新コンテナがRunningになりヘルスチェックが通った後に旧コンテナが削除されます。

またデプロイ中の不具合検知は、デプロイサーキットブレーカーとCloudWatch Alarmを利用することができます。デプロイサーキットブレーカーは自動でのロールバックも実施してくれます。
デプロイサーキットブレーカーの不具合検知の条件は、「タスクがRunningになるか」と、「ELBやCloudMap、ECSコンテナのヘルスチェックが通るか」の2つです。詳細は以下リンクを参照してください。

B/Gデプロイ

B/GデプロイはECSタスクの入れ替えは実施せず、稼働中のタスクとは別にGreen環境(新タスク)を別のターゲットグループにデプロイし、任意のタイミングで、稼働中のBlue環境(旧タスク)からGreen環境へ、リスナールールの変更という形で切り替えが実施されます。
またロードバランサーのリスナールールとターゲットグループを2つ用意しているので、ユーザが利用しているBlue環境への影響は発生しません。また、Green環境にトラフィックを切り替える前に、任意のポートでGreen環境のみでのテストを実施することができます。テスト用のリスナールールはオプションなのでなしでも可能です。

B/GデプロイはCodeDeployと統合されているので、ECSサービスをコンソールから作成したときCodeDeployアプリケーションとデプロイグループが作成されます。
B/Gデプロイに関しても、どのくらいの割合で更新していくかをCodeDeployのデプロイ設定で指定することができます。ECSAllAtOnceECSCanaryXPercentYMinutesECSLinearXPercentEveryYMinutesから選択できます。XとYの値は自分で設定することもできます。

  • ECSAllAtOnce
    1回ですべてのトラフィックを入れ替えを実施
  • ECSCanaryXPercentYMinutes
    Green環境がデプロイされた後、Y分間は 全体トラフィックのX%をGreen環境に流すことができます。Y分後、すべてのトラフィックがGreen環境に流されます。
  • ECSLinearXPercentEveryYMinutes
    Green環境がデプロイされた後、Y分間ごとにトラフィックのX%をGreen環境に段階的に移していきます。

B/Gデプロイの流れを見る

ECSAllAtOnceの流れを見ていきます。

  1. デプロイ前
    デプロイ前は2つのリスナールールともに稼働中のタスクが存在するターゲットグループを向いています。この環境にデプロイしていきます。

  2. デプロイ開始
    デプロイが開始されると、Green環境に新しいタスクがデプロイされます。デプロイ先は稼働中のターゲットグループとは別のターゲットグループにデプロイされ、テスト用のリスナールールの向き先がGreen環境に変更されます。
    またECSAllAtOnceではなくCanaryやLinearでのデプロイのときは、リスナールールの重み付けの設定でX%のトラフィックをGreenターゲットグループに流すことでトラフィックの制御を行っています。

  3. トラフィックの再ルーティング
    任意の時間経過後もしくはコンソールでの操作で次のフェーズに移ることができます。ここでは本番用のリスナールールをGreen環境に向けます。この間はBlue環境のECSタスクが残っているので、旧環境へのロールバックもコンソールから1ポチで実施できます。

  4. Blue環境削除
    最後にBlue環境の削除です。こちらも任意の時間経過後もしくはコンソールでの操作でできます。

最後に2つのデプロイ方法の比較をまとます。

ローリングアップデートとB/Gデプロイの比較

観点 ローリングアップデート B/Gデプロイ
コスト面 追加コストは最小限 タスク数は2倍、デプロイ時間も影響し高い
複雑性 ECSと統合されてるので容易 CodeDeployを使用するので少し複雑
ロールバックの容易性 サーキットブレーカーの使用もしくは新規でECSタスクを実行する 旧環境が残っている間は即座に可能
デプロイ中の影響 デプロイ中に新旧環境が混在する ターゲットグループで分離しているのでユーザ影響なし

最後に

これを書くまでは「B/Gデプロイでいいやん。」と思っていましたが、検証を通してローリングアップデートの手軽さや容易さはすごく感じました。B/Gデプロイもコストが掛かったりAutoScalingの動作などの考慮事項もありますが、ロールバックの簡単さや影響度の少なさは魅力的です。 また、B/Gデプロイはターゲットグループを分けていることで、ユーザへの影響がなく、事前のテストも可能という点も大きなメリットになると思います。 ローリングアップデートとB/Gデプロイは一長一短で絶対にこっちではないとダメというのはないと思います。要件に合わせてメリット・デメリットを比較しながら選択する必要があると感じました。

最後に余談ですが、ECSの旧コンソールは2023年12月4日を過ぎると使用できなくなるようです。なので年内には新コンソール上でもB/Gデプロイを選択できるようになるかもしれないですね。 GitHub上に公開されているECSのロードマップを見ていても、IssueがあるのでコンソールからCodeDeployが選択できるようになるまで気長に待とうと思います。

執筆者: 梅原 航 インフラエンジニア。 主にAWSを使ってます。