ECS が VPC Lattice 経由で公開されているサービスの blue/green デプロイに対応したので試してみた

ECS が VPC Lattice 経由で公開されているサービスの blue/green デプロイに対応したので試してみた

Amazon ECS の VPC Lattice 対応がアップデートされ、ALB を省いた構成でも blue/green デプロイが可能になりました。その動作を確認しました。
2026.10.04

はじめに

2026年10月2日の告知で、Amazon ECS の VPC Lattice 対応に、組み込みの blue/green、linear、canary が加わりました。新規・既存どちらの ECS サービスでも有効にできます。

https://aws.amazon.com/jp/about-aws/whats-new/2026/10/amazon-ecs-vpc-lattice-blue-green-deployments/

ECS サービスに Lattice のターゲットグループを設定するだけでよく、ALB を別に作る必要はありません。一方、CodeDeploy(CODE_DEPLOY デプロイコントローラー)による blue/green は、Lattice では未対応です。ドキュメントには、linear と canary も blue/green と同じ Lattice のリソースで動くと書かれています。

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-vpc-lattice.html

この記事では、ALB を置かずに Nginx の Fargate サービスを作り、v1 から v2 へ blue/green デプロイしました。デプロイ中に ECS が Lattice のルールの重みをどう書き換え、クライアントの応答がどう変わるかを時系列で確認します。

Lattice と ECS の構成

Lattice 側に用意するもの

Lattice 側には次を用意しました。作成コマンドは、公式ドキュメントにある同じ構成の例を使いました。

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/vpc-lattice-resources-for-blue-green.html

  • ターゲットグループ2つ(IP タイプ、HTTP:80。どちらも ACTIVE にしておく)
  • Lattice サービスとリスナー(既定アクションは固定の 404)
  • 本番ルール(パス / のプレフィックス一致)
  • テストルール(ヘッダー X-Environment: test、優先度 10)

ルールのアクションは forward のみで、fixedResponse のルールは ECS が拒否します。どちらのルールにも2つのターゲットグループを含め、現在のトラフィックを受ける側を重み 100、もう一方を 0 にします。テストルールは本番ルールとは別のリクエストにマッチさせ、先に評価されるよう優先度の数字を小さくします。

デプロイ中は ECS がルールの forward を書き換えます。外部から変更するとデプロイが失敗するため、ECS に任せます。2つのターゲットグループはデプロイごとに役割が入れ替わります。最初の段階的デプロイでは、本番ルールが重み 100 で転送している側(今回は targetGroupArn に指定した側)ではなく、もう一方へトラフィックを移します。以降、targetGroupArn に指定した側を TG-A、代替側を TG-B と呼びます。

タスクのセキュリティグループで受信を許可したのは、Lattice のマネージドプレフィックスリストからのポート80だけです。プレフィックスリスト名は com.amazonaws.<region>.vpc-lattice で、<region> は利用するリージョン名に置き換えます。

ECS 側の設定

ECS 側では、vpcLatticeConfigurations に advancedConfiguration を追加します。roleArn には、ECS が VPC Lattice のリソースを管理するためのインフラストラクチャロールの ARN を指定します。alternateTargetGroupArn には2つ目のターゲットグループを、productionListenerRule と testListenerRule には本番・テストのルールを指定します。deploymentConfiguration の strategy は BLUE_GREEN にします。

rolling で動いているサービスの切り替え方は、公式ドキュメントに書かれています。advancedConfiguration は、strategy を変更する更新と同時か、それ以前の更新で追加しておきます。今回は新規にサービスを作る create-service で確かめました。

次の JSON を svc.json として保存し、aws ecs create-service --cli-input-json file://svc.json に渡しました。ID は例示値に置き換えています。

{
  "cluster": "lattice-bg",
  "serviceName": "lattice-bg-web",
  "taskDefinition": "lattice-bg-nginx:1",
  "desiredCount": 2,
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "subnets": [
        "subnet-0123456789abcdef0",
        "subnet-0fedcba9876543210"
      ],
      "securityGroups": [
        "sg-0123456789abcdef0"
      ],
      "assignPublicIp": "ENABLED"
    }
  },
  "vpcLatticeConfigurations": [
    {
      "roleArn": "arn:aws:iam::123456789012:role/lattice-bg-ecs-infra",
      "targetGroupArn": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:targetgroup/tg-0123456789abcdef0",
      "portName": "web",
      "advancedConfiguration": {
        "alternateTargetGroupArn": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:targetgroup/tg-0fedcba9876543210",
        "productionListenerRule": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:service/svc-0123456789abcdef0/listener/listener-0123456789abcdef0/rule/rule-0123456789abcdef0",
        "testListenerRule": "arn:aws:vpc-lattice:ap-northeast-1:123456789012:service/svc-0123456789abcdef0/listener/listener-0123456789abcdef0/rule/rule-0fedcba9876543210"
      }
    }
  ],
  "deploymentController": {
    "type": "ECS"
  },
  "deploymentConfiguration": {
    "strategy": "BLUE_GREEN",
    "maximumPercent": 200,
    "minimumHealthyPercent": 100,
    "bakeTimeInMinutes": 2
  }
}

タスク定義とクライアント

タスク定義には Nginx 公式イメージを使いました。コンテナは起動時に、ECS のタスクメタデータ(ECS_CONTAINER_METADATA_URI_V4/task)からタスク ARN、リビジョン、アベイラビリティゾーンを取得します。それを index.html に書き出し、その後 Nginx を起動します。v1 は nginx:1.27 と APP_VERSION=v1、v2 は nginx:1.28 と APP_VERSION=v2 で、それ以外は同じです。v2 の全文を td2.json として保存し、aws ecs register-task-definition --cli-input-json file://td2.json で登録しました。

タスク定義 v2(td2.json)
{
  "family": "lattice-bg-nginx",
  "networkMode": "awsvpc",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/lattice-bg-task-exec",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "public.ecr.aws/docker/library/nginx:1.28",
      "essential": true,
      "entryPoint": [
        "/bin/sh",
        "-c"
      ],
      "command": [
        "M=$(curl -s \"$ECS_CONTAINER_METADATA_URI_V4/task\")\ng(){ echo \"$M\" | sed -n \"s/.*\\\"$1\\\":\\\"\\([^\\\"]*\\)\\\".*/\\1/p\" | head -1; }\nprintf 'app_version=%s\\ntask_arn=%s\\ntaskdef_revision=%s\\navailability_zone=%s\\ncontainer_ip=%s\\nnginx=%s\\n' \"$APP_VERSION\" \"$(g TaskARN)\" \"$(g Revision)\" \"$(g AvailabilityZone)\" \"$(hostname -i)\" \"$(nginx -v 2>&1)\" > /usr/share/nginx/html/index.html\nexec nginx -g 'daemon off;'\n"
      ],
      "portMappings": [
        {
          "name": "web",
          "containerPort": 80,
          "protocol": "tcp",
          "appProtocol": "http"
        }
      ],
      "environment": [
        {
          "name": "APP_VERSION",
          "value": "v2"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/lattice-bg",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "web"
        }
      }
    }
  ]
}

Lattice のサービスは、サービスネットワークまたは VPC 関連付けを通してクライアントから呼び出します。今回のクライアントは、サービスネットワークを関連付けた VPC(タスクと同じ VPC)に置いた Lambda です。ヘッダーなしの本番経路と X-Environment: test を付けたテスト経路の2本に、約13秒間隔でリクエストを送りました。

環境は ap-northeast-1 で、Fargate 0.25 vCPU / 0.5 GB の2タスク、ターゲットグループのヘルスチェック間隔は10秒です。

初回のサービス作成

デプロイの完了は、describe-service-deployments の status が SUCCESSFUL になったことで判断しました。以下の時刻は、いずれも記録した時点の時刻です。

新規に作ったサービスでも、最初のデプロイは blue/green として動きました。サービスは 00:41:31 に作成しました。タスク2つは、targetGroupArn に指定した TG-A ではなく代替の TG-B に登録され、HEALTHY になりました。2つとも HEALTHY になったのは 00:42:45 で、TG-A は最初に記録した 00:42:05 の時点から空でした。

ECS サービスの rolloutState(describe-services)は、00:43:25 の時点で COMPLETED でした。その時点でも、本番ルールの重みは作成時のまま TG-A 100 / TG-B 0 でした。最初にステージを観測した 00:45:49 の時点では POST_SCALE_UP でした(それより前のステージ遷移の記録はありません)。その後、TEST_TRAFFIC_SHIFT(00:46:39)、PRODUCTION_TRAFFIC_SHIFT(00:48:18)を観測しました。本番ルールが TG-A 0 / TG-B 100 に変わったのは 00:48:20 で、サービスデプロイが SUCCESSFUL になったのは 00:49:55 でした。

v1 から v2 へのデプロイ

update-service で v2 のタスク定義を渡しました。bakeTimeInMinutes は 2 のままです。v1 のタスクは TG-B に登録されており、v2 のタスクは TG-A に登録されました。

次の表の時刻は 2026-10-04 の JST です。ECS のステージの時刻は、describe-service-deployments を4秒間隔で取得し、各ステージを最初に観測した時刻です。ルールの重みとクライアントの応答は、Lambda のリクエストと同時に約13秒間隔で記録したものです。

時刻 ECS のステージ Lattice とクライアントで観測したこと
01:12:39 (update-service を実行) 本番・テストとも v1 が応答
01:12:53 SCALE_UP v2 のタスクが TG-A に登録される(1件目は 01:13:19、2件とも HEALTHY になったのは 01:13:59)
01:14:07 POST_SCALE_UP 本番・テストとも v1 が応答
01:17:16 TEST_TRAFFIC_SHIFT テストルールが TG-A 100 / TG-B 0 に変わる(01:17:19)。テスト経路の最初の v2 応答は 01:17:22。本番経路は v1 のまま
01:18:51 POST_TEST_TRAFFIC_SHIFT テスト経路は v2、本番経路は v1
01:18:56 PRODUCTION_TRAFFIC_SHIFT 本番ルールが TG-A 100 / TG-B 0 に変わる(01:19:05)。本番経路の最初の v2 応答は 01:19:08
01:20:31 BAKE_TIME 本番・テストとも v2 が応答
01:22:33 CLEAN_UP 本番・テストとも v2 が応答
01:22:38 SUCCESSFUL TG-B は 01:23:33 の時点で DRAINING、01:23:46 の時点で空

テスト経路で初めて v2 の応答が返った 01:17:22 から、本番経路で初めて v2 の応答が返った 01:19:08 まで、1分46秒ありました。

update-service の実行(01:12:39)からサービスデプロイの完了(API が返した完了時刻 01:22:37)までは9分58秒でした。PRIMARY の rolloutState が COMPLETED と記録されたのは、SUCCESSFUL を観測した 01:22:38 より後の 01:24:26 です。

ステージ間の待ち時間は、POST_SCALE_UP から TEST_TRAFFIC_SHIFT までが3分9秒、TEST_TRAFFIC_SHIFT から POST_TEST_TRAFFIC_SHIFT までと PRODUCTION_TRAFFIC_SHIFT から BAKE_TIME までがどちらも1分35秒、BAKE_TIME から CLEAN_UP までが2分2秒でした。これらは、公式ドキュメントに書かれた POST_SCALE_UP 後の約3分、各重み変更後の約90秒、設定した bakeTimeInMinutes の2分に対応します。

応答本文の抜粋を v1 と v2 で1件ずつ示します(アカウントID、タスクID、コンテナの IP アドレスは置換しています)。

app_version=v1
task_arn=arn:aws:ecs:ap-northeast-1:<account-id>:task/lattice-bg/<task-id>
taskdef_revision=1
availability_zone=ap-northeast-1a
container_ip=<container-ip>
nginx=nginx version: nginx/1.27.5
app_version=v2
task_arn=arn:aws:ecs:ap-northeast-1:<account-id>:task/lattice-bg/<task-id>
taskdef_revision=2
availability_zone=ap-northeast-1c
container_ip=<container-ip>
nginx=nginx version: nginx/1.28.3

約13秒間隔で本番とテストに各56回(計112回)送ったリクエストは、すべて HTTP 200 で、エラー応答や接続エラーはありませんでした。本番経路の応答に含まれていたタスク ARN は、v1 が2つ、v2 が2つでした。

まとめ

2025年7月にリリースされた ECS の組み込み blue/green デプロイが、今回のアップデートで Lattice 連携にも対応しました。

https://aws.amazon.com/jp/blogs/news/accelerate-safe-software-releases-with-new-built-in-blue-green-deployments-in-amazon-ecs/

ECS の組み込みデプロイは、モニタリングの強化など改善が進み、利用しやすくなっています。

https://dev.classmethod.jp/articles/ecs-console-deployment-tab-canary-linear-blue-green/

Lattice を使う ECS サービスで、blue/green のためだけに ALB を併用していた方は、今回のアップデートをぜひお試しください。

この記事をシェアする

関連記事