Memo

メモ > サーバ > サービス: AWS > ECR+ECS+Codeシリーズで自動デプロイ: CodeBuildでデプロイ用イメージを自動ビルド

■ECR+ECS+Codeシリーズで自動デプロイ: CodeBuildでデプロイ用イメージを自動ビルド
上にある「ECR+ECS+Codeシリーズで自動デプロイ: ベースイメージを登録」からの続き ローカルにDockerをビルドする環境が無くても、リポジトリの内容をもとにAWS上でビルド&ECRへのイメージプッシュを行える 主に以下の書籍を参考に検証中 CodeシリーズはP.335から AWSコンテナ設計・構築[本格]入門 | SBクリエイティブ https://www.sbcr.jp/product/4815607654/ GitHub - uma-arai/sbcntr-resources: 書籍用の各種リソースのダウンロードリポジトリ https://github.com/uma-arai/sbcntr-resources ■前提 ベースイメージは、先の手順で作成した以下を使うものとする 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/base_php81_apache:1.0.0 そのイメージをもとに、先の手順でプログラムも含めたApache+PHPの環境を作成した ecr_php81_apache 以下で起動&終了でき、http://localhost/ にアクセスできることを確認した
$ cd docker/ecr_php81_apache $ docker-compose build $ docker-compose up -d $ docker-compose down
■準備: Bitbucketアプリパスワードの作成 今回はBitbucketからデプロイするので、以下を参考にアプリパスワードを発行しておく アプリ パスワード | Bitbucket Cloud | アトラシアン サポート https://support.atlassian.com/ja/bitbucket-cloud/docs/app-passwords/ 個人設定 → アクセス管理 → アプリパスワード 以下のページに遷移できる https://bitbucket.org/account/settings/app-passwords/ Label: Example-ECS 権限: 「リポジトリ」の「読み取り」のみ 「作成」をクリックするとアプリパスワードが表示されるので控えておく ■準備: IAMポリシーの作成 セキュリティ認証情報 → ポリシー → ポリシーの作成 「JSON」タブに以下を入力する AWSアカウントID(123456789012)とイメージ名(base_php81_apache と ecr_php81_apache)は、環境に合わせて調整する イメージ名は、 ベースイメージを参照するためのリポジトリ(base_php81_apache)と、 ビルド済みイメージを保存するためのリポジトリ(ecr_php81_apache)を、 それぞれ2箇所で指定する
{ "Version": "2012-10-17", "Statement": [ { "Sid": "ListImagesInRepository", "Effect": "Allow", "Action": [ "ecr:ListImages" ], "Resource": [ "arn:aws:ecr:ap-northeast-1:123456789012:repository/base_php81_apache", "arn:aws:ecr:ap-northeast-1:123456789012:repository/ecr_php81_apache" ] }, { "Sid": "GetAuthorizationToken", "Effect": "Allow", "Action": [ "ecr:GetAuthorizationToken" ], "Resource": "*" }, { "Sid": "ManageRepositoryContents", "Effect": "Allow", "Action": [ "ecr:BatchCheckLayerAvailability", "ecr:GetDownloadUrlForLayer", "ecr:GetRepositoryPolicy", "ecr:DescribeRepositories", "ecr:ListImages", "ecr:DescribeImages", "ecr:BatchGetImage", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:PutImage" ], "Resource": [ "arn:aws:ecr:ap-northeast-1:123456789012:repository/base_php81_apache", "arn:aws:ecr:ap-northeast-1:123456789012:repository/ecr_php81_apache" ] } ] }
「次のステップ:タグ」をクリック そのまま「次のステップ:確認」をクリック ポリシーの作成画面になるので以下を入力 名前: Container-Test-AccessingECRRepositoryPolicy 説明: Policy to access ECR repo 「ポリシーの作成」をクリック なお、上記のコードは書籍のサポートページ掲載されている sbcntr-resources/cloud9_ecr_policy.json at main - uma-arai/sbcntr-resources https://github.com/uma-arai/sbcntr-resources/blob/main/iam/cloud9_ecr_policy.json AWS公式サイトにも掲載されている(「Accessing One Amazon ECR Repository」の部分) Amazon Elastic Container Registry Identity-Based Policy Examples - Amazon ECR https://docs.aws.amazon.com/AmazonECR/latest/userguide/security_iam_id-based-policy-examples.html ■CodeBuild用ファイル作成 アプリケーションリポジトリのルートディレクトリに、以下をもとにファイルを作成する https://github.com/uma-arai/sbcntr-resources/blob/main/cicd/buildspec.yml docker\ecr_php81_apache\buildspec.yml
version: 0.2 env: variables: AWS_REGION_NAME: ap-northeast-1 ECR_REPOSITORY_NAME: ecr_php81_apache DOCKER_BUILDKIT: "1" phases: install: runtime-versions: docker: 20 pre_build: commands: - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) - aws ecr get-login-password --region ${AWS_REGION_NAME} | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION_NAME}.amazonaws.com/${ECR_REPOSITORY_NAME} - IMAGE_TAG=$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7) build: commands: - docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} -f docker/php/Dockerfile . post_build: commands: - docker image push ${REPOSITORY_URI}:${IMAGE_TAG} - printf '[{"name":"%s","imageUri":"%s"}]' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json artifacts: files: - imagedefinitions.json
ファイルを作成したら、コミット&プッシュしておく imagedefinitions.json というファイル名が2箇所あるが、これはビルド結果をCodeDeployやCodePipelineに渡すためのもの ファイル名は ・Amazon ECS 標準デプロイには imagedefinitions.json がデフォルト ・Amazon ECS Blue/Green デプロイでは imageDetail.json がデフォルト となっているので、原則これに合わせておくといい また imageDetail.json の場合、printf 内の「[{"name":"%s","imageUri":"%s"}]」は「{"name":"%s","ImageURI":"%s"}」となるので注意 イメージ定義ファイルのリファレンス - AWS CodePipeline https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/file-reference.html また、一例だが post_build 部分を以下のようにすると、イメージをプッシュする直前の諸々の情報が、CodeBuildのコンソールに出力されるようになる デバッグの一手段として
post_build: commands: - echo Build completed on `date` - echo ${AWS_REGION_NAME} - echo ${ECR_REPOSITORY_NAME} - echo ${DOCKER_BUILDKIT} - echo ${AWS_ACCOUNT_ID} - echo ${REPOSITORY_URI} - echo ${IMAGE_TAG} - echo '[{"name":"%s","imageUri":"%s"}]' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG - docker image push ${REPOSITORY_URI}:${IMAGE_TAG} - printf '[{"name":"%s","imageUri":"%s"}]' $ECR_REPOSITORY_NAME $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
■CodeBuild設定 ※今回はCodeCommitではなく、Bitbucketからデプロイする ※「Container-Test」というパイプライン名は、実際は案件名と環境をもとに付けると良さそう CodeBuild → ビルドプロジェクトを作成する プロジェクトの設定 プロジェクト名: Container-Test ビルドバッジ: (「ビルドバッジを有効にする」にチェックを入れる) ソース ソースプロバイダ: Bitbucket リポジトリ: Bitbucketアプリパスワードで接続する Bitbucketユーザー名: refirio Bitbucketのアプリパスワード: 9jzJ4nHrLp395xTzjgdX ※入力したら「Bitbucket認証情報の保存」ボタンをクリックし、Bitbucketに接続できることを確認する リポジトリのURL: https://bitbucket.org/refirio/ecr_php81_apache.git(Bitbucketに接続すると入力欄が表示される) ソースバージョン: master 環境 環境イメージ: マネージド型イメージ オペレーティングシステム: Amazon Linux 2 ランタイム: Standard イメージ: aws/codebuild/amazonlinux2-x86_64-standard:4.0 イメージのバージョン: このランタイムバージョンには常に最新のイメージを使用してください 特権付与: (「Docker イメージを構築するか、ビルドで昇格されたアクセス権限を取得するには、このフラグを有効にします」にチェックを入れる) サービスロール: 新しいサービスロール(以前作成したものがあれば「既存のサービスロール」を選択する) ロール名: Container-Test-CodeBuild-Role(以前作成したものがあれば選択する) Buildspec ビルド仕様: buildspecファイルを使用する アーティファクト タイプ: アーティファクトなし キャッシュタイプ: ローカル 少なくとも 1 つのオプションを選択してください。:(「DockerLayerCache」のみにチェックを入れる) ログ CloudWatch:(「CloudWatch Logs」にチェックを入れる) 「ビルドプロジェクトを作成する」ボタンをクリック ■ロールにアクセス権限を付与 CodeBuild → ビルドプロジェクト 作成したプロジェクトをクリックし、「ビルド開始」をクリック …としても、現時点では以下のエラーになる CodeBuildを設定する際に Container-Test-CodeBuild-Role というロールを作ったが、このロールにアクセス権限を与えていないため [Container] 2022/01/19 11:37:34 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 https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/ecr_php81_apache. Reason: exit status 1 「準備: IAMポリシーの作成」で作成したポリシーを紐づける セキュリティ認証情報 → ロール 先の手順中で作成した Container-Test-CodeBuild-Role を選択 「アクセス許可を追加 → ポリシーをアタッチ」をクリック 上の手順中で作成した Container-Test-AccessingECRRepositoryPolicy にチェックを入れ、「ポリシーのアタッチ」ボタンをクリック ■CodeBuild実行 CodeBuild → ビルドプロジェクト → Container-Test 画面上部にある「ビルド開始」ボタンをクリック しばらく待つと最後に以下のようなログが表示され、ビルドが完了した
[Container] 2023/05/12 03:50:00 Phase complete: POST_BUILD State: SUCCEEDED [Container] 2023/05/12 03:50:00 Phase context status code: Message: [Container] 2023/05/12 03:50:00 Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED [Container] 2023/05/12 03:50:00 Phase context status code: Message:
ビルドする内容によると思われるが、今回は4〜5分程度で完了した ECRのリポジトリ ecr_php81_apache を確認すると、a322b3d というタグが指定されたイメージを確認できる (buildspec.yml の内容に従って、Bitbucketのコミットしたときに発行されたハッシュの先頭7桁がタグ名に使われる) 作成された以下のイメージを使用して、新しいタスクとしてECSに反映できることを確認する 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ecr_php81_apache:a322b3d ※タグの上書き禁止設定(タグのイミュータビリティ)を有効にしている場合、 後の手順でエラーにならないように、この時点でリポジトリに何かしらの変更を加えておくといい ※デプロイできるかの確認のために、この時点でトップページの表示に何かしらの変更を加えておくといい ■ビルドエラー 以下などが参考になりそう CodeBuildでECRビルドエラーから得た4つの知見 - Qiita https://qiita.com/icck/items/bcf118a38c2a691a837d AWS CodeBuildを使ってDockerイメージをビルドし、Amazon EC2 Container Registry(ECR)へpushする | DevelopersIO https://dev.classmethod.jp/articles/20170225-codebuild-docker/ AWS CodeBuildでDockerビルドしてECRへプッシュする - け日記 https://ohke.hateblo.jp/entry/2020/09/26/230000 ■ビルドエラー: 具体例1 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
[Container] 2022/01/20 06:31:27 Running command docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . failed to dial gRPC: cannot connect to the Docker daemon. Is 'docker daemon' running on this host?: dial unix /var/run/docker.sock: connect: no such file or directory
エラーメッセージで調べると、特権を有効にする必要があるらしい CodeBuildでDocker in Dockerする - Qiita https://qiita.com/reireias/items/c02e5e7b2f099f2dab9e プロジェクトを選択し、「編集 → 環境 → イメージの上書き」として「特権付与」の項目を確認すると、チェックを入れ忘れていた チェックを入れて「環境を更新」ボタンを押す ■ビルドエラー: 具体例2 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
[Container] 2022/01/20 07:26:20 Entering phase BUILD [Container] 2022/01/20 07:26:20 Running command docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . #1 [internal] load build definition from Dockerfile #1 sha256:25a25a7aeafc92304eb63ea0db9f200c3253075e86ba57c7dac9663fd44d2194 #1 transferring dockerfile: 2B done #1 DONE 0.1s #2 [internal] load .dockerignore #2 sha256:f9f7891f650ee769119b4b75aaaa3c7e5037b200eb42f86391868e95a0a17f8a #2 transferring context: 2B done #2 DONE 0.1s failed to solve with frontend dockerfile.v0: failed to read dockerfile: open /var/lib/docker/tmp/buildkit-mount854683111/Dockerfile: no such file or directory [Container] 2022/01/20 07:26:20 Command did not exit successfully docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . exit status 1 [Container] 2022/01/20 07:26:20 Phase complete: BUILD State: FAILED [Container] 2022/01/20 07:26:20 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} .. Reason: exit status 1
Dockerfileを読み込めないとなっている 以下のようにパスを調整 docker\ecr_php81_apache\docker\buildspec.yml
- docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} . ↓ - docker image build -t ${REPOSITORY_URI}:${IMAGE_TAG} -f docker/php/Dockerfile .
■ビルドエラー: 具体例3 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
[Container] 2022/01/20 07:57:40 Entering phase POST_BUILD [Container] 2022/01/20 07:57:40 Running command docker image push ${REPOSITORY_URI}:${IMAGE_TAG} The push refers to repository [123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ecr_php81_apache] 4906f6f3890c: Preparing 2fee96bd8066: Preparing 280952099e51: Preparing 〜中略〜 4906f6f3890c: Retrying in 1 second 7173e6f39ae9: Retrying in 1 second 280952099e51: Retrying in 1 second 2fee96bd8066: Retrying in 1 second EOF [Container] 2022/01/20 07:58:30 Command did not exit successfully docker image push ${REPOSITORY_URI}:${IMAGE_TAG} exit status 1 [Container] 2022/01/20 07:58:30 Phase complete: POST_BUILD State: FAILED [Container] 2022/01/20 07:58:30 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker image push ${REPOSITORY_URI}:${IMAGE_TAG}. Reason: exit status 1
IAMポリシーで指定するリポジトリの名前が間違っていたので修正 ■ビルドエラー: 具体例4 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
tag invalid: The image tag '6abc7d3' already exists in the 'ecr_php81_apache' repository and cannot be overwritten because the repository is immutable. [Container] 2022/02/08 02:32:30 Command did not exit successfully docker image push ${REPOSITORY_URI}:${IMAGE_TAG} exit status 1 [Container] 2022/02/08 02:32:30 Phase complete: POST_BUILD State: FAILED [Container] 2022/02/08 02:32:30 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: docker image push ${REPOSITORY_URI}:${IMAGE_TAG}. Reason: exit status 1 [Container] 2022/02/08 02:32:30 Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED [Container] 2022/02/08 02:32:30 Phase context status code: Message:
タグの上書き禁止設定(タグのイミュータビリティ)を有効にしていて、すでにビルド済みのイメージが存在するためだった リポジトリに変更を加えてから再度ビルドするか、ビルド済みのイメージを削除してから再度ビルドする ■ビルドエラー: 具体例5 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
[Container] 2023/05/12 03:25:38 Waiting for agent ping [Container] 2023/05/12 03:25:39 Waiting for DOWNLOAD_SOURCE [Container] 2023/05/12 03:25:42 Phase is DOWNLOAD_SOURCE [Container] 2023/05/12 03:25:42 CODEBUILD_SRC_DIR=/codebuild/output/src317942003/src/bitbucket.org/refirio/ecr_php81_apache [Container] 2023/05/12 03:25:44 Phase complete: DOWNLOAD_SOURCE State: FAILED [Container] 2023/05/12 03:25:44 Phase context status code: YAML_FILE_ERROR Message: YAML file does not exist
buildspec.ymlをコミット&プッシュしていなかったので対応 ■ビルドエラー: 具体例6 「ビルド開始」をクリックする しばらく待つと、以下のエラーで止まった
[Container] 2023/05/12 03:30:08 Waiting for agent ping [Container] 2023/05/12 03:30:09 Waiting for DOWNLOAD_SOURCE [Container] 2023/05/12 03:30:12 Phase is DOWNLOAD_SOURCE [Container] 2023/05/12 03:30:12 CODEBUILD_SRC_DIR=/codebuild/output/src787575457/src/bitbucket.org/refirio/ecr_php81_apache [Container] 2023/05/12 03:30:12 YAML location is /codebuild/output/src787575457/src/bitbucket.org/refirio/ecr_php81_apache/buildspec.yml [Container] 2023/05/12 03:30:12 No commands found for phase name: install [Container] 2023/05/12 03:30:12 Processing environment variables [Container] 2023/05/12 03:30:12 Selecting 'docker' runtime version '19' based on manual selections... [Container] 2023/05/12 03:30:14 Phase complete: DOWNLOAD_SOURCE State: FAILED [Container] 2023/05/12 03:30:14 Phase context status code: YAML_FILE_ERROR Message: Unknown runtime version named '19' of docker. This build image has the following versions: 20
buildspec.ymlで「runtime-versions」を「docker: 19」から「docker: 20」に修正

Advertisement