LoginSignup
9
8

More than 1 year has passed since last update.

CodePipeline を利用した Fargate の ローリングデプロイ

Last updated at Posted at 2021-10-09

はじめに

ECSのローリングデプロイの手順をまとめました。

流れ

①CodeBuild作成
②CodeBuildで作成されたIAMロールに、ECRの権限付与
③buildspec.ymlの作成
④CodePipeline作成
⑤CodePipeline実行時のエラー集

デプロイまでのイメージ図

前提

  • 下記の記事でFargateを作成済み
    (記事を参考にしなくても、ECSが作成されていればよい。Fargateタイプ,EC2タイプどちらでも可)
    Fargate+WordPress構築 ①~Fargate+WordPress構築 ③

  • GitHubにリポジトリ作成済み

  • もしくは、Laravelをfargateで構築した記事も参考になるかと思います。

CodeBuild作成

ビルドプロジェクトを作成するをクリックします。

プロジェクトの設定

プロジェクト名のみ記入

ソース

ソースプロバイダ:GitHub
リポジトリ:OAuth を使用して接続する
GitHubに接続をクリックします

`Authorize aws-codesuite`をクリックします。 `確認`をクリックします。

リポジトリの URL:[GitHubのURL]

環境

  • 環境イメージ:マネージド型イメージ
  • オペレーティングシステム:Amazon Linux 2
  • ランタイム:Standard
  • イメージ:最新のバージョン
  • イメージのバージョン:最新のバージョン
  • 特権付与:チェックする!
  • 環境タイプ: linux
  • サービスロール:新しいサービスロール
    ロールは後で、修正します。

サービスロールは、すでに設定済みの場合、新しくサービスロールを必要はありません。
下記のように既存のサービスロールを選択、AWS CodeBuild にこのサービスロールの編集を許可...のチェックマークを外すだけです。

スクリーンショット 2022-04-07 11.51.33.png

サービスロールのIAM
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Resource": [
                "arn:aws:logs:ap-northeast-1:xxxxxxxxxx:log-group:/aws/codebuild/*:*",
                "arn:aws:logs:ap-northeast-1:xxxxxxxxxx:log-group:/aws/codebuild/*:*"
            ],
            "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:xxxxxxxxxx:report-group/*"
            ]
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "ssm:GetParameters",
            "Resource": "arn:aws:ssm:*:xxxxxxxxxx:parameter/*"
        }
    ]
}

追加設定

環境変数(コンテナ1つの場合)

環境変数を5つ設定します。
スクリーンショット 2022-04-05 12.25.07.png

名前 意味
AWS_DEFAULT_REGION ap-northeast-1 awsリージョン
IMAGE_REPO_NAME wordpress ECRのリポジトリ名
CONTAINER_NAME sample-wordpress タスク定義で設定したコンテナ名
IMAGE_TAG prod ECRに保管されたイメージタグ
AWS_ACCOUNT_ID 12345678 AWSアカウントID

環境変数(コンテナ2つの場合)

下記は、Laravelをfargateで構築した記事になります。 

タスク定義で設定したコンテナが2つの場合、 下記のようにIMAGE_REPO_NAMECONTAINER_NAMEをそれぞれ2つ設定します。

1つのタスクにコンテナが2つある場合があるかと思います。
例えば、Laravelの場合、php-fpmのコンテナとnginxのコンテナを使用します。

名前 意味
AWS_DEFAULT_REGION ap-northeast-1 awsリージョン
IMAGE_REPO_NAME_1 laravel-php ECRのリポジトリ名
CONTAINER_NAME_1 app タスク定義で設定したコンテナ名
IMAGE_REPO_NAME_2 laravel-nginx ECRのリポジトリ名
CONTAINER_NAME_2 nginx タスク定義で設定したコンテナ名
IMAGE_TAG prod ECRに保管されたイメージタグ
AWS_ACCOUNT_ID 12345678 AWSアカウントID

Buildspec

ビルド仕様:buildspec ファイルを使用する
builspec.ymlファイルは、後ほど作成して、GitHubにプッシュします。

バッチ設定

デフォルトのまま
チェックしません
スクリーンショット 2021-10-30 22.26.21.png

アーティファクト

アーティファクトなし
Docker イメージを Amazon ECR にプッシュする場合は、[アーティファクトなし] を選択できます。
キャッシュタイプローカル
DockerLayerCacheチェックする
SourceCacheチェックする

ローカルキャッシュについて

概要

DockerイメージのレイヤやGitのメタデータをCodeBuildの実行ホスト環境内にキャッシュする事で実行時間短縮が期待できます。
CodeBuildのローカルキャッシュには以下3つの種類が存在します。

  • DockerLayerCache
    Buildフェーズなどで実行するDockerイメージのbuild/pull時の各レイヤをキャッシュしてイメージのビルドやDLを高速化します。
    Dockerイメージのbuildやpullは主にBuildフェーズなどで行う内容の為、実行時間が短縮されるフェーズも同様です。

  • SourceCache
    ビルドに使用するソースコードを保存してあるGitリポジトリからDLしたメタデータをキャッシュして、次回以降のDLに前回DL時からの差分のみをDLできるようになります。
    GitリポジトリからDLしたメタデータをキャッシュするので、DOWNLOAD_SOURCEフェーズの実行時間が短縮されます。

  • CustomCache
    buidspec.ymlのcache/pathsで指定したディレクトリ配下のパスに存在するファイル群がキャッシュされるようになります。

キャッシュについて、詳しくはこちら↓

ログ

CloudWatch Logsがチェックされていますので、そのままにします。
ビルド出力ログが CloudWatch にアップロードされます。

スクリーンショット 2021-10-30 22.26.56.png

ビルドプロジェクトを作成をクリックします。

CodeBuildで作成されたIAMロールに、ECRの権限付与

CodeBuildを実行する際、ロールにECRを操作する権限が必要になります。
IAMのロールから、codebuildで検索すると、先程名付けたプロジェクト名のポリシーが見つかります。

ECRの実行権限を追加します。

**上記の画像の`ここに加える!!`の位置に以下のコードを追加します。**
        {
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart"
            ],
            "Resource": "*",
            "Effect": "Allow"
        },

下記の画像のように追加できているとOKです。

buildspec.ymlの作成

GitHubにプッシュするファイルは以下の2つです。

  • Dockerfile
  • buildspec.yml

ファイルの置き場所は全てルートディレクトリ配下です。

./
├── Dockerfile
└── buildspec.yml

CodeBuildで必須ファイルは、以下の2つになります。

  • buildspec.yml

buildspec.ymlの作成

buildspec.ymlは、以下をコピペし、一部編集します。
buildspec.ymlファイルは、ソースコードのトップディレクトリに設置しておくことで、CodeBuildがbuildspec.ymlの内容を読み込み実行します。

DockerHubのアカウント作成

その前に、DockerHubのアカウント作成する必要があります。理由を含めて下記の記事を見てください

コンテナが1つの場合

buildspec.yml
version: 0.2

env:
  parameter-store:
    DOCKER_USER: DOCKER_HUB_ID
    DOCKER_PASSWORD: DOCKER_HUB_PASSWORD

phases:
  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - echo $DOCKER_PASSWORD | docker login -u $DOCKER_USER --password-stdin
  build:
    commands:
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
  post_build:
    commands:
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG  > imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json

imagedefinitions.jsonについて

CodeBuildステージで、ビルド情報がimagedefinitions.jsonに記載され、デプロイステージで、その情報を元にタスク定義の新しいリビジョンを作成し、タスク定義を反映したタスクがデプロイされます

詳細はこちら↓

コンテナが2つの場合

buildspec.yml
version: 0.2

env:
  parameter-store:
    DOCKER_USER: DOCKER_HUB_ID
    DOCKER_PASSWORD: DOCKER_HUB_PASSWORD

phases:
  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - echo $DOCKER_PASSWORD | docker login -u $DOCKER_USER --password-stdin
  build:
    commands:
      - docker build -t $IMAGE_REPO_NAME_1:$IMAGE_TAG -f docker/php/Dockerfile .
      - docker build -t $IMAGE_REPO_NAME_2:$IMAGE_TAG -f docker/nginx/Dockerfile .
      - docker tag $IMAGE_REPO_NAME_1:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_1:$IMAGE_TAG
      - docker tag $IMAGE_REPO_NAME_2:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_2:$IMAGE_TAG
  post_build:
    commands:
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_1:$IMAGE_TAG
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_2:$IMAGE_TAG
      - printf '[{"name":"%s","imageUri":"%s"},{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME_1 $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_1:$IMAGE_TAG $CONTAINER_NAME_2 $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_2:$IMAGE_TAG > imagedefinitions.json

artifacts:
  files:
    - imagedefinitions.json

buildspec.ymlのコマンド集

設定 意味 備考
version ビルドスペックのバージョン 現時点2021/10/1の最新バージョンは0.2です。
phases ビルドの各フェーズでどういったコマンドを実行するか定義する大本のキー 設定可能なフェーズは install / pre_build / build / post_build の4つです。
install インストールフェーズで実行するコマンドを定義 ビルドする前に必要なライブラリなどをここで用意します。
pre_build ビルド前に実行するコマンドを定義 設定ファイルを書き換えたりといったビルド前に実施するちょっとした処理内容を記述する箇所です。
build ビルドする際に実行するコマンドを定義 dockerのイメージをビルドしたり、タグ付けします。
post_build ビルド後に実行するコマンドを定義 例えばGitHubリリースへアップロードするといったビルド後の処理を記述します。
artifacts ビルド後に生成した成果物(アーティファクト)の設置場所 type はzipのみ指定可能。 files でCodeBuildでビルドしたアーティファクトのパスを指定します。ワイルドカードも可能です。

そしてGitHubにプッシュしましょう。

CodePipeline作成

CodePipeline作成をクリックします。

パイプラインの設定

  • パイプライン名:適切に
  • サービスロール:新しいサービスロール

ソースステージを追加する

  • ソースプロバイダー:GitHub(バージョン2)
  • 接続:GitHubに接続するをクリック
  • 接続名:リポジトリ名
     GitHubに接続するをクリック

 Authorize AWS Connector for GitHubをクリックすると前の画面に戻る

  • GitHubアプリの新しいアプリをインストールするをクリックします
`Only select repositories`を選択し、`リポジトリを選択し`、installをクリックします

接続をクリックします

  • リポジトリ名:選択肢として表示されます
  • ブランチ名:選択肢として表示されます

ビルドステージを追加する

  • プロバイダーを構築する:AWS CodeBuild
  • プロジェクト名:先程作成したCodeBuild名
  • 環境変数:無記入
  • ビルドタイプ:単一ビルド

デプロイステージを追加する

  • デプロイプロバイダ:Amazon ECS
  • クラスター名:ECSで作成済みのクラスター
  • サービス:ECSで作成済みのサービス
  • イメージ定義ファイル - オプショナル:無記入
    イメージ定義ファイル(image definitions file)は、CodeBuildする時に作成されるので、書かなくても大丈夫です。

次に進み問題なければ、パイプライン作成するをクリックします。

CodePipelineが動きます。

CodePipeline実行時のエラー

Code Buildステージエラー①

Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command:
 aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 
xxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com. Reason: exit status 1

原因は、ビルドを実行するロールにECRを操作する権限がないことが考えられます。
先程説明した手順通り、権限が付与されているか確認しましょう。

そして、ECRの実行権限のポリシーを追加する必要があります。

CodePipelineを再実行してみましょう。
CodePipelineの変更をリリースするをクリックすると、再実行されます。

それでもだめなら、アクセスキーとシークレットキーが正しく設定されているか確認します

$ cat ~/.aws/credentials 

Code Buildステージエラー②

Phase context status code: YAML_FILE_ERROR Message: YAML file does not exist

buildspec.ymlがないと言われていますので、buildspec.ymlを加え、GitHubにプッシュすると解決します。

Code Buildステージエラー③

Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker push xxxxxxxxx.dkr.ecr.p-northeast-1.amazonaws.com/wordpress:latest. Reason: exit status 1

p-northeast-1となっております。正しくは、ap-northeast-1です。

ECS Deployステージエラー①

The AWS ECS container wordpres does not exist

コンテナ名が間違えている可能性が大です。この場合、正しくはwordpressです。

ECS Deployステージエラー②

imagedefinitions.jsonが無効なフォーマットになっています。

The image definition file imagedefinitions.json contains invalid JSON format

buildspec.ymlに以下の記載がない場合に、このエラーになります。
こちらの工程ですね

コンテナが1つの場合

printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG  > imagedefinitions.json

コンテナが2つの場合

printf '[{"name":"%s","imageUri":"%s"},{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME_1 $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_1:$IMAGE_TAG $CONTAINER_NAME_2 $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME_2:$IMAGE_TAG > imagedefinitions.json

デプロイまで成功すると、ECSのタスクが実行されているはずです!

1回のビルドで2つのサービスのタスクをデプロイする

1回のビルドで、2つのサービス(2つのタスク定義をデプロイ)にそれぞれタスクをデプロイしたい場合があるかと思います。
その場合、Deployステージにアクションを追加クリックし、先程設定したものとは別に、デプロイしたいサービスを指定します。
また、アクション名変数の名前空間は、先程作成したDeployと名前を被らないように設定すると、完了です。
スクリーンショット 2022-04-08 13.04.27.png

スクリーンショット 2022-04-08 13.07.02.png

ビルド完了後、各サービスに設定されたタスクがそれぞれデプロイされます。

CodeBuildの環境を編集する場合

codebuildの環境を修正し、更新するとき、以下のエラーになります。

スクリーンショット 2022-04-06 17.52.52.png

codebuild.amazonaws.com did not create the default version (v4) of the CodeBuildBasePolicy-xxxxxxx-ap-northeast-1 policy that is attached to the codebuild-xxxxxxx-role role. 
To continue, detach the policy from any other identities and then delete the policy and the role.

「AWS CodeBuild にこのサービスロールの編集を許可し、このビルドプロジェクトでの使用を可能にする」のチェックを外すと、更新できます。

スクリーンショット 2022-04-06 17.50.43.png

DockerHubアカウントを設定

Code Buildステージエラーで以下のエラーが起きることがあるため、DockerHubの無料プランに入ることをおすすめします。

toomanyrequests: You have reached your pull rate limit. 
You may increase the limit by authenticating and upgrading:
https://www.docker.com/increase-rate-limit

下記の記事通りに行ってください。

CodePipelineの通知設定

Slackに通知設定は下記の記事通りにするとできます。

CloudFrontのキャッシュを削除するステージ追加

CloudFrontを使用している場合、デプロイごとにCloudFrontのキャッシュを削除したいケースがあるかと思います。
以下の記事通り行うと実現できます。

参考記事

9
8
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
8