こんにちは。AWS CLIが好きな福島です。
はじめに
今回は、以下のハンズオンを実施したため、ハンズオンの内容を基にCI/CD for Amazon ECSの自動デプロイの流れをまとめてみます。
◆AWS CI/CD for Amazon ECS ハンズオン
https://pages.awscloud.com/rs/112-TZM-766/images/AWS_CICD_ECS_Handson.pdf
また、以下のブログを読んだ後に本ブログをお読みいただくと良いかと存じます。 https://blog.serverworks.co.jp/cicd-ecs-build-deploy-files
概要図

流れの説明
①コードのPush
ローカルや開発環境で開発したコードをCodeCommitにPushします。
②CodeCommitへのPushを検知し、CodePipelineが起動
CodeCommitへのPushを検知し、CodePipelineが起動します。
これはCodePipeline作成時の以下の設定にあたります。

③CodePipeline用のS3バケットが作成され(初回実行のみ)、CodeCommitのコードが複製
CodePipeline用のS3バケットが作成され(初回実行のみ)、CodeCommitにPushしたコードが複製されます。
CodePipelineの作成時に作成するS3バケットの設定などを行いませんが、「codepipeline-ap-northeast-1-任意の数字」という名前で自動でS3バケットが作成されます。
- 補足
CodePipelineを実行後、実行履歴のアーティファクトでS3を確認することが可能です。
SourceArtifactをクリックすると、S3バケットが表示されます。

④CodePipelineからCodeBuildが呼び出され、ビルド環境が起動(利用者から確認不可)
CodePipelineからCodeBuildが呼び出され、ビルド環境が起動されます。
(ビルド環境は利用者からは確認することはできません。)
ビルド環境は、CodeBuildのビルドプロジェクト作成時の「環境」で設定した内容で起動されます。

また、IAMロールを自動作成した場合、ロールには以下のようなカスタムポリシーがアタッチされます。 なお今回実施したハンズオンの場合、ビルド環境からECRにもアクセスが必要なため、AmazonEC2ContainerRegistryPowerUser(マネージドポリシー)を別途付与しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Resource": [
"arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/codebuild/php-sample-build",
"arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/codebuild/php-sample-build:*"
],
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
]
},
{
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::codepipeline-ap-northeast-1-*"
],
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectVersion",
"s3:GetBucketAcl",
"s3:GetBucketLocation"
]
},
{
"Effect": "Allow",
"Action": [
"codebuild:CreateReportGroup",
"codebuild:CreateReport",
"codebuild:UpdateReport",
"codebuild:BatchPutTestCases",
"codebuild:BatchPutCodeCoverages"
],
"Resource": [
"arn:aws:codebuild:ap-northeast-1:123456789012:report-group/php-sample-build-*"
]
}
]
}
⑤S3に複製されたコードをビルド環境に複製
S3に複製されたコードをビルド環境に複製します。
- 余談
CodeCommitから直接コードを複製しても良い気がしますが、S3にコードを一旦複製しているのは、過去に実行したビルドで利用したコードを管理するためなのかなと考えました。
⑥ECRにログイン
⑦イメージの作成,
⑧ECRにイメージをPush(imageDetail.jsonも作成)
⑥,⑦,⑧まとめて記載しますが、今回のハンズオンの場合、buildspec.ymlに従いざっくり
- ECRにログイン
- イメージの作成
- ECRにイメージをPush
を行います。
buildspec.ymlにはビルド時のコマンドが記載されており、利用するファイルは、ビルドプロジェクト作成時の「Buildspec」で設定可能です。

⑨BuildArtifactをS3に格納
BuildArtifactとは、BuildSpec.ymlに定義したファイルとなります。今回は、imageDetail.jsonとなります。
これがあることでロールバックを可能にしているかと存じます。
アプリケーションのリビジョンからバージョンを確認することが可能でこれの実態がBuildArtifactなのかなと思っております。

⑩CodePipelineからCodeDeployが呼び出される
CodeBuildの処理が完了したら、CodeDeployが呼び出されます。
⑪taskdef.jsonの内容でタスク定義の更新(利用するイメージの書き換え)
CodeBuildで作成したイメージを利用するようタスク定義をtaskdef.jsonを基に更新します。
タスク定義更新に利用するファイル(taskdef.json)は、CodePipelineのデプロイの編集画面の以下で設定します。

⑫更新したタスク定義でコンテナをデプロイ(Greenの環境を作成)
appspec.ymlを基に更新したタスク定義でタスク(コンテナ)をデプロイします。(Greenの環境を作成)
この段階でECSの画面を確認すると、タスク(コンテナ)が増えていることが分かります。
タスク画面(参考)

⑬既存のコンテナを削除(Blueの環境を削除)
appspec.ymlを基に既存のコンテナを削除します。(Blueの環境を削除)
この段階でECSの画面を確認すると、タスク(コンテナ)が減っていることが分かります。
タスク画面(参考)

補足
⑫,⑬時のALB側の動き
⑫,⑬の際のALBの動きを記載します。
まず、ECSのサービスを作成する際にデプロイメントタイプを設定する箇所があります。
デプロイメントタイプで「Blue/Green デプロイメント (AWS CodeDeploy を使用)」を選択し、ロードバランサーにALBを選択すると、
以下のようにターゲットグループを2つ用意することになります。

この2つのターゲットグループをCodeDeployが自動でを入れ替えることでBlue/Greenデプロイを行っています。 そのため、デプロイ前後でALBのターゲットグループが入れ替わっていることが分かるかと存じます。
- デプロイ前

- デプロイ後

IMAGE1_NAME,TASK_DEFINITIONが定義される流れ
この2つの変数が定義される流れが混乱したため、まとめてみました。
①CodeBuild時にアーティファクト(imageDetail.json)を生成
- imageDetail.jsonの中身(例)
{
"ImageURI": "ACCOUNTID.dkr.ecr.us-west-2.amazonaws.com/dk-image-repo@sha256:example3"
}
②生成したアーティファクト(imageDetail.json)に記載されたImageURIが「IMAGE1_NAME」に定義される
③ソースに含まれるtaskdef.jsonと「IMAGE1_NAME」に定義された情報を基にタスク定義を生成

- taskdef.jsonに設定されたIAMGE1_NAME(例)
"image": "<IMAGE1_NAME>",
④生成されたタスク定義が「TASK_DEFINITION」に定義される
⑤タスク定義をソースに含まれるappspec.ymlと「TASK_DEFINITION」に定義された情報を基にECSへデプロイ

- appsepec.ymlに設定されたTASK_DEFINITION(例)
TaskDefinition: "<TASK_DEFINITION>"
終わりに
今回は、備忘録としてECSへの自動デプロイの流れをまとめてみました。
どなたかのお役に立てれば幸いです。