Open15

Google Cloud Platform (GCP)作業ログ

ArkBigArkBig

Cloud Runを使った。Rustで開発するため、FunctionsではなくRunを選択しました。Dockerは経験あるのでとりあえず動かす分には簡単にできてすげーって思いました。
パブリッククラウドだとセキュリティ設定ミスでの情報漏洩がニュースで見るでそのあたり少し触るかと思って、サービスアカウントを作ってみたら初心者には難しかった。

ArkBigArkBig

Cloud Buildでサービスアカウントを指定して実行すると次のエラーメッセージが表示されます。

不正解の対応
なるほどよくわからんけど、サービスアカウントにそれっぽい権限をつけてみたけどダメでした。
Cloud Build/ユーザー指定のサービス アカウントの構成
そもそもブラウザ上でIAM設定してると、ここに書かれている権限はどれに該当するんだろう?となりました。部分的に翻訳されてるのでよくわからん。ということでコマンドで実行して権限を付与することにしました。幸いブラウザ上でもCloud Shellが起動できて便利。

gcloud projects add-iam-policy-binding $PROJECT_NAME --member $SERVICE_ACCOUNT --role $ROLE) gcloud projects add-iam-policy-binding zenn-news-project --member serviceAccount:zenn-news-serviceaccount@zenn-news-project.iam.gserviceaccount.com --role roles/iam.serviceAccountUser

正解の対応
エラーメッセージはログの保存方法を指定する必要があることを説明してくれてました。ブラウザでの設定ではなく、Cloud Build構成ファイルに記載が必要なようです。
Cloud Build/ビルドログの保存と管理
構成 > 自動検出にしてDockerfileを検出してもらってますが、cloudbuild.yamlで指定するみたい。Cloud Build 構成ファイル(yamlまたはjson)を選択して、インラインにするとブラウザ上で設定できました。

steps:
- name: 'gcr.io/cloud-builders/docker'
  args: [ 'build', '-t', 'us-west1-docker.pkg.dev/$PROJECT_ID/zenn-news-artifact/zenn-news-image:latest', '.' ]
images:
- 'us-west1-docker.pkg.dev/$PROJECT_ID/zenn-news-artifact/zenn-news-image:latest'

timeout: 500s
options:
  logging: CLOUD_LOGGING_ONLY #サービスアカウントを指定するので、ログ保存先を制限

とりあえず、(b)の方法をとることにしました。
ただし保存するとDockerになってオプション設定は見えないところに保存されているようです。再度Cloud Build 構成ファイルのインラインからエディタを起動しても、デフォルトの設定が表示されるだけなのでcloudbuild.yamlファイルをリポジトリにおくほうが良さそうです。

ArkBigArkBig

IAM APIの有効化

::message alert
ビルドをトリガーできませんでした: generic::permission_denied: generic::permission_denied: Identity and Access Management (IAM) API has not been used in project 12345 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=12345 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
(超訳> IAM APIが使えないので、有効化してね)
:::

このエラーが出たら指定のURLにアクセスしてIAM APIを有効化します。IAMが見れてるから有効化されてるかと思ってたけど、APIはまた別なようです。

ArkBigArkBig

リージョン問題

Artifact Registryと同じリージョンを使おうとしたけど、混雑してるのかビルドできませんでした。グローバル(非リージョン)にすることで解消。GitHubリポジトリとの連携もリージョン設定ごとに必要なので、違うリージョン使うときは紛らわしいのでトリガーとリポジトリ連携を消してから切り替えた方がいいかも。そのために命名規則で設定リージョンを含めるようにするのもあるか。
リージョンが違うと通信量が発生しそうな気がするけど、少量だから大丈夫だろうか。

ArkBigArkBig

ビルド開始ができるようになりましたが、履歴をみるとエラーが確認できます。

サービスアカウントの権限

必要な IAM 権限

「ログ書き込み(roles/logging.logWriter)」権限を付与する

gcloud projects add-iam-policy-binding zenn-news-project --member serviceAccount:zenn-news-serviceaccount@zenn-news-project.iam.gserviceaccount.com --role roles/logging.logWriter

「Artifact Registry 書き込み(roles/artifactregistry.writer)」権限を付与する

gcloud projects add-iam-policy-binding zenn-news-project --member serviceAccount:zenn-news-serviceaccount@zenn-news-project.iam.gserviceaccount.com --role roles/artifactregistry.writer

とりあえずこの2つの権限だけで、Cloud Buildは成功して、Artifact Registryにイメージが登録されました。

ArkBigArkBig

Cloud Buildをデフォルトで使うと、Container Registryが使われます。管理画面にアクセスすると脆弱性診断してくれるみたいだ、やった。と思ってContainer Scanning APIを有効にしました。
Google Container Registryの脆弱性スキャンが有料になるよ
Container Analysis の料金/脆弱性スキャン
なんだってー。1スキャン$0.26。仕事ならまだしも趣味レベルだとドキドキする値段だったから無効に戻した。

またCloud Registryは重要なセキュリティ修正のみになるので、今後はArtifact Registryへ移行するのがいいらしい。Cloud Buildの構成ファイルを試すときに移行してみよう。

ArkBigArkBig

Cloud Run

Cloud Run画面から「継続的デプロイの設定」をすると、Container Registryが使われる設定のCloud Buildが作成されます(2022-12-15現在)。今のところArtifact Registryを使用するためには、自分でCloud Build構成ファイルを書く必要があるようです。

ArkBigArkBig

Cloud Build Configuration File

Cloud Build構成ファイルcloudbuild.yamlの変数置換について
変数値の置換

images:
- $_IMAGE #substitutionsで定義したもの(もしくはコマンド引数で指定したもの)になる
substitutions:
  #ここでの変数置換は`${〜}`で囲む必要がある
  _IMAGE: us-west1-docker.pkg.dev/${PROJECT_ID}/zenn-news-artifact/zenn-news-image:${COMMIT_SHA}
options:
  dynamic_substitutions: true #substitutionsで変数置換できるようにする

トリガーで実行されると自動でALLOW_LOOSEオプションが設定されて、置換できないときにエラーになります。
substitutionsで他の変数で置換したいなら、dynamic_substitutionsオプションを有効にし、${〜}で囲んで参照します。
ちなみにユーザー定義変数はアンダースコア始まるにする必要があるようです。

ArkBigArkBig

Cloud Buildのログがinfoだけど、ERRORが出てました。

エラーでた設定↓

steps:
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  args: [ 'run', 'deploy', 'zenn-news-run', '--image', '$_IMAGE', '--region', 'us-west1' ]

name: 'gcr.io/cloud-builders/docker'と違って、cloud-sdkはエントリーポイントが指定されてないようです。
entrypoint: gcloudを追加するか、args: [ 'gcloud', 'run', ... ]と第一引数で指定が必要でした。

ArkBigArkBig

「Cloud Run 管理者(roles/run.admin)」権限を付与。

ArkBigArkBig

FirestoreをAPI経由で使う。

Cloud ConsoleからFirestoreデータベース作ろうとしたけど、なぜかインスタンスの作成が求められてとても高価になってしまう。

それで仕方なく、Firebaseのプロジェクトを作ってそっちからFirestoreのデータベースを作って試してた。

OAuth を使用しないサービス アカウントの認証

JWTを使った認証でAPI呼び出ししてみますが、

このエラーで拒否されてしまいます。

結局、Firebaseでプロジェクトを作ったら、GCP側にも同じ名前のプロジェクトが作られていて、使用するサービスアカウントはそちらのものを使用する必要がありました。(プロジェクト間で共有できる設定もありそうだけど)

このプロジェクトが作られるということに気づいて、Cloud ConsoleのFirestore画面のリンクからだと表示されることに気づいて、ようやくスクショの画面に気づいた。

FirestoreとFilestore

このスクショ撮るまでFirestoreが2つあるんだーとか思ったら、Filestoreを使おうとしてたみたいだ。アールとエルの発音じゃなくて目視なのに完全にFireと思い込んでたよ。

改めて、元々のGCPプロジェクトでFirestoreデータベースを作ってテストすると、「Cloud Datastore ユーザー(roles/datastore.user)」権限付与でAPI呼び出しがようやく成功しました。

ArkBigArkBig

このトラブルのため、監査ログログエクスプローラーも少し勉強できました。
「IAMと管理 > 監査ログ」でFirestoreのアクセスをログとるように設定し、「ロギング > ログエクスプローラー」の監査対象リソースでログが見れる。
最初はこれも別プロジェクトのFirestoreだったからログされてなくて悩んだ。

ArkBigArkBig

Cloud BuildでBuildKitを有効にするには、cloudbuild.yamlでDOCKER_BUILDKIT環境変数を設定する必要がある。

cloudbuild.yaml
  - name: "gcr.io/cloud-builders/docker"
    env:
      - DOCKER_BUILDKIT=1
    args: ["build", "-t", "$_IMAGE", "."]
    timeout: 500s

これがないとCOPYに--chmod使ってると、下記エラーが出る。

the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled
ArkBigArkBig

Cloud BuildでたくさんデプロイしてたらArtifact Registryの容量が大変なことになってました。過去のも全て保存されていて、7GBオーバー。これでは無料枠超えてしまってます。
ということで、Cloud Buildで古いイメージを削除するようにしました。

steps:
  - name: "gcr.io/google.com/cloudsdktool/cloud-sdk"
    # delete old images
    args:
      - bash
      - -c
      - |
        gcloud artifacts docker images list ${_IMAGE_NAME} --include-tags --filter='TAGS!~latest' --format='value(DIGEST)' | xargs -n1 -I '{}' gcloud artifacts docker images delete --quiet --async --delete-tags ${_IMAGE_NAME}@'{}'
    allow_failure: true
  - name: "gcr.io/cloud-builders/docker"
    env:
      - DOCKER_BUILDKIT=1
    args: ["build", "-t", "${_IMAGE_NAME}:latest", "-t", "$_IMAGE", "."]
    timeout: 500s
  - name: "gcr.io/cloud-builders/docker"
    args: ["push", "-a", "${_IMAGE_NAME}"]
 :
substitutions:
  _IMAGE_NAME: us-west1-docker.pkg.dev/${PROJECT_ID}/zenn-news-artifact/zenn-news-image
  _IMAGE: ${_IMAGE_NAME}:${COMMIT_SHA}
options:
  dynamic_substitutions: true

gcloud artifacts docker images list"TAGS!=latest"なものをリストアップして、gcloud artifacts docker images deleteで削除しています。
最新のイメージをpushする前に実行しているので、最大2つのイメージが保存されるようになりました。そして無事500MB以下に収まりました。

もし権限が「Artifact Registry 書き込み(roles/artifactregistry.writer)」を設定していたら「Artifact Registry リポジトリ管理者(roles/artifactregistry.repoAdmin)」に変更して削除もできるようにします。