M.

Artifact Registry が86GBに膨らんだ(「30日より古いものを削除」が効かない理由とクリーンアップポリシー)

  • GCP
  • Cloud Run
  • Artifact Registry
  • コスト削減

GCP の Artifact Registry に クリーンアップポリシーを入れたのに、2週間後には容量が元に戻っていました。

ポリシーの「30日より古いイメージを削除する」という条件が、ビルドの頻度に対して長すぎたのが原因です。保持件数を基準にしたポリシーに見直したところ、ようやく容量が落ち着きました。

前提:画像生成 Web アプリ Moeter の GPU ワーカーを Cloud Run(GPU)で動かしています。イメージは Cloud Build でビルドし、Artifact Registry に置いています。

最初の状態

9月半ばに確認したとき、この GCP プロジェクトのストレージは次のようになっていました。

  • Artifact Registry:82GB
  • Cloud Storage:78GB

Artifact Registry の保存料金は、無料枠(0.5GB)を超えた分が1GBあたり月 $0.10 です。82GB なら月 $8 ほどになります。個人開発としては無視できない額です。

そこで、Artifact Registry にクリーンアップポリシー、Cloud Storage にライフサイクルルールを設定しました。「最新5件は残し、30日(バケットによっては7日)より古いものは削除する」という内容です。これで約58GB減りました。

2週間後、86.7GB に戻っていた

月末に請求を見直したところ、Artifact Registry は 86.7GB まで膨らんでいました。最初より増えています。

原因は GPU ワーカーのイメージでした。

  • イメージ1個が11.5GB:画像生成モデル(6.5GB + 1.5GB)をイメージに直接焼き込んでいる
  • 月に8回くらいビルドする:機能追加や調整のたびに再ビルドしてデプロイしている

30日分を残すと、11.5GB × 8回 ≒ 92GB が常に残ります。「30日より古いものを削除」という条件では、削除対象がほとんど出てこない のです。

古いイメージを消すポリシーを入れていても、ビルドの頻度とイメージのサイズによっては何も消えません。期間で区切るなら、「その期間に何回ビルドするか × 1個のサイズ」を見積もる必要がありました。

保持件数を基準にしたポリシーに変える

ポリシーを「最新2件だけ残し、7日より古いものは削除する」に変えました。

[
  {
    "name": "keep-latest-2",
    "action": { "type": "Keep" },
    "mostRecentVersions": { "keepCount": 2 }
  },
  {
    "name": "delete-older-than-7d",
    "action": { "type": "Delete" },
    "condition": { "tagState": "any", "olderThan": "7d" }
  }
]
gcloud artifacts repositories set-cleanup-policies <リポジトリ名> --project=<プロジェクトID> --location=us-central1 --policy=policy.json --no-dry-run

Keep と Delete の両方に当てはまるバージョンは、Keep が優先 されます。最新2件は7日を過ぎても消えないので、稼働中のイメージと、1つ前に戻すためのイメージは残ります。

なお、ポリシーは設定してすぐに実行されるわけではありません。バックグラウンドで定期的に評価されるので、容量が減るまで1日ほどかかります。急ぐ場合は、古いバージョンを手動で消します。

keepCount を小さくしすぎると稼働中のイメージが消える

別のアプリ(こちらは普通の Web アプリ)にも同じポリシーを入れようとして、気づいたことがあります。

そのリポジトリでは、1回のデプロイでタグなしのバージョンが2件、一緒に作られていました。keepCount: 2 にすると、最新のデプロイで作られた付属物だけで2件の枠が埋まり、肝心の稼働中のイメージが削除対象になってしまいます。

こちらは「最新10件を残し、14日より古いものは削除」にしました。keepCount を決める前に、一度リポジトリの中身を一覧して、1回のデプロイで何件のバージョンが増えるかを確認しておくと安全です。

Cloud Build のソースバケットも膨らむ

Artifact Registry と一緒に、Cloud Storage の方も見直しました。

gcloud builds submit や gcloud run deploy --source を使うと、ビルド用のソースが tar にまとめられて、Cloud Storage のバケット(<プロジェクトID>_cloudbuild や run-sources-...)にアップロードされます。このプロジェクトでは 1回のビルドあたり7.3GB ありました。

ビルドが終われば不要なものなので、この2つのバケットはライフサイクルルールで 1日経ったら削除 にしました。

もう1つ注意したいのが ソフトデリート です。Cloud Storage のバケットは、デフォルトで削除したオブジェクトを7日間保持し、その間も保存料金がかかります。1日で消しても、ソフトデリートが有効だと結局7日分の料金がかかります。ビルド用のバケットでは復元する必要もないので、無効にしました。

gcloud storage buckets update gs://<バケット名> --clear-soft-delete

ついでに:使っていない Cloud Run サービス

調べている途中で、実験用に作った GPU の Cloud Run サービスが残っているのを見つけました。イメージも4.7GB 残っていました。

GPU の Cloud Run は、リクエストを処理していない待機時間も含めて、インスタンスが起動している間ずっと課金されます。この実験サービスでは、3日間で合計11時間ほど起動していて、それだけで約 $15 かかっていました。サービスごと削除しました。

まだやっていないこと

根本的な対策は、モデルをイメージに焼き込まず、Cloud Storage に置いて起動時に読み込む構成にすることです。イメージから8GB分が抜けるので、何回ビルドしても容量はあまり増えなくなります。

ただ、起動のたびに8GBのモデルを読み込むことになるので、コールドスタートが遅くなります。利用者の待ち時間に直結するので、今のところは保持件数を絞る対策にとどめています。

まとめ

  • 「N日より古いものを削除」は、ビルド頻度 × イメージサイズ によっては何も消さない。大きなイメージを頻繁にビルドするなら、保持件数(keepCount)を基準にする。
  • keepCount を決める前に、1回のデプロイで何件のバージョンが増えるか を確認する。
  • Cloud Build のソースバケットは短期で削除し、ソフトデリートも無効 にする。

GCP の費用見直し全体の流れは、Claude Code に GCP の課金を棚卸しさせたら、月1万円が半分になった にまとめています。

この記事をシェア

「GCP」の記事(7件)

  1. GCS の画像を Cloudflare Worker で中継してエッジにキャッシュする(バケット名を変えずに独自ドメインで配る)
  2. ▶ Artifact Registry が86GBに膨らんだ(「30日より古いものを削除」が効かない理由とクリーンアップポリシー)
  3. Claude Code に GCP の課金を棚卸しさせたら、月1万円が半分になった(失敗込みの記録)
  4. GCP の予算アラートで Cloud Run の GPU だけを自動停止する(maxInstanceCount: 0 では止まらなかった)
  5. 個人開発の GCP で「やらなかった」コスト削減4つ(e2-small・東京リージョン・Nearline・Standard ティアの保留)
  6. GCP の確約利用割引(CUD)を二重に買ってしまい、サポートに取り消してもらった話
  7. GCP の請求で Networking は ¥0 なのに、VM の通信料がかかっていた(404 の gzip 化と Standard ティア)

テーマから探す