Zenn Tech Blog
😊

gcr-cleanerを使ってビルドついでにArtifact Registryの古いイメージを削除する

2023/03/31に公開

ふだんの開発では、Ruby on Rails のアプリをコンテナイメージとしてビルドし、それを Cloud Run へデプロイして動かしています。イメージへはタグをつけており、デプロイのたびに新しく生成されます。こうなるとイメージの数がおおくなり、保管料が無視できなくなってきます。


Artifact Registry の料金 - Storage https://cloud.google.com/artifact-registry/pricing?hl=ja#storage

おおよそ100GB程度使っており、それでも$10なのでまだ慌てる時間ではないですが、節約できるものは積極的に削りましょう。

gcr-cleanerを Cloud Build で実行する

Artifact Registry のコンテナイメージを削除するには大きくふたつ選択肢があります。

  • リポジトリのクリーンアップポリシーでライフタイムサイクルを設定する
  • gcr-cleaner で削除する

こちらのスクラップで言及(というかほぼ完結)しています。

https://zenn.dev/catnose99/scraps/0d18ca2fe55241

この記事でも「10個だけ残してあとは削除」ということをやりたいたいめ、gcr-cleaner で消すことにします。

イメージをビルドするトリガーに混ぜる

gcr-cleaner を実行するとして、すでにあるビルドに混ぜるか、新しくトリガーを作るか迷うところですが、すでにあるビルドに混ぜるのがオススメです。私たちが運用しているビルドでは、Cloud Runへのデプロイのために コンテナイメージのビルドと Artifact Registry へのプッシュを行っています。この状況だと、

  • サービスアカウントの権限設定をひとつ追加すればOK
  • イメージ名も指定しやすい
  • ビルドイメージのプッシュとセットで実行されるため、確実にイメージがプッシュされたあとにクリーンアップを実行できる

という条件が揃っており、実現までの作業が少なく済みます。Cloud Build のサービスアカウントに、「Artifact Registry 管理者」のロールを追加してください。

Artifact Registry のリポジトリとCloud Buildのプロジェクトが異なる場合

補足です。プロジェクトによっては、Artifact Registry のリポジトリをひとつのプロジェクトで一元管理するシーンもあるかと思います。その場合は、Artifact Registry のリポジトリに対して、許可するIAMを設定することになります。Terraformの例ですが、以下のようにします。

# Artifact Registry リポジトリ
resource "google_artifact_registry_repository" "app" {
  provider   = google-beta
  project       = var.gcp_project_id
  location      = var.artifact_registry_location
  repository_id = "app"
  description   = "アプリケーション"
  format        = "DOCKER"
}

# 別プロジェクトの Cloud Build からのアクセスを許可する。
resource "google_artifact_registry_repository_iam_binding" "binding_builder" {
  provider   = google-beta
  project    = var.gcp_project_id
  location   = var.artifact_registry_location
  repository = google_artifact_registry_repository.app.name
  role       = "roles/artifactregistry.repoAdmin"   # Cloud Build から削除できるようにここをrepoAdminとする
  members = [
    # CloudBuildのサービスアカウントを指定する
    "serviceAccount:xxxxxxxxxxxxxxx@cloudbuild.gserviceaccount.com",
  ]
}

-dry-run で試す

イメージが消えることに対して不安がある場合、-dry-runオプションで削除対象をリストアップするのみに留めるよう、オプションを指定できます。早速試します。

cloudbuild.yml
- id: build-app # コンテナイメージのビルド
- id: push-app  # コンテナイメージのプッシュ
- id: deploy-app # Cloud Run へのデプロイ
- id: clean-backend-images
    name: asia-docker.pkg.dev/gcr-cleaner/gcr-cleaner/gcr-cleaner-cli:latest
    args:
      - -repo
      - $_ARTIFACT_REPOSITORY_IMAGE_NAME
      - -keep
      - "10"
      - -tag-filter-any
      - "^v.*" # v1.1.234 のように、vの文字列から始まるタグを含むイメージのみ
      - -dry-run # これを指定
    waitFor: ["deploy-app"]
substitutions:
  _ARTIFACT_REPOSITORY_IMAGE_NAME: us-central1-docker.pkg.dev/${PROJECT_ID}/apps/backend-app

トリガーを実行してみた様子です。

vからはじまるイメージ以外も削除されるように見えますが、これはv1.101に対応するハッシュも検出されているだけです。どちらも同じイメージを指していますので、問題なく-tag-filter-anyで指定したものだけが消えます。

実際に消す

対象が合ってそうならば、-dry-runのオプションを外すことでイメージが削除されます。

まとめ

gcr-cleanerを Cloud Build で実行することは、以下のメリットがあります。

  • ライフサイクルポリシーではなく「10個イメージを残してあとは削除」のように現実に則した指定ができる
  • Cloud Build でイメージをビルド・プッシュする処理に混ぜることで、権限設定やイメージ名を指定する手間を省く

ひとつステップを追加することでストレージ料金の節約になりますので、ぜひお試しください。

Zenn Tech Blog
Zenn Tech Blog

Discussion