コンテナレジストリの仕組み:イメージを直接 Push/Pull する
(labs.iximiuz.com)- コンテナレジストリは一見単純だが、誤ったタグ、プラットフォーム不一致、レイヤー欠落、実際には削除されないといった問題をデバッグするには、内部動作の原理を必ず理解する必要がある
- レジストリの中核は コンテンツアドレス指定方式(content-addressable)の blob ストア で、すべてのレイヤー・設定ファイル・アーティファクトは digest をアドレスとして保存される
- イメージの push は blob のアップロード後に manifest で束ねる順序 で進み、pull は manifest を先に受け取ってから blob を順にダウンロードする逆順の構造になっている
- イメージ削除 は単なるアンタグだけでは完全に削除されず、ほかの manifest で共有中のレイヤーを先に確認したうえで、blob まで直接削除する必要がある
- マルチプラットフォームイメージ は、既存の API エンドポイントをそのまま維持しつつ、image index(manifest list)という追加の間接レイヤーを 1 つ導入するだけで実現されている
Registry API 概要
- 現代のコンテナレジストリの大半は OCI Distribution Specification を実装しており、この仕様はコンテンツ配布を標準化する API プロトコルを定義している
- Registry API は実際には簡潔で理解しやすく、
curlだけでも十分に直接操作できる
Blob のアップロードとダウンロード
- レジストリは本質的に コンテンツアドレス指定 blob ストア であり、ファイルをローカルでハッシュ化した後、digest をアドレスとして使ってアップロードする
- 最も単純なアップロード方式は Monolithic PUT 方式で、
POSTでセッションを初期化した後、PUTで blob を送信する 2 段階構造- 大容量ファイルには
POST + PATCH + PUTのチャンクアップロード方式のほうが効率的だが、小さい blob であれば Monolithic PUT で十分
- 大容量ファイルには
- アップロード成功時には
HTTP/2 201 Createdレスポンスとともに、新しい blob の場所を指すLocationヘッダーが返される - ダウンロードは digest さえ分かれば
GET /v2/<repo>/blobs/<digest>ですぐに実行できる
イメージ Push
- イメージ push の手順: (1) 各 rootfs レイヤー の blob をアップロード → (2) image configuration blob をアップロード → (3) すべての digest を 1 つの JSON ドキュメントにまとめる manifest ファイルを push
- manifest は
PUT /v2/<repo>/manifests/<tag>エンドポイントにアップロードし、この時点でタグが作成される - 実際のクライアント(例:
docker push)は blob アップロードを並列に実行するが、原理を理解するためには逐次処理でもよい - イメージディレクトリ構成例:
config.json,layer-1.tar.gz,layer-2.tar.gz,manifest.json
タグ一覧の取得
GET /v2/<repo>/tags/listエンドポイントで、特定リポジトリの すべてのタグ一覧 を取得できる- この機能は
dockerCLI では公開されておらず、curlまたはcrane、regctlのようなツールでのみアクセスできるcrane、regctlは同じエンドポイントをlsコマンドとしてラップしたもの
イメージ Pull
- pull の手順は push の逆順: (1)
GET /v2/<repo>/manifests/<tag>で manifest を取得 → (2) manifest に記載された digest を使って すべての blob をダウンロード - 現代の manifest は rootfs レイヤーやイメージ設定に加え、Helm チャート、SBOM、出所証明(provenance attestation)、LLM の重み など任意のアーティファクトを blob として参照する汎用ストアとしても使われている
イメージ削除
- イメージ削除は単純ではなく、タグの削除(アンタグ)だけでは manifest 自体は削除されない
- 完全削除の手順:
- (1)
DELETE /v2/<repo>/manifests/<tag>でタグを削除 - (2) manifest を digest で参照して、参照中のすべての blob を確認
- (3) ほかの manifest で共有されていない blob だけ を選択的に削除
- (4)
DELETE /v2/<repo>/blobs/<manifest-digest>で manifest blob を削除
- (1)
- レジストリはコンテンツアドレス指定ストアであるため、同じ rootfs レイヤーを複数のイメージで共有でき、削除時にはそのレイヤーを参照している すべてのイメージに影響 する
- 代替策として、すべてのタグを削除した後にレジストリの ガベージコレクション(garbage collection) 設定に依存する方法もあるが、公開レジストリでは常に有効とは限らない
マルチプラットフォームイメージ
- マルチプラットフォームイメージは レジストリ API の構造変更なしに 実装されている — エンドポイントの追加・変更なしに既存 API をそのまま利用する
- 構成方法:
- 各単一プラットフォーム変種(amd64、arm64 など)を、それぞれ個別の manifest とともに digest ベースで先に push する
- その後、image index(manifest list) と呼ばれる上位 manifest をタグ付きで push する
GET /v2/<repo>/manifests/<tag>を呼び出すと、単一プラットフォーム manifest または image index のいずれかが返され、呼び出し側は返却ドキュメントの content type で判別しなければならない- 結果として、マルチプラットフォーム対応は既存構造に 間接レイヤー 1 つと index ドキュメントのアップロード/ダウンロード手順 1 つ を追加しただけである
レジストリ API の保護
- OCI Distribution Spec は認証方式を厳密には定義していないが、実際のレジストリの多くは HTTP Basic 認証 を使用している
- 認証情報が平文で送信されるのを防ぐため、必ず HTTPS 上で運用する必要がある
まだコメントはありません。