Skip to content
Published on

[containerd] イメージ管理:OCIイメージとスナップショット

Authors

containerdイメージ管理:OCIイメージとスナップショット

containerdのイメージ管理サブシステムはOCIイメージスペックに基づいてイメージの保存、配布、アンパッキングを担当する核心機能です。この記事ではContent Store、Snapshotter、イメージPullフロー、ガベージコレクションの内部動作を分析します。


1. OCIイメージスペック

1.1 イメージ構造

OCIイメージは3つの核心コンポーネントで構成されます:

OCIイメージ構造:

1. Image Index(Fat Manifest)
   - 複数プラットフォーム(linux/amd64、linux/arm64など)をサポート
   - 各プラットフォーム別Manifestを指す

2. Image Manifest
   - Configオブジェクトのダイジェスト
   - レイヤーリスト(順序保証)
   - メディアタイプ情報

3. Image Config
   - 環境変数、エントリポイント、CMD
   - レイヤーdiff IDリスト
   - 作成履歴

1.2 コンテンツアドレス指定

コンテンツアドレス指定(Content Addressable Storage):

すべてのオブジェクトはSHA256ダイジェストで識別:
  sha256:abc123... -> Image Index JSON
  sha256:def456... -> Image Manifest JSON
  sha256:789ghi... -> Image Config JSON
  sha256:jkl012... -> Layer tar.gz

利点:
  - 重複排除:同一レイヤーは1回のみ保存
  - 整合性検証:ダイジェストでデータ検証
  - キャッシング:ダイジェストベースのキャッシュルックアップ

2. Content Store

2.1 概要

Content Storeはcontainerdのコンテンツアドレスストレージで、イメージのすべてのバイナリデータを管理します。

Content Storeディレクトリ構造:

/var/lib/containerd/io.containerd.content.v1.content/
  blobs/
    sha256/
      abc123...  (Image Index)
      def456...  (Image Manifest)
      789ghi...  (Image Config)
      jkl012...  (Layer 1 tar.gz)
      mno345...  (Layer 2 tar.gz)
  ingest/
    (一時ダウンロードデータ)

2.2 Content Store API

Content Store主要操作:

Info(digest)     -> コンテンツメタデータ照会(サイズ、作成時間)
ReaderAt(digest) -> コンテンツ読み取り(io.ReaderAtインターフェース)
Writer(ref)      -> コンテンツ書き込み(アトミックコミット)
Delete(digest)   -> コンテンツ削除
ListStatuses()   -> 進行中の書き込み操作照会
Abort(ref)       -> 進行中の書き込み操作キャンセル

2.3 Ingestプロセス

コンテンツ書き込み(Ingest)プロセス:

1. Writer作成(参照キー割り当て)
        |
        v
2. ingest/ディレクトリに一時ファイル作成
        |
        v
3. データストリーミング書き込み
   (レジストリからレイヤーダウンロードなど)
        |
        v
4. ダイジェスト検証
   (期待ダイジェストと実際のデータハッシュを比較)
        |
        v
5. アトミックコミット
   (ingest/ -> blobs/sha256/ に移動)
        |
        v
6. 失敗時にingest/をクリーンアップ

3. Snapshotter

3.1 Snapshotter概要

Snapshotterはイメージレイヤーをファイルシステムスナップショットとして管理するプラグインです。コンテナが使用するルートファイルシステムを準備します。

Snapshotterの役割:

イメージレイヤー(tar.gz)
    |
    v
Snapshotterが各レイヤーをスナップショットに変換
    |
    v
スナップショットを重ねて統合ファイルシステムを構成
    |
    v
コンテナにマウントポイントを提供

3.2 スナップショットタイプ

スナップショット種類:

1. Committed(コミット済み)
   - 読み取り専用スナップショット
   - イメージレイヤーに対応
   - 複数コンテナで共有可能

2. Active(アクティブ)
   - 読み取り/書き込みスナップショット
   - コンテナの書き込み可能レイヤー
   - 1つのコンテナに割り当て

3.3 overlayfs Snapshotter

最も広く使用されるSnapshotterです:

overlayfs動作:

レイヤー1(base):/snapshots/1/fs  (lowerdir)
レイヤー2(app):/snapshots/2/fs   (lowerdir)
書き込みレイヤー:/snapshots/3/fs   (upperdir)
作業ディレクトリ:/snapshots/3/work (workdir)

マウント:
  mount -t overlay overlay \
    -o lowerdir=/snapshots/2/fs:/snapshots/1/fs,\
       upperdir=/snapshots/3/fs,\
       workdir=/snapshots/3/work \
    /container/rootfs

利点:
  - Copy-on-Write:変更時のみコピー
  - 高速なコンテナ起動
  - レイヤー共有でディスク節約

3.4 native Snapshotter

native Snapshotter:

- 各スナップショットを独立ディレクトリに保存
- 親スナップショットを完全にコピー(hardlink使用)
- overlayfsをサポートしない環境で使用
- ディスク使用量が大きい
- シンプルで移植性が高い

3.5 devmapper Snapshotter

devmapper Snapshotter:

- Linux device mapperのthin provisioningを使用
- ブロックレベルCopy-on-Write
- 高パフォーマンスワークロードに適合
- Firecracker microVMと共に使用
- 設定が複雑(thin-pool事前構成が必要)

使用事例:
  - AWS Fargate(Firecracker)
  - 高パフォーマンスコンテナ環境
  - ブロックストレージベースのインフラ

3.6 Snapshotter API

Snapshotter主要操作:

Stat(key)              -> スナップショット情報照会
Prepare(key, parent)   -> Activeスナップショット作成(書き込み可能)
View(key, parent)      -> Committedスナップショットの読み取り専用ビュー
Commit(name, key)      -> ActiveスナップショットをCommittedに変換
Mounts(key)            -> スナップショットのマウント情報を返す
Remove(key)            -> スナップショット削除

4. イメージPullフロー

4.1 全体フロー

イメージPull全体フロー:

1. イメージ参照の解決
   docker.io/library/nginx:latest
        |
        v
2. Image Index/Manifestダウンロード
   - レジストリからマニフェストを取得
   - プラットフォームに合ったマニフェストを選択
        |
        v
3. Configダウンロード
   - イメージ設定JSONをダウンロード
   - Content Storeに保存
        |
        v
4. レイヤーダウンロード(並列)
   - 各レイヤーをContent Storeに保存
   - 既に存在するレイヤーはスキップ
        |
        v
5. レイヤーアンパッキング
   - Content Storeからレイヤーを読み取り
   - Snapshotterでスナップショット作成
        |
        v
6. イメージメタデータ登録
   - BoltDBにイメージレコード作成
   - タグとダイジェストのマッピング

4.2 レイヤーダウンロード詳細

レイヤーダウンロード:

1. マニフェストからレイヤーダイジェストリストを抽出
2. Content Storeに既に存在するか確認
3. 存在しないレイヤーのみレジストリからダウンロード
4. Transfer Serviceがダウンロード管理:
   - 同時ダウンロード制限(デフォルト3個)
   - 進捗状況追跡
   - リトライロジック
5. 各レイヤーはgzip圧縮状態でContent Storeに保存

4.3 レイヤーアンパッキング

レイヤーアンパッキング(Unpack):

1. Content Storeからレイヤーblobを読み取り
2. gzip解凍
3. tarアーカイブ展開
4. Snapshotterにスナップショット作成:
   a. 最初のレイヤー:親なしでPrepare
   b. レイヤー内容をスナップショットに適用(Apply)
   c. Commitで読み取り専用に変換
   d. 次のレイヤー:前のスナップショットを親としてPrepare
5. 最終スナップショットチェーン完成

スナップショットチェーン:
  Layer 1 (committed) <- Layer 2 (committed) <- Layer 3 (committed)

5. イメージメタデータ

5.1 イメージレコード

イメージメタデータ(BoltDB):

イメージレコード:
  - Name: "docker.io/library/nginx:latest"
  - Target:
      MediaType: "application/vnd.oci.image.index.v1+json"
      Digest: "sha256:abc123..."
      Size: 1234
  - Labels:
      "containerd.io/gc.ref.content.0": "sha256:def456..."
      "containerd.io/gc.ref.content.1": "sha256:789ghi..."
  - CreatedAt: 2026-03-20T00:00:00Z
  - UpdatedAt: 2026-03-20T00:00:00Z

5.2 イメージ照会

# ctrでイメージリスト照会
ctr -n k8s.io images list

# イメージ詳細情報
ctr -n k8s.io images check

# イメージコンテンツ確認
ctr -n k8s.io content get sha256:abc123... | jq .

6. ガベージコレクション

6.1 GCメカニズム

ガベージコレクション動作:

1. ルートオブジェクト識別:
   - イメージレコード
   - コンテナレコード
   - Leaseレコード

2. 参照追跡(Mark):
   - イメージ -> Manifest -> Config + Layers
   - コンテナ -> スナップショットチェーン
   - Lease -> 保護中のリソース

3. 未参照オブジェクト削除(Sweep):
   - Content Storeの未参照blob削除
   - Snapshotterの未参照スナップショット削除
   - メタデータの孤立レコードクリーンアップ

6.2 GCラベル

GC参照ラベル:

containerdはGC参照をラベルで管理します:

イメージラベル:
  "containerd.io/gc.ref.content.0": "sha256:..."  (マニフェスト参照)
  "containerd.io/gc.ref.content.1": "sha256:..."  (レイヤー参照)

コンテンツラベル:
  "containerd.io/gc.ref.content.config": "sha256:..." (config参照)
  "containerd.io/gc.ref.content.l.0": "sha256:..."    (レイヤー参照)

スナップショットラベル:
  "containerd.io/gc.ref.snapshot.overlayfs": "sha256:..." (スナップショット参照)

6.3 Lease

Lease(リース):

- 進行中の操作のリソースをGCから保護
- イメージPull中にダウンロードされたレイヤーを保護
- コンテナ作成中のスナップショットを保護
- TTLベースの自動期限切れ
- 操作完了後に明示的削除可能

例:
  イメージPull開始 -> Lease作成
  レイヤーダウンロード -> Leaseがコンテンツを保護
  イメージ登録完了 -> Lease削除(イメージレコードが参照を保持)

6.4 GCスケジューリング

GCトリガー:

1. 定期実行:
   - containerd設定のgc_schedule(デフォルト値なし)
   - 設定時にcron式で周期を指定

2. イベントベース:
   - イメージ削除時
   - コンテナ削除時
   - APIを通じた明示的呼び出し

3. ctrによる手動実行:
   ctr -n k8s.io content prune

7. まとめ

containerdのイメージ管理はContent Storeのコンテンツアドレス保存、Snapshotterのレイヤー管理、GCのリソースクリーンアップという3つの軸で構成されます。overlayfs SnapshotterのCopy-on-Writeメカニズムは高速なコンテナ起動と効率的なディスク使用を可能にし、LeaseベースのGC保護はイメージ操作の安全性を保証します。