AWS Fargate + CodeDeployを使ったBlue/Green デプロイメント試してみた

こちらの手順にしたがって既存のサービスで試した結果、ハマッたことなどメモ。

この機能がやってくれること

  • サービスの更新をトリガーに、CodeDeploy発動
  • 既存タスクを稼動させつつ、新タスクを別ポート(8080)で立ち上げ
  • ヘルスチェックに合格すると、トラフィックを自動で新タスクのほうへ移してくれる
    • 80ポートに紐付くターゲットグループを変えている
    • ヘルスチェックに失敗すると、ターゲットグループの向き先を元に戻してロールバックする
  • 1時間くらい経って問題なければ旧タスクを亡くして、新タスクのみ稼動

のように見える

ハマッたこと

  • 自環境だと手順にあるのロールでは権限が足らなかった
  • ターゲットグループのヘルスチェックのパスが変えられなかった
    • サービス作成後に手動で変えられた
    • 作成ウィザードで作るとそうなるので、Terraformで事前作成しておくとよさそう。
  • CodeDeployのInstall(ライフサイクルイベント)で1時間経っても終わらず強制終了させられた
    • デプロイに時間がかかっていて、殺戮と再生が無限ループされていたので、ヘルスチェックの猶予期間を長めに設定した

ざっくりセットアップの流れ

まずはロールの作成

ロール作成画面から

赤枠を選択して次へ。
AWSCodeDeployRoleをアタッチして、ロールを作成します。
手順に従ってロール名は ecsCodeDeployRole
その後以下のポリシーを作成しアタッチします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iam:PassRole",
                "ecs:DescribeServices",
                "ecs:CreateService",
                "ecs:UpdateService",
                "ecs:DeleteService",
                "ecs:CreateTaskSet",
                "ecs:UpdateServicePrimaryTaskSet",
                "ecs:DeleteTaskSet",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:ModifyRule",
                "lambda:InvokeFunction",
                "cloudwatch:DescribeAlarms",
                "sns:Publish",
                "s3:GetObject",
                "s3:GetObjectMetadata",
                "s3:GetObjectVersion"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

次の権限はCodeDeploy実行時に権限エラーになったため追記している。

           "iam:PassRole",
            "ecs:DescribeServices",
            "ecs:CreateService",
            "ecs:UpdateService",

このロールはサービス作成時に設定します。

ロードバランサー

既存のALBは80ポートを受付ていた。
Blue/Greenではテスト用に8080ポートを用意する。

用意したもの

  1. ALBのリスナーに8080ポートを追加
  2. テスト用ターゲットグループ(ポート80)を追加し、ヘルスチェックのパスを適当なものに設定した

Before:

ALB-TEST(port:80)----> TG-01(port:80, ヘルスチェック: /index.php)

After:

ALB-TEST(port:80)----> TG-01(port:80, ヘルスチェック: /index.php)
ALB-TEST(port:8080)----> TG-02(port:80, ヘルスチェック: /index.php)

サービスの作成

ステップ1: サービスの設定

ECSのマネジメントコンソールからサービスの作成。
基本的には既存のサービスの内容で設定していく。
Fargateタイプを選択肢、DeploymentsにBlue/greenを選ぶ。
ロールは事前に作成した ecsCodeDeployRole

ステップ2: ネットワークの設定

ロードバランサーを選択すると、ヘルスチェックの猶予期間を設定できるようになるので設定。大事。

負荷分散用のコンテナで「Test listener」にチェックを入れ、80と8080ポートを設定しておきます。

ターゲットグループは事前に用意したものを設定すると、ヘルスチェックのパスを変更しなくて済むので手間が減ります。
最後に「サービスの検出の統合の有効化」チェックをはずして次へ

ステップ3: Auto Scaling(オプション)

「サービスの必要数を直接調整しない」を選択して次へ

ステップ4: サービスの確認

間違いなければ作成します。
サービス作成後、CodeDeployも作成されていると思います。


Blue/greenを試す

上記の手順でサービスが立ち上がったら、
タスク定義を更新して新しいリビジョン作ります。
 →公式の手順ではタグの追加をしているので同じように設定します。

サービスの更新画面から、タスク定義のリビジョンを変更するとCodeDeployが動きだします。

CodeDeployが動き出したのがわかります。

この状態ではまだタスクが2つ立ち上がっています。リビジョン13と14です。

デプロイからヘルスチェックまで成功すると、トラフィックが変わります。
デプロイのステータス欄にある、「ステップ4: Wait」で1時間くらい監視し、問題なければ完全に切り替えます。

新しいリビジョンのタスクのみ残っていることが確認できます。

イメージ

おしまい

Terraformで上記設定までできればより素晴らしいですね。

12/20 追記)
Terraformで設定できるようになってました

サーバサイドエンジニア。オムライスが好物

シェアする

  • このエントリーをはてなブックマークに追加

フォローする