LoginSignup
9
4

More than 1 year has passed since last update.

ECS Blue/GreenデプロイCI/CDパイプライン構築

Last updated at Posted at 2023-04-11

内容

ECS FargateのBlue/Greenデプロイに関して
AWS Codeサービス(CodeCommit・CodeBuild・CodeDeploy・CodePipeline)によるCI/CDパイプライン構築を行ったのでそのアウトプットとしてまとめていきたいと思います。

CodeサービスやECSについての基礎についてもまとめてみたので、合わせてご確認下さい。
AWS Codeサービスを利用したCI/CDパイプラインの仕組み
AmazonECSの構成まとめ

事前に作成済の想定

  • VPC・サブネット・RDSなどの基本的なネットワークは作成済
  • ECSクラスター・タスク・タスク定義を作成済
  • Dockerfile, docker-compose.ymlなどのファイルは作成済
  • ACMで発行したSSL証明書をALB関連付け済

目次

パイプラインの構成

今回は以下のようなパイプラインの構成で進めて行きたいと思います。

image.png

Blue/Greenデプロイとは

古い環境(Blue環境)と新しい環境(Green環境)の両方の環境を用意し、サービスのアップデート時にはGreen環境に変更を反映し、動作確認後ロードバランサー等によるルーティングの制御によってトラフィックを切り替え、ダウンタイムなしで環境を切り替えるデプロイ方式。

  • Blue環境に既存のアプリケーションが存在し、ロードバランサーがBlueにトラフィックを流している環境に対して、CodeDeployを用いてGreen環境に新しくデプロイを行う。
    テストリスナーポートへのアクセスにより、動作確認が可能。
    スクリーンショット 2023-04-11 10.18.55.png

  • Green環境へデプロイ完了後、CodeDeployがロードバランサーを操作してトラフィックがBlue環境を向くように変更
    スクリーンショット 2023-04-11 10.21.57.png

  • ルーティングの変更後、Blue環境はロールバックのために一定期間存在し、一定期間経過後削除される
    スクリーンショット 2023-04-11 10.25.16.png

■ ビルド定義・デプロイ定義・タスク定義ファイルの作成

以下の3つのファイルを作成する

  • ビルド定義ファイル(buildspec.yml)
  • デプロイ定義ファイル(appspec.yml)
  • タスク定義ファイル(taskdef.json)

ビルド定義ファイル(buildspec.yml)の作成

詳細の書き方は公式ドキュメントなどをご参照ください。

基本的な処理

  • ECRへログイン
  • Dockerイメージをビルド
  • ECRにイメージをプッシュ

を行います。

imageDetail.jsonの作成

Blue/GreenデプロイのCI/CDパイプラインにおいて、ビルド定義ファイルで重要なのが
imageDetail.jsonファイルの作成と出力です。

imageDetail.jsonに関しての公式リファレンスにあるように、以下のJSONを作成します。

{
    "ImageURI": "ACCOUNTID.dkr.ecr.us-west-2.amazonaws.com/dk-image-repo@sha256:example3"
}

出力アーティファクトの設定

buildspec.ymlでは、artifactsの項目に出力するアーティファクトを設定します。
ここでは、appspec.ymltaskdef.jsonimageDetail.jsonの出力を設定します。

artifacts:
  files:
    - appspec.yml
    - taskdef.json
    - imageDetail.json

デプロイ定義ファイル(appspec.yml)の作成

プロジェクトのルート直下にappspec.ymlを作成します。
ディレクトリを変更(codedeploy/ディレクトリ配下に配置)したかったのですが、うまくいかずルート直下に配置しています。
何かやり方あれば是非コメント下さい!

appspec.ymlの内容は、細かく設定するのであればリファレンスを参照いただければと思います。
基本的には下記の内容となります。

version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "<TASK_DEFINITION>"
        LoadBalancerInfo:
          ContainerName: "[通信を受け付けるコンテナ名]"
          ContainerPort: "80"

デプロイの際にタスク定義を参照するのですが、参照するタスク定義は最新のものである必要があります。
(理由:タスク定義にはECRの最新のイメージURI、つまり最新のソースコードが反映されたDockerイメージが設定される。したがって、更新されたECRリポジトリURIを設定したタスク定義を使用する必要がある。)

TaskDefinition: "<TASK_DEFINITION>"の記述によって、後述するタスク定義ファイル(taskdef.json)が動的に使われるようになります。

タスク定義ファイル(taskdef.json)の作成

タスク定義ファイルは、既に手動で作成したタスク定義から作成します。

  • ECS > 対象のクラスター > 「タスク」タブ > 「タスク定義」のリンク > 「JSON」タブ > 「JSONのダウンロード」
    ※注意)この作業は、必ず「新しいECSエクスペリエンス」をオンにして、新デザインのAWSコンソールから作業してください。古いコンソール画面ではJSON形式が全く異なり、私はここでハマりました。
  • ダウンロードしたJSONファイルを、taskdef.jsonという名前でプロジェクトのルート直下に配置
  • imageの項目を下記のように修正する
"image": "<IMAGE_NAME>"

タスク定義に最新のECRリポジトリのDockerイメージURIを記述する必要がありますが、ここでは動的に設定するためにプレイスホルダーを使います。

このプレースホルダーの文字列は、CodePipelineのデプロイステージで設定します(CodePipeline作成のデプロイステージで後述)。

このプレースホルダーに何が入ってくるかというと、上述したbuildspec.ymlの出力アーティファクトとして設定した

{
    "ImageURI": "ACCOUNTID.dkr.ecr.us-west-2.amazonaws.com/dk-image-repo@sha256:example3"
}

この値が入ってくるということになります。

  • tagsの項目の1行を削除
    
    
    "tags": [] # この1行を削除
}

3ファイル作成完了

以上が3つの定義ファイルの作成となります。
最新のECRリポジトリURIを参照するための流れがわかりづらくなるので、以下にもう一度まとめます。

  • appspec.ymlで、最新のタスク定義を参照する記述を行う
  • この最新のタスク定義はtaskdef.jsonが使われ、その中に書かれているECRリポジトリのURIはプレースホルダーで動的に最新のものが参照されるようになっている。
  • taskdef.jsonのプレースホルダーには、buildspec.ymlで出力したimageDetail.jsonの値が入ってくる。

この流れを掴むのが最も大事です。
ここは時間をかけて理解することをおすすめします。

■ ALBの作成

インターネットからのアクセスをトラフィックするロードバランサー(ALB)を作成

  • EC2 > ロードバランサー > 新規作成 > ALB

ロードバランサーの設定

項目 備考
名前 sample-blue-green-alb
スキーム インターネット向け
リスナー 80を追加 ECSサービスで作成するので、後ほど削除
AZ, サブネット public-1a,public-1c 自身の環境に合わせてください

セキュリティ設定の構成

項目
ここでは何も設定せずに次の手順へ

セキュリティグループの設定

項目 備考
既存 sample-alb-sg 8080, 4403ポート許可を追加

ルーティングの設定

項目 備考
ターゲットグループ sample-blue-green-dummy-tg ECSサービスで作成するので、後ほど削除

ターゲットの登録

項目
ここでは何も設定せずに次の手順へ
  • すべて入力できたら確認して「作成」

リスナーとターゲットグループの削除

下記は後ほどECSサービス作成時に作成されるので、ここでは一度削除する

  • ロードバランサー > 先ほど作成したALB(sample-blue-green-alb)> リスナータブ > 作成したリスナーを削除
  • ターゲットグループ > 先程作成したターゲットグループ(sample-blue-green-dummy-tg)を削除

■ Blue/Greenデプロイ用のECSサービス作成

事前作業)CodeDeploy用のIAMロール作成

CodeDeployがECSにデプロイするために、ECSとS3へのアクセス権限を付与する必要がある

  • IAM > ロール > ロールを作成
項目 備考
信頼されたエンティティタイプ AWSのサービス
ユースケース CodeDeploy > CodeDeploy-ECS
許可ポリシー AWSCodeDeployRoleForECS S3への権限も含まれる。
ロール名 CodeDeployRoleForECSBlueGreen

サービスの設定

  • ECS > クラスター > sample-cluster > サービスタブ > 「作成」ボタン
項目
起動タイプ FARGATE
オペレーティングシステム Linux
タスク定義 sample-task-definition
リビジョン latest
クラスター sample-cluster
サービス名 sample-blue-green-service
タスクの数 1

デプロイメント

項目
デプロイメントタイプ Blue/Greenデプロイメント
デプロイメント設定 CodeDeployDefault.ECSAllAtOnce
CodeDeployのサービスロール CodeDeployRoleForECSBlueGreen(上述のとおり事前にIAMロールを作成)

VPCとセキュリティグループ

項目
クラスターVPC sample-vpc
サブネット sample-subnet-1a, 1c
セキュリティグループ sample-web-sg HTTP:80(プロダクション), 8080(テスト) を許可
パブリックIP ENABLED DISABLEDでも良さそうな気はする

ロードバランシング

項目
種類 ALB
ロードバランサー名 sample-blue-green-alb(上記で作成したALB)
ロードバランス用のコンテナ web-container:80:80

ロードバランス用のコンテナ

項目
プロダクションリスナーポート HTTP: 80
テストリスナーポート HTTP: 8080
ターゲットグループ1 HTTP sample-blue-green-tg-1
ターゲットグループ2 HTTP sample-blue-green-tg-2
ヘルスチェックパス / (1も2も。自身の環境で適宜変更)

Auto Scaling

項目 備考
Service Auto Scaling しない 適宜設定

作成

  • サービス作成すると以下が自動作成される
    • ALBのリスナー(80と8080で作成しておいて、ALBのリスナ設定画面で443と4403に変更するようにする)
    • TG
    • CodeDeployのアプリケーション、デプロイグループ

以下のエラーで詰まったので、注意

  • sample-web-sgにテスト用ポートのインバウンドルールが設定されていなかった
  • ALB作成後の手順のリスナとターゲットグループの削除を行っていなかった

ALBのリスナの設定

  • 自動作成された HTTP:80 ⇒ tg1, HTTP:8080 ⇒ tg2 を削除
  • リスナの追加で HTTP:80 ⇒ HTTPS:443へリダイレクト, HTTP:8080 ⇒ HTTPS:4403へリダイレクト , HTTPS:443 ⇒ tg1, HTTPS:4403 ⇒ tg2 を追加する

■ CodePipeline作成

  • CodePipeline > パイプラインを作成する

パイプラインの設定を選択

  • パイプライン名:SampleBlueGreenPipeline
  • その他はデフォルトのまま
項目
パイプライン名 SampleBlueGreenPipeline
サービスロール 新しいサービスロール
ロール名 自動作成
その他 デフォルトのまま

ソースステージを追加

項目
ソースプロバイダー AWS CodeCommit
リポジトリ名 sample
ブランチ名 main
検出オプション CloudWatch Events
出力アーティファクト形式 CodePipelineのデフォルト

ビルドステージを追加

※ 事前にビルドプロジェクトを作成しておいてください。本記事では割愛。

項目
プロバイダー AWS CodeBuild
リージョン アジアパシフィック (東京)
プロジェクト名 sample-build-project
ビルドタイプ 単一ビルド

デプロイステージを追加

項目
プロバイダー Amazon ECS(ブルー/グリーン)
リージョン アジアパシフィック (東京)
CodeDeploy アプリケーション名 ECS サービスを作成すると自動作成されるアプリケーションを選択
CodeDeploy デプロイグループ ECS サービスを作成すると自動作成されるアプリケーションを選択
ECS タスク定義 BuildArtifact
CodeDeploy AppSpec ファイル BuildArtifact
入力アーティファクトを持つイメージの詳細 BuildArtifact
タスク定義のプレースホルダー文字 IMAGE_NAME
  • ここまで作成できれば完了

■ CodePipeline作成後にやること

CodeDeploy デプロイグループの編集

Blue環境からGreen環境にトラフィックを切り替えるタイミングを設定する必要がある

  • CodeDeploy > アプリケーション > デプロイグループ > 編集

  • デプロイ設定の項目で、トラフィックを再ルーティングするタイミングを指定するにチェック

    • 新環境にトラフィックを切り替えるまでの時間を設定する(とりあえず1時間)
  • 元のリビジョンの終了

    • トラフィックがGreen環境に切り替わったあとで、Blue環境を保持する時間(とりあえず1時間)
  • なぜか設定必要)LoadBalancer

    項目 備考
    ロードバランサー sample-blue-green-alb
    本番稼働リスナーポート HTTPS: 443 HTTPSの場合この設定でいけました。適宜変更。
    テストリスナーポート HTTPS: 4403 HTTPSの場合この設定でいけました。適宜変更。
    ターゲットグループ1 sample-blue-green-tg-1
    ターゲットグループ2 sample-blue-green-tg-2

パイプラインの実行

  • CodePipelineのソースステージで設定したブランチに変更が加わると、CodePipelineが走り出します。
    デプロイステージで止まるので、詳細ボタンからCodeDeployの画面へ遷移
    image.png

  • ステップ3が進行中の状態となれば、テスト用リスナーポートで新しい環境へブラウザからアクセスできるようになります。(https://example.com:4403)
    image.png

  • 動作確認後、「トラフィックの再ルーティング」ボタンを押すことで、通信がGreen環境に流れるようになる
    image.png

  • 問題なければ「元のタスクセットの終了」ボタンを押すことでBlue環境が削除される
    image.png

  • すべて完了となれば終了
    スクリーンショット 2023-04-07 16.49.03.png
    image.png

最後に

ECS FargateのBlue/Greenデプロイと、Codeサービスを利用したCI/CDパイプラインの構築をまとめました。

また今回は、1タスクに1つのコンテナを起動する想定での設定をまとめましたが、実サービスでは1タスクに複数コンテナを稼働させることがあると思います。
そういった環境下でのパイプライン構築時に、いくつかエラーに遭遇しました。
1タスクに複数コンテナを稼働させる場合の設定や、エラーの内容とエラー解決については別記事にまとめたいと思います。

ここまで読んでいただき、ありがとうございました。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4