本レポジトリで構成するCICDについて解説します。全体の流れは以下の通りです。
大きく、GitHub Actionsでソースを準備するいわゆるCIの部分、
CloudWatchおよびCodeStarConnectionsで変更を検出する部分、
CodePipelineでデプロイするいわゆるCDの部分に分かれます。
アプリケーションおよびECSのデプロイ設定はそれぞれGitHubのレポジトリで管理しています。 アプリケーションレポジトリに変更がプッシュされるとGitHub Actionsにより変更内容がAWSのソース置き場(ECR)に配置されます。
アプリケーションのレポジトリのmasterブランチに変更がプッシュされるとGitHub Actionsによりアプリケーションビルドのパイプラインが自動実行されます。サンプルレポジトリの場合は以下のようなパイプラインを定義しています。パイプラインの設定内容はレポジトリの.github\workflows\workflow.ymlを参照ください。
- GitHub Actionsセルフホストランナー上で docker コマンドを使用してレポジトリのルートにあるdockerfileをbuildする
- buildしたimageは以下のタグを付与しECRにプッシュする
<ECRホスト名>/<PJ-NAME-APP-NAME>:latest
- このパイプラインは
masterブランチに対する変更時に実行する - パイプラインは
latestのタグがついたrunnerで実行する
ECRにプッシュされる最新のイメージは常に<ECRホスト名>/<PJ-NAME-APP-NAME>:latestというイメージ名になります。古いイメージはタグなしとなり一日経過後にライフサイクルポリシーにより自動で削除されます。もし、古いイメージに戻したい場合はアプリケーションレポジトリを過去のバージョンに戻してイメージを再ビルドしてください。
ソース置き場(ECR)が更新されるとその変更を検知し、CloudWatchからCodePipelineが実行されます。
ECRの変更はCloudWatch Eventで検知します。指定したレポジトリに対するイメージプッシュが成功したイベントを検知するとCodePipelineのパイプラインを開始します。
アプリケーションおよびECSのデプロイ設定はそれぞれGitHubのレポジトリで管理しています。
ECSデプロイ設定のレポジトリに対しmasterブランチに変更がプッシュされるとCodeStarConnectionsによりレポジトリの更新が検知され、
これによりCodePipline が実行されます。
CodePipelineは2つのステージで構成します。SourceステージとDeployステージです。これらのステージは順番に実行されます。Sourceステージはデプロイに必要な情報を取得するステージです。DeployはCodeDeployを実行し、ECSサービスのタスクをBlue/Greenデプロイで更新します。
Sourceステージは2つのソースアクションを定義しています。GitHub(ECSレポジトリ)およびECRから情報を取得するアクションです。それぞれ以下の情報を取得し、アーティファクトとして格納します。格納したアーティファクトは次のステージへ引き継がれます。
- CodeStarConnections
- ECSデプロイ設定をGitHubのレポジトリから取得し、
settings.zipを作成します。 - 作成したzipを
settingsという名前のアーティファクトとして格納します。
- ECSデプロイ設定をGitHubのレポジトリから取得し、
- ECR
- 指定レポジトリの
latestタグのついたイメージ名(このイメージは<アカウントID>.dkr.ecr.<リージョン>.amazonaws.com/<レポジトリ名>@<イメージのハッシュID>の形式となる。そのため、同じlatestタグでもイメージを一意に判別できる)を取得します。 - 上記取得したイメージ名を
imagesという名前のアーティファクトとして格納します。
- 指定レポジトリの
Deployステージは1つのデプロイアクションを定義しています。CodeDeployを使用したECSサービスのタスクをBlue/Greenデプロイするアクションです。前のステージで取得したアーティファクトを使い、Blue/Greenデプロイ用に定義したCodeDeployを実行します。
- アーティファクト
settingsおよびimagesを受け取ります settingsのzipを展開し、中に含まれるappspec.yamlをAppSpecTemplatePathに設定しますsettingsのzipを展開し、中に含まれるtaskdef.jsonをTaskDefinitionTemplatePathに設定します- アーティファクト
imagesに格納されたイメージを使用し、taskdef.json内のIMAGE1_NAMEを置換します
CodeDeployによるタスクの切り替えには数分時間を要します。パイプラインの進行状況はマネジメントコンソールのCodePipelineまたはCodeDeployで確認できます。
デプロイが成功しても不具合などが見つかりすぐに前のバージョンへ戻したい場合はCodeDeployからロールバックを実行してください。Blue/Greenの設定で5分間、前バージョンのタスクを削除する猶予期間を設けています。この猶予期間はサービスデプロイモジュールのパラメータで任意の時間に設定可能です。
ただし、アプリケーション(ECR)の変更に伴うデプロイをした後のBlue/Greenのロールバックをした場合は注意が必要です。Blue/Greenのロールバックを実行してもECRのイメージはロールバックされません。そのため、ECRにあるlatestタグのイメージは更新され、前バージョンのイメージはタグなしのイメージとなります。ECRのライフサイクルポリシーでタグなしのイメージは1日後に自動で削除するようになっているため、1日以上放っておくと稼働中のイメージが消失してしまいます。タスク異常終了やレプリカ数の増大など、新たにタスクを作るまでは問題になりませんが、忘れない内にアプリケーションを正しく修正し、ECRのイメージを最新化しましょう。
ECS定義のみの更新であれば上記影響ありません。CodeDeployからロールバックを実行するとタスク定義は残りますが、サービスが使用するタスク定義はロールバックされ、前バージョンのタスク定義を使用します。