内容
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関連付け済
目次
- パイプラインの構成
- Blue/Greenデプロイとは
- ■ ビルド定義・デプロイ定義・タスク定義ファイルの作成
- ■ ALBの作成
- ■ Blue/Greenデプロイ用のECSサービス作成
- ■ CodePipeline作成
- ■ CodePipeline作成後にやること
- パイプラインの実行
- 最後に
パイプラインの構成
今回は以下のようなパイプラインの構成で進めて行きたいと思います。
Blue/Greenデプロイとは
古い環境(Blue環境)と新しい環境(Green環境)の両方の環境を用意し、サービスのアップデート時にはGreen環境に変更を反映し、動作確認後ロードバランサー等によるルーティングの制御によってトラフィックを切り替え、ダウンタイムなしで環境を切り替えるデプロイ方式。
-
Blue環境に既存のアプリケーションが存在し、ロードバランサーがBlueにトラフィックを流している環境に対して、CodeDeployを用いてGreen環境に新しくデプロイを行う。
テストリスナーポートへのアクセスにより、動作確認が可能。
-
Green環境へデプロイ完了後、CodeDeployがロードバランサーを操作してトラフィックがBlue環境を向くように変更
■ ビルド定義・デプロイ定義・タスク定義ファイルの作成
以下の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.yml
・taskdef.json
・imageDetail.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の画面へ遷移
-
ステップ3が進行中の状態となれば、テスト用リスナーポートで新しい環境へブラウザからアクセスできるようになります。(https://example.com:4403)
最後に
ECS FargateのBlue/Greenデプロイと、Codeサービスを利用したCI/CDパイプラインの構築をまとめました。
また今回は、1タスクに1つのコンテナを起動する想定での設定をまとめましたが、実サービスでは1タスクに複数コンテナを稼働させることがあると思います。
そういった環境下でのパイプライン構築時に、いくつかエラーに遭遇しました。
1タスクに複数コンテナを稼働させる場合の設定や、エラーの内容とエラー解決については別記事にまとめたいと思います。
- CodePipeline『Exception while trying to read the task definition artifact file from: SourceArtifact』エラーの原因と対処法
- 【ECS Blue/Greenデプロイ】1タスクで複数コンテナ稼働している場合のCI/CDパイプライン構築
ここまで読んでいただき、ありがとうございました。