このドキュメントでは、イメージ ダイジェストの概要とその検索方法、Kubernetes クラスタでの使用を適用する方法について説明します。このドキュメントは、コンテナ イメージをビルドしてデプロイするデベロッパーとオペレーターを対象としています。
コンテナ イメージ ダイジェストはコンテナ イメージを一意かつ不変的に識別します。ダイジェストを使用してイメージをデプロイすると、イメージタグでデプロイする際のデメリットを回避できます。
このドキュメントのコマンドは、Google Cloud CLI、Docker、cURL、jq
、pack
などのツールがインストールされている Linux または macOS のシェル環境にアクセスできることを前提としています。これらのツールがプリインストールされている Cloud Shell を使用することもできます。
コンテナ イメージとイメージタグ
コンテナ イメージを操作するには、使用するイメージを参照する必要があります。イメージの異なるリビジョンを参照する方法としては、イメージタグを使用するのが一般的です。通常は、ビルド時にバージョン ID をタグとしてイメージに割り当てます。たとえば、v1.0.1
はバージョン 1.0.1
を表します。
タグを使用すると、人が読み取れる文字列を使用してイメージを検索できるようになります。ただし、タグは変更可能な参照で、下の図に示すように、タグで参照されるイメージが変更される可能性があります。
上の図のように、既存のイメージと同じタグを使用して新しいイメージを公開すると、タグは既存のイメージを参照せず、新しいイメージを参照するようになります。
イメージタグのデメリット
タグの参照先が変わる可能性があるため、イメージをデプロイする際に次のようなデメリットがあります。
Kubernetes でタグを使用してデプロイすると、予期しない結果が生じることがあります。たとえば、タグ
v1.0.1
でコンテナ イメージを参照する既存の Deployment リソースがあるとします。バグの修正や軽微な変更を行うと、ビルドプロセスで同じタグv1.0.1
を持つ新しいイメージが作成されます。Deployment のリソース仕様を変更しない場合でも、Deployment リソースから新しい Pod を作成するときに古いイメージではなく、新しいイメージが使用される可能性があります。この問題は、StatefulSet、DaemonSets、ReplicaSet、Jobs などの他の Kubernetes リソースにも適用されます。ツールを使用してイメージをスキャンまたは分析する場合、これらのツールの結果はスキャンされたイメージに対してのみ有効です。タグで参照されるイメージは変更される可能性があるため、スキャンされたイメージをデプロイするときにタグに依存することはできません。
Google Kubernetes Engine(GKE)で Binary Authorization を使用する場合、Pod の作成時に使用される正確なイメージを特定できないため、タグベースの Deployment は許可されません。
イメージ ダイジェストを使用してイメージをデプロイすると、このようなタグのデメリットを回避できます。イメージにタグを追加することも可能ですが、このような操作を行う必要はありません。
イメージの構造
イメージは次のコンポーネントで構成されます。
- イメージ マニフェスト
- 構成オブジェクト
- 1 つ以上のファイル システム レイヤの配列
- オプションのイメージ インデックス
次の図に、これらのコンポーネントを示します。
この図には、イメージ コンポーネントの詳細が示されています。
- イメージ マニフェストは、構成オブジェクト、ファイル システム レイヤ、オプションのメタデータへの参照を含む JSON ドキュメントです。
- イメージ マニフェストは、
digest
属性を使用して、構成オブジェクトと各ファイル システム レイヤを参照します。digest
属性の値は、ダイジェストが参照するコンテンツの暗号ハッシュで、通常は SHA-256 アルゴリズムを使用して計算されます。 - ダイジェスト値は、オブジェクトに対する不変のアドレスを作成するために使用されます。このプロセスはコンテンツのアドレス指定が可能なストレージと呼ばれ、ダイジェストに基づいてイメージ マニフェスト、イメージ インデックス、構成オブジェクト、レイヤを取得できます。
- イメージ ダイジェストは、イメージ インデックスまたはイメージ マニフェスト JSON ドキュメントのハッシュです。
- 構成オブジェクトは、CPU アーキテクチャ、エントリポイント、公開されたポート、環境変数など、イメージのプロパティを定義する JSON ドキュメントです。
- ファイル システム レイヤの配列は、コンテナ ランタイムがレイヤのスタックに使用する順序を定義します。これらのレイヤは通常、
gzip
ユーティリティで圧縮された tar ファイルとして配布されます。 - オプションのイメージ インデックス(マニフェスト リストとも呼ばれます)は、1 つ以上のイメージ マニフェストを参照します。この参照は、イメージ マニフェストのダイジェストになります。イメージ インデックスは、さまざまなプラットフォーム(
amd64
やarm64
などのアーキテクチャ)に対して複数の関連イメージを生成する場合に便利です。
詳細については、イメージ マニフェスト、ダイジェスト、タグの確認をご覧ください。
イメージ ダイジェストの検索
デプロイでイメージ ダイジェストを使用するには、最初にダイジェストを見つける必要があります。その後、デプロイ コマンドでダイジェストを使用するか、Kubernetes マニフェストにダイジェストを追加します。
イメージ ダイジェストは、現在の状況に応じて、さまざまな方法で取得できます。以降のセクションでは、さまざまなプロダクトやツールの使用例を紹介します。
これらセクションでは、Cloud Shell か、gcloud CLI、Docker、cURL、jq
などのツールがインストールされているシェル環境でコマンドを実行します。
Artifact Registry
Artifact Registry に格納されているイメージの場合は、
gcloud artifacts docker images describe
コマンドを使用します。gcloud artifacts docker images describe \ LOCATION-docker.pkg.dev/PROJECT/REPOSITORY/IMAGE:TAG \ --format 'value(image_summary.digest)'
次のように置き換えます。
LOCATION
: リポジトリのリージョンまたはマルチリージョン ロケーションPROJECT
: 実際の Google Cloud プロジェクト IDREPOSITORY
: リポジトリ名IMAGE
: イメージ名TAG
: イメージタグ
Container Registry
Container Registry に格納されているイメージの場合、名前とタグを指定して
gcloud container images describe
コマンドを実行すると、イメージ ダイジェストを取得できます。ダイジェストを表示する場合は、--format
フラグを使用します。gcloud container images describe \ gcr.io/google-containers/pause-amd64:3.2 \ --format 'value(image_summary.digest)'
出力は次のようになります。ただし、ダイジェストの値が異なる可能性があります。
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
Cloud Build
Cloud Build を使用してビルドされたイメージの場合、--format
フラグを指定して gcloud builds describe
コマンドを実行し、イメージ ダイジェストを取得します。この方法は、イメージの公開に使用したレジストリに関係なく機能します。
すでに完成しているビルドの場合は、次の操作を行います。
プロジェクトのビルドリストを取得します。
gcloud builds list
BUILD_ID
をメモしておきます。イメージ ダイジェストを取得します。
gcloud builds describe BUILD_ID \ --format 'value(results.images[0].digest)'
BUILD_ID
は、Cloud Build のビルドに割り当てられた一意の ID に置き換えます。
現在のプロジェクトの Cloud Build から最新のビルドのイメージ名とダイジェストを取得します。
gcloud builds describe \ $(gcloud builds list --limit 1 --format 'value(id)') \ --format 'value[separator="@"](results.images[0].name,results.images[0].digest)'
ビルドで複数のイメージが生成される場合は、出力をフィルタして、いずれかのイメージのダイジェストを取得します。
gcloud builds describe BUILD_ID --format json \ | jq -r '.results.images[] | select(.name=="YOUR_IMAGE_NAME") | .digest'
YOUR_IMAGE_NAME
は、cloudbuild.yaml
ファイルの含まれるイメージの名前に置き換えます。gcloud builds submit
コマンドを使用して Cloud Build にビルドを送信する場合は、環境変数の出力からイメージ ダイジェストをキャプチャできます。IMAGE_DIGEST=$(gcloud builds submit \ --format 'value(results.images[0].digest)' | tail -n1)
Cloud Native Buildpack
Cloud Native Buildpack と Google Cloud Builder を使用してイメージをビルドし公開する場合は、
pack
コマンドで--quiet
フラグを使用してイメージ名とダイジェストをキャプチャできます。pack build --builder gcr.io/buildpacks/builder:v1 --publish --quiet \ LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \ > image-with-digest.txt
次のように置き換えます。
LOCATION
: リポジトリのリージョンまたはマルチリージョン ロケーションPROJECT_ID
: 実際の Google Cloud プロジェクト IDREPOSITORY
: リポジトリ名IMAGE
: イメージ名
image-with-digest.txt
ファイルには、イメージ名とダイジェストが含まれています。イメージにタグを追加するには、
--tag
フラグを使用します。
Docker クライアント
docker
コマンドライン クライアントのmanifest
サブコマンドを実行すると、コンテナ イメージ レジストリからイメージ マニフェストとマニフェスト リストを取得できます。amd64
CPU アーキテクチャとlinux
オペレーティング システムの場合は、イメージregistry.k8s.io/pause:3.9
のマニフェスト リストからダイジェストを取得します。docker manifest inspect --verbose registry.k8s.io/pause:3.9 | \ jq -r 'if type=="object" then .Descriptor.digest else .[] | select(.Descriptor.platform.architecture=="amd64" and .Descriptor.platform.os=="linux") | .Descriptor.digest end'
出力は次のようになります。
sha256:8d4106c88ec0bd28001e34c975d65175d994072d65341f62a8ab0754b0fafe10
ローカルの Docker デーモンに保存され、イメージ レジストリから pull または push されるイメージの場合は、Docker コマンドライン ツールを使用してイメージ ダイジェストを取得します。
イメージをローカルの Docker デーモンに pull します。
docker pull docker.io/library/debian:bookworm
イメージ ダイジェストを取得します。
docker inspect docker.io/library/debian:bookworm \ | jq -r '.[0].RepoDigests[0]' \ | cut -d'@' -f2
出力は次のようになります。ただし、ダイジェストの値が異なる可能性があります。
sha256:3d868b5eb908155f3784317b3dda2941df87bbbbaa4608f84881de66d9bb297b
ローカル Docker デーモンでイメージとダイジェストを一覧表示します。
docker images --digests
出力には、ダイジェスト値があるイメージ ダイジェストが表示されます。イメージは、イメージ レジストリから pull または push された場合にのみ、ダイジェスト値を持ちます。
crane
と gcrane
オープンソースの crane
と gcrane
コマンドライン ツールを使用すると、イメージをローカル Docker デーモンに pull せずに、イメージ ダイジェストを取得できます。
crane
とgcrane
を現在のディレクトリにダウンロードします。VERSION=$(curl -sL https://api.github.com/repos/google/go-containerregistry/releases/latest | jq -r .tag_name) curl -L "https://github.com/google/go-containerregistry/releases/download/${VERSION}/go-containerregistry_$(uname -s)_$(uname -m).tar.gz" | tar -zxf - crane gcrane
イメージ ダイジェストを取得します。
./gcrane digest gcr.io/distroless/static-debian11:nonroot
crane
とgcrane
には、このドキュメントで説明していない機能があります。詳細については、crane
とgcrane
のドキュメントをご覧ください。
Kubernetes Deployment でのイメージ ダイジェストの使用
Kubernetes クラスタにデプロイするイメージにダイジェストの使用を適用するには、Policy Controller または Open Policy Agent(OPA)Gatekeeper を使用します。Policy Controller は、OPA Gatekeeper オープンソース プロジェクトからビルドされています。
Policy Controller と OPA Gatekeeper はいずれも OPA ポリシー エンジン上にビルドされています。Policy Controller と OPA Gatekeeper は、ポリシーを適用するための Kubernetes 検証 Admission Webhook を提供します。また、制約テンプレートと制約用にカスタム リソース定義(CRD)も提供します。
制約テンプレートには、高レベルの宣言型言語(Rego)で記述されたポリシー ロジックが含まれています。以下は、Kubernetes リソース仕様のコンテナ、初期コンテナ、エフェメラル コンテナがダイジェスト付きのイメージを使用することを検証する制約テンプレートです。
上のポリシーには、re_match
関数への入力として正規表現が含まれています。この正規表現は、コンテナ イメージのダイジェストと照合されます。これは、Open Container Initiative イメージ仕様のダイジェスト形式に基づいています。
制約は、kind
や namespace
などの属性と照合し、Kubernetes リソースにポリシーを適用します。次の例の制約は、制約テンプレートのポリシーを default
Namespace 内のすべての Pod
リソースに適用します。
制約テンプレートと制約を作成すると、default
Namespace の新しい Pod は、イメージ ダイジェストを使用して、コンテナ イメージを参照する必要があります。
詳細な例については、Gatekeeper ポリシー ライブラリの imagedigests
ポリシーをご覧ください。
イメージ マニフェスト、ダイジェスト、タグについて
このセクションでは、curl
や docker
などのコマンドライン ツールを使用して、レジストリ内の既存のイメージを調べる方法について説明します。これらのコマンドは Cloud Shell か、gcloud CLI、Docker、cURL、jq
などのツールがインストールされているシェル環境で実行します。次のコマンドは、Artifact Registry の公開イメージを使用します。
cURL とマニフェスト URL を使用して、イメージ
gcr.io/google-containers/pause-amd64:3.2
のマニフェストを取得します。curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2
出力は次のようになります。
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "config": { "mediaType": "application/vnd.docker.container.image.v1+json", "size": 759, "digest": "sha256:80d28bedfe5dec59da9ebf8e6260224ac9008ab5c11dbbe16ee3ba3e4439ac2c" }, "layers": [ { "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", "size": 296534, "digest": "sha256:c74f8866df097496217c9f15efe8f8d3db05d19d678a02d01cc7eaed520bb136" } ] }
config
セクションにあるダイジェスト属性の値を使用して構成オブジェクトを取得します。同様に、各レイヤのdigest
属性を使用して、そのレイヤの tar ファイルを取得します。イメージにオプションのイメージ インデックスが含まれている場合は、タグを使用してマニフェスト URL に HTTP
GET
リクエストを送信すると、イメージ マニフェストではなくイメージ インデックスを取得できます。イメージ
gcr.io/google-containers/pause:3.2
のイメージ インデックスを取得します。curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2
出力は次のようになります。
{ "schemaVersion": 2, "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json", "manifests": [ { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108", "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:bbb7780ca6592cfc98e601f2a5e94bbf748a232f9116518643905aa30fc01642", "platform": { "architecture": "arm", "os": "linux", "variant": "v7" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:31d3efd12022ffeffb3146bc10ae8beb890c80ed2f07363515580add7ed47636", "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:7f82fecd72730a6aeb70713476fb6f7545ed1bbf32cadd7414a77d25e235aaca", "platform": { "architecture": "ppc64le", "os": "linux" } }, { "mediaType": "application/vnd.docker.distribution.manifest.v2+json", "size": 526, "digest": "sha256:1175fd4d728641115e2802be80abab108b8d9306442ce35425a4e8707ca60521", "platform": { "architecture": "s390x", "os": "linux" } } ] }
結果をフィルタリングして、必要なプラットフォームのイメージ ダイジェストを抽出します。
amd64
CPU アーキテクチャとlinux
オペレーティング システムのイメージ マニフェストのダイジェストを取得します。curl -s https://gcr.io/v2/google-containers/pause/manifests/3.2 | \ jq -r '.manifests[] | select(.platform.architecture=="amd64" and .platform.os=="linux") | .digest'
このコマンドのフィルタリングは、containerd などのコンテナ ランタイムがイメージ インデックスからターゲット プラットフォームに一致するイメージを選択する方法と似ています。
出力は次のようになります。
sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
イメージ ダイジェストは、イメージ マニフェストに衝突耐性のあるハッシュが適用された後の値です。通常は SHA-256 アルゴリズムが使用されます。
イメージ
gcr.io/google-containers/pause-amd64:3.2
のダイジェストを取得します。curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1
出力は次のようになります。
4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
次のようにイメージ ダイジェスト値を使用すると、このイメージを参照できます。
gcr.io/google-containers/pause-amd64@sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
コンテンツのアドレス指定が可能なストレージのコンセプトを使用して、ダイジェストを参照として使用し、イメージ マニフェストを取得します。
curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/sha256:4a1c4b21597c1b4415bdbecb28a3296c6b5e23ca4f9feeb599860a1dac6a0108
多くのコンテナ イメージ レジストリは、HTTP
HEAD
リクエストに応じて、Docker-Content-Digest
ヘッダーでマニフェスト、イメージ インデックス、構成オブジェクト、ファイル システム レイヤのダイジェストを返します。イメージgcr.io/google-containers/pause-amd64:3.2
のイメージ インデックスのダイジェストを取得します。curl -s --head https://gcr.io/v2/google-containers/pause/manifests/3.2 \ | grep -i Docker-Content-Digest \ | cut -d' ' -f2
出力は次のようになります。
sha256:927d98197ec1141a368550822d18fa1c60bdae27b78b0c004f705f548c07814f
Docker-Content-Digest
ヘッダーは、Open Container Initiative の配布仕様で必須になっていません。このため、この方法がすべてのコンテナ イメージ レジストリで機能するとは限りません。これは、Artifact Registry と Container Registry で使用できます。イメージ マニフェストのダイジェスト値を使用してイメージ構成オブジェクトを取得するには、次の操作を行います。
構成ダイジェストを取得します。
CONFIG_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.config.digest')
構成ダイジェストを使用して構成オブジェクトを取得します。読みやすくするため、
jq
を使用して出力をフォーマットします。curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$CONFIG_DIGEST \ | jq
出力は次のようになります。
{ "architecture": "amd64", "config": { "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Entrypoint": [ "/pause" ], "WorkingDir": "/", "OnBuild": null }, "created": "2020-02-14T10:51:50.60182885-08:00", "history": [ { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ARG ARCH", "comment": "buildkit.dockerfile.v0", "empty_layer": true }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ADD bin/pause-amd64 /pause # buildkit", "comment": "buildkit.dockerfile.v0" }, { "created": "2020-02-14T10:51:50.60182885-08:00", "created_by": "ENTRYPOINT [\"/pause\"]", "comment": "buildkit.dockerfile.v0", "empty_layer": true } ], "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:ba0dae6243cc9fa2890df40a625721fdbea5c94ca6da897acdd814d710149770" ] } }
イメージ マニフェストからダイジェスト値を使用してファイル システム レイヤを取得するには、次の操作を行います。
取得するレイヤのダイジェストを取得します。
LAYER_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | jq -r '.layers[0].digest')
レイヤ ダイジェストを使用してレイヤの tar ファイルを取得し、コンテンツを表示します。
curl -sL https://gcr.io/v2/google-containers/pause-amd64/blobs/$LAYER_DIGEST \ | tar --list
このレイヤには
pause
というファイルが 1 つだけあります。
イメージ ダイジェストに関連付けられたタグを検索するには、次の操作を行います。
検索するダイジェストを定義します。
IMAGE_DIGEST=$(curl -s https://gcr.io/v2/google-containers/pause-amd64/manifests/3.2 \ | shasum -a 256 \ | cut -d' ' -f1)
IMAGE_DIGEST
環境変数には、タグ3.2
で参照されるイメージのダイジェストが含まれます。イメージタグ リストのエンドポイント(
/tags/list
)を使用して、タグ情報を一覧表示し、ダイジェスト値のタグを抽出します。curl -s "https://gcr.io/v2/google-containers/pause-amd64/tags/list?n=1" \ | jq ".manifest.\"sha256:$IMAGE_DIGEST\".tag"
出力は次のようになります。
[ "3.2" ]
cURL を使用して Artifact Registry コンテナ イメージ リポジトリからイメージのマニフェストを取得するには、
Authorization
リクエスト ヘッダーにアクセス トークンを配置します。curl -s -H "Authorization: Bearer $(gcloud auth print-access-token)" \ https://LOCATION-docker.pkg.dev/v2/PROJECT_ID/REPOSITORY/IMAGE/manifests/DIGEST
次のように置き換えます。
LOCATION
: リポジトリのリージョンまたはマルチリージョン ロケーションPROJECT_ID
: 実際の Google Cloud プロジェクト IDREPOSITORY
: リポジトリ名IMAGE
: イメージ名DIGEST
:sha256:DIGEST_VALUE
の形式のイメージ ダイジェスト。