Artifact Registryのクリーンアップポリシーを試してみた

記事タイトルとURLをコピーする

G-gen の藤岡です。当記事では、Google Cloud (旧称 GCP) の Artifact Registry で不要になったイメージを自動削除するクリーンアップポリシーを紹介します。

前提知識

Artifact Registry

Artifact Registry は、コンテナイメージや言語パッケージを保管するサービスです。
単体で使うほかに、Google Cloud のサービス(例 : Cloud Run、Cloud Functions 等)では自動で Artifact Registry にイメージが保管される場合もあります。

保管イメージへの課金

デフォルトでは、Artifact Registry に保管されたイメージは削除しない限り残ります。ストレージ料金は $0.10/GB/月(0.5GB 超えた場合)のため、使い方によってはストレージ料金が肥大化する可能性もあります。
クリーンアップポリシーを使うことで、保管イメージの増加によるストレージ料金の肥大化への対処が自動化できます。

クリーンアップポリシーを使わずに、自前のプログラムで過去のイメージを削除する際は以下の記事をご参照ください。 blog.g-gen.co.jp

クリーンアップポリシー

クリーンアップポリシーとは

クリーンアップポリシー とは、Artifact Registry に保存されたアーティファクト(コンテナイメージ等)を、事前に設定したポリシーにもとづいて自動で削除するための機能です。

2024年4月現在では、Preview (プレビュー) 版として公開されています。

削除ポリシーと保持ポリシー

クリーンアップポリシーでは、削除ポリシー保持ポリシーという2種類のポリシーを定義できます。これらのポリシーはリポジトリに対して設定します。削除ポリシーは削除するイメージの条件を、保持ポリシーは保持するイメージの条件を指定します。(条件については後述)

注意点は、保持ポリシーのみを設定しても、保持対象外のイメージは削除されない点です。削除ポリシーは単体で機能しますが、保持ポリシーは削除ポリシーと組み合わせる必要があります。

例として以下のクリーンアップポリシーが設定されたリポジトリの挙動は、タグの有無は問わず最新の3バージョンを保持し、それ以外のイメージは削除されます。

  • タグの有無を問わずイメージを削除(削除ポリシー)
  • 最新の3バージョンのみを保持(保持ポリシー)

詳細

条件

クリーンアップポリシーの対象となるイメージには以下の条件を設定できます。

  • タグの状態(tagState)※必須条件
  • タグのプレフィックス(tagPrefixes
  • バージョンのプレフィックス(versionNamePrefixes
  • パッケージ名のプレフィックス(packageNamePrefixes
  • アップロードされてからの期間(olderThan / newerThan
  • 保持するバージョン数(keepCount)※保持ポリシーでのみ設定可能

制約

クリーンアップポリシーには以下の制約があります。

  • クリーンアップポリシーによる削除と保持がトリガーされるのは、1回/日
  • 削除ポリシーによってトリガーされる削除は、リポジトリごとに最大300,000件/日
  • リポジトリあたりのクリーンアップポリシー数は10

ドライラン

クリーンアップポリシーにはドライランモードがあります。

挙動は Cloud Logging で確認できます(ドライランのためリソースに変化はない)。このログはデータアクセス監査ログとして記録されますが、デフォルトではデータアクセス監査ログが有効になっていません。

そのためドライランの結果を確認するには、Artifact Registry API のデータアクセス監査ログで データ書き込み を有効にします。

Terraform 対応

クリーンアップポリシーは Terraform の google_artifact_registry_repository リソースでサポートされています。

適用方法

前提

ここでは、前述の例で挙げた「タグの有無は問わず最新の3バージョンを保持し、それ以外のイメージは削除する」クリーンアップポリシーを適用します。

リポジトリの作成

任意のリポジトリを作成します。

fujioka@cloudshell:~ (XXX)$ gcloud artifacts repositories create test-repo \
    --repository-format=docker \
    --location=asia-northeast1
Create request issued for: [test-repo]
Waiting for operation [projects/XXX/locations/asia-northeast1/operations/31e7a62e-11aa-4a0e-8b7a-90e0ccdbd461] to complete...done.                                                                                                                                 
Created repository [test-repo].
fujioka@cloudshell:~ (XXX)$ 

ポリシーファイルの用意

クリーンアップポリシーはコンソールからも設定できますが、JSON ファイルを作成し、コマンドラインからも実行できます。ここでは以下の policy.json という JSON ファイルを用意します。

[
    {
      "name": "delete-any",
      "action": {"type": "Delete"},
      "condition": {
        "tagState": "any"
      }
    },
    {
      "name": "keep-latest-3",
      "action": {"type": "Keep"},
      "mostRecentVersions": {
        "keepCount": 3
      }
    }
]

クリーンアップポリシーの設定(ドライラン)

ドライランで適用します。

fujioka@cloudshell:~ (XXX)$ gcloud artifacts repositories set-cleanup-policies test-repo \
    --location=asia-northeast1 \
    --policy=policy.json \
    --dry-run
Updated repository [test-repo].
Dry run is enabled.
[
  {
    "action": {
      "type": "DELETE"
    },
    "condition": {
      "tagState": "ANY"
    },
    "name": "delete-any"
  },
  {
    "action": {
      "type": "KEEP"
    },
    "mostRecentVersions": {
      "keepCount": 3
    },
    "name": "keep-latest-3"
  }
]
fujioka@cloudshell:~ (XXX)$ 

コンソールでは、以下のように表示されます。

イメージのプッシュ

任意のイメージをプッシュし、5つのイメージが保存されている状態にします。

ログの確認

ドライランモード(protoPayload.request.validateOnly)で実行された結果が出力されます。
今回は「タグの有無は問わず最新の3バージョンを保持し、それ以外のイメージは削除する」クリーンアップポリシーを適用しました。
実際のリソースとしては5つのイメージがリポジトリにある状態のため、削除対象として2つのイメージが記録されています(protoPayload.request.names)。

{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "service-00000000000@gcp-sa-artifactregistry.iam.gserviceaccount.com"
    },
    "requestMetadata": {
      "callerIp": "private",
      "callerSuppliedUserAgent": "stubby_client",
      "requestAttributes": {
        "time": "2024-04-02T07:27:58.171276147Z",
        "auth": {}
      },
      "destinationAttributes": {}
    },
    "serviceName": "artifactregistry.googleapis.com",
    "methodName": "google.devtools.artifactregistry.v1.ArtifactRegistry.BatchDeleteVersions",
    "authorizationInfo": [
      {
        "resource": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
        "permission": "artifactregistry.versions.delete",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
    "request": {
      "parent": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
      "validateOnly": true,
      "@type": "type.googleapis.com/google.devtools.artifactregistry.v1.BatchDeleteVersionsRequest",
      "names": [
        "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/hello-world/versions/sha256:5d0cc9349f2e675542decde8be21c94264714a7ece91fefdb4f722b18c544510",
        "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/hello-world/versions/sha256:cb1a3c1190265153e7b50ccfde70e3683eba5326cfae8ac68632e1a6b9985573"
      ]
    }
  },
  "insertId": "1ndsju6d19n5",
  "resource": {
    "type": "audited_resource",
    "labels": {
      "project_id": "XXXXXX",
      "method": "google.devtools.artifactregistry.v1.ArtifactRegistry.BatchDeleteVersions",
      "service": "artifactregistry.googleapis.com"
    }
  },
  "timestamp": "2024-04-02T07:27:58.162187524Z",
  "severity": "INFO",
  "logName": "projects/XXXXXX/logs/cloudaudit.googleapis.com%2Fdata_access",
  "operation": {
    "id": "projects/XXXXXX/locations/asia-northeast1/operations/29bfca3e-4a01-4895-8840-b7dfd92ad07c",
    "producer": "artifactregistry.googleapis.com",
    "first": true
  },
  "receiveTimestamp": "2024-04-02T07:27:58.429334137Z"
}

実行

ドライランモードではなく実際に削除まで行う場合は、コマンドラインで --no-dry-run をつける、またはコンソールから アーティファクトを削除 を選択します。

結果の確認

クリーンアップポリシーに従い、2つのイメージが削除されました。

{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "service-00000000000@gcp-sa-artifactregistry.iam.gserviceaccount.com"
    },
    "requestMetadata": {
      "callerIp": "private",
      "callerSuppliedUserAgent": "stubby_client",
      "requestAttributes": {
        "time": "2024-04-02T13:28:08.653796809Z",
        "auth": {}
      },
      "destinationAttributes": {}
    },
    "serviceName": "artifactregistry.googleapis.com",
    "methodName": "google.devtools.artifactregistry.v1.ArtifactRegistry.BatchDeleteVersions",
    "authorizationInfo": [
      {
        "resource": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
        "permission": "artifactregistry.versions.delete",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
    "request": {
      "parent": "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/-",
      "names": [
        "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/hello-world/versions/sha256:5d0cc9349f2e675542decde8be21c94264714a7ece91fefdb4f722b18c544510",
        "projects/XXXXXX/locations/asia-northeast1/repositories/test-repo/packages/hello-world/versions/sha256:cb1a3c1190265153e7b50ccfde70e3683eba5326cfae8ac68632e1a6b9985573"
      ],
      "@type": "type.googleapis.com/google.devtools.artifactregistry.v1.BatchDeleteVersionsRequest"
    }
  },
  "insertId": "1h9vo9pcafo",
  "resource": {
    "type": "audited_resource",
    "labels": {
      "service": "artifactregistry.googleapis.com",
      "project_id": "XXXXXX",
      "method": "google.devtools.artifactregistry.v1.ArtifactRegistry.BatchDeleteVersions"
    }
  },
  "timestamp": "2024-04-02T13:28:08.644978076Z",
  "severity": "INFO",
  "logName": "projects/XXXXXX/logs/cloudaudit.googleapis.com%2Fdata_access",
  "operation": {
    "id": "projects/XXXXXX/locations/asia-northeast1/operations/7ba5387a-1dda-4390-9a4c-d100313f1c18",
    "producer": "artifactregistry.googleapis.com",
    "first": true
  },
  "receiveTimestamp": "2024-04-02T13:28:08.883393539Z"
}

藤岡 里美 (記事一覧)

クラウドソリューション部

数年前までチキン売ったりドレスショップで働いてました!2022年9月 G-gen にジョイン。ハイキューの映画を4回は見に行きたい。

Google Cloud All Certifications Engineer / Google Cloud Partner Top Engineer 2024