G-gen の武井です。組織のポリシーでリソースロケーションに制約のあるプロジェクトで gcloud builds submit (Cloud Build のビルドコマンド)
を実行したところ、HTTPError 412
エラーが出力され Docker イメージのビルドに失敗する事象が起きました。
当記事では、事象の原因と対策をご紹介します。
事象
構成
今回問題のあった環境は、組織 example.co.jp
のツリー構造に属するプロジェクトの一つです。
組織レベルで constraints/gcp.resourceLocations
を下図のように設定し、組織全体でリソースロケーションを東京リージョン (asia-northeast1)
と大阪リージョン (asia-northeast2)
に制限しています。
- 参考 : リソース ロケーションの制限
- 参考 : 組織のポリシーを解説 - G-gen Tech Blog
実行内容
以下のソースコードを用いて gcloud builds submit
コマンドを以下の通り実行したところエラーが発生しました。
この際、API の有効化、Cloud SDK の認証、ならびに実行ユーザーや Cloud Build サービスアカウントの IAM 設定等に不備はありませんでした。
- 参考 : gcloud builds submit
- 参考 : コンテナ イメージをビルドします
- 参考 : サービスの有効化と無効化
- 参考 : Cloud Build サービス アカウント
- 参考 : gcloud auth loginとgcloud auth application-default loginの違いとは? - G-gen Tech Blog
# ソースコード一覧 $ tree . ├── image_build.sh └── source ├── cloudbuild.yaml ├── Dockerfile ├── go.mod ├── go.sum └── main.go
# image_build.sh #!/bin/bash # 変数定義 project_id=$(gcloud config get-value project) location="asia-northeast1" repository_name="image-build-test" image_name="test" # APIがまだ有効でない場合はチェックして有効化する services=( artifactregistry.googleapis.com cloudbuild.googleapis.com ) for service in "${services[@]}"; do if gcloud services list --enabled --filter="name:${service}" --format="value(name)" | grep "${service}"; then echo "Service ${service} is already enabled." else echo "Enabling service ${service}..." gcloud services enable "${service}" fi done # コンテナイメージ用のリポジトリを確認 if gcloud artifacts repositories describe "$repository_name" --location=$location &>/dev/null; then echo "Artifact repository $repository_name already exists, skipping creation." else # 存在しない場合は作成 gcloud artifacts repositories create "$repository_name" \ --location $location \ --repository-format "docker" echo "Artifact repository $repository_name created." fi # イメージビルド gcloud builds submit ./source \ --config=./source/cloudbuild.yaml \ --region=$location \ --substitutions=_LOCATION=$location,_REPOSITORY=$repository_name,_IMAGE=$image_name
# cloudbuild.yaml # 変数は`image_build.sh`の`gcloud builds submit --substitutions`から動的に渡される steps: - id: docker build and push name: 'gcr.io/cloud-builders/docker' args: [ 'build', '-t', '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}:latest', '.' ] images: - '${_LOCATION}-docker.pkg.dev/$PROJECT_ID/${_REPOSITORY}/${_IMAGE}:latest'
# Dockerfile # Goのバージョン1.22.2を使用 FROM golang:1.22.2 as builder # 作業ディレクトリの設定 WORKDIR /app # 依存関係のコピーとダウンロード COPY go.mod go.sum ./ RUN go mod download # ソースコードのコピー COPY main.go ./ # アプリケーションのビルド RUN CGO_ENABLED=0 GOOS=linux go build -o main . # 実行環境の設定 # Distroless base image を使用 FROM gcr.io/distroless/base-debian10 WORKDIR / # ビルドしたバイナリを実行環境にコピー COPY --from=builder /app/main . # コンテナ起動時のコマンド CMD ["/main"]
エラーの詳細
エラーメッセージは ERROR: (gcloud.builds.submit) HTTPError 412: 'us' violates constraint 'constraints/gcp.resourceLocations'
でした。出力の詳細は以下のとおりです。
# 実行ログ $ ./image_build.sh Your active configuration is: [cloudshell-1976] projects/111111111111/services/artifactregistry.googleapis.com Service artifactregistry.googleapis.com is already enabled. projects/111111111111/services/cloudbuild.googleapis.com Service cloudbuild.googleapis.com is already enabled. Artifact repository image-build-test already exists, skipping creation. ERROR: (gcloud.builds.submit) HTTPError 412: 'us' violates constraint 'constraints/gcp.resourceLocations'
原因
調査
'us' violates
と示されていることから、gcloud builds submit
コマンド実行時に何らかのリソースが US マルチリージョン に作成されようとした結果、エラーが発生したのではないかと推察しました。
判明した原因
以下の公式ドキュメントを確認したところ、以下のような記載がありました。
Cloud Build はデフォルトで、ビルドを実行するロケーションとは異なる Google 指定リージョンにビルドログを保存します。
つまり、US マルチリージョンにビルド実行ログ保存用の Cloud Storage バケットを作成しようとした際、リソースロケーションの制約に違反してエラーが発生したことがわかりました。
対処法
gcloud builds submit
コマンドに --default-buckets-behavior="regional-user-owned-bucket"
を付与して実行します。
これにより、ビルドログ保存先リージョンを US からビルド実行先 (今回で言えば東京リージョン) に変更してリソースロケーションの制約を回避します。
# image_build.sh (修正後、gcloud builds submit 部分のみ記載) gcloud builds submit ./source \ --config=./source/cloudbuild.yaml \ --default-buckets-behavior="regional-user-owned-bucket" \ --region=$location \ --substitutions=_LOCATION=$location,_REPOSITORY=$repository_name,_IMAGE=$image_name
# 実行ログ (image_build.sh 修正後) $ ./image_build.sh Your active configuration is: [cloudshell-772] projects/111111111111/services/artifactregistry.googleapis.com Service artifactregistry.googleapis.com is already enabled. projects/111111111111/services/cloudbuild.googleapis.com Service cloudbuild.googleapis.com is already enabled. Artifact repository image-build-test already exists, skipping creation. Creating temporary archive of 5 file(s) totalling 19.7 KiB before compression. Uploading tarball of [./source] to [gs://yutakei-test-prj_asia-northeast1_cloudbuild/source/1714488853.161679-ce5f2b25b04146be8f8bd54f8d053851.tgz] Created [https://cloudbuild.googleapis.com/v1/projects/yutakei-test-prj/locations/asia-northeast1/builds/48b469e7-243e-4fc6-b490-ec43c1403414]. Logs are available at [ https://console.cloud.google.com/cloud-build/builds;region=asia-northeast1/48b469e7-243e-4fc6-b490-ec43c1403414?project=111111111111 ]. Waiting for build to complete. Polling interval: 1 second(s). ------------------------------------------------------------------ REMOTE BUILD OUTPUT ------------------------------------------------------------------ starting build "48b469e7-243e-4fc6-b490-ec43c1403414" ※ 途中省略 Step 10/10 : CMD ["/main"] Running in dae2b25a7765 Removing intermediate container dae2b25a7765 2b7d07a95edc Successfully built 2b7d07a95edc Successfully tagged asia-northeast1-docker.pkg.dev/yutakei-test-prj/image-build-test/test:latest PUSH Pushing asia-northeast1-docker.pkg.dev/yutakei-test-prj/image-build-test/test:latest The push refers to repository [asia-northeast1-docker.pkg.dev/yutakei-test-prj/image-build-test/test] 89648652935c: Preparing 91f7bcfdfda8: Preparing 05ef21d76315: Preparing 91f7bcfdfda8: Layer already exists 05ef21d76315: Layer already exists 89648652935c: Pushed latest: digest: sha256:03a23554f16b2ed46c7125d6eafbce97e8d7582a4a29d3c8d759891c58174f49 size: 950 DONE --------------------------------------------------------------------------------------------------------------------------------------------------------- ID: 48b469e7-243e-4fc6-b490-ec43c1403414 CREATE_TIME: 2024-04-30T14:54:14+00:00 DURATION: 2M1S SOURCE: gs://yutakei-test-prj_asia-northeast1_cloudbuild/source/1714488853.161679-ce5f2b25b04146be8f8bd54f8d053851.tgz IMAGES: asia-northeast1-docker.pkg.dev/yutakei-test-prj/image-build-test/test (+1 more) STATUS: SUCCESS
その他
今回記事にしたCloud Build ですが、サービスアカウントとして使われていた <PROJECT_NUMBER>@cloudbuild.gserviceaccount.com
の仕様が2024年4月29日から変更されます。
詳しくは当社の記事で解説しています。ぜひご確認ください。
武井 祐介 (記事一覧)
クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア
Google Cloud Partner Top Engineer 2025 選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。
趣味はロードバイク、ロードレースやサッカー観戦です。
Follow @ggenyutakei