# 機能設計書 51-イメージ管理

## 概要

本ドキュメントは、Kubeletのイメージ管理機能について、コンテナイメージのプル（ダウンロード）、キャッシュ管理、およびガベージコレクション（不要イメージの削除）の設計を記載する。

### 本機能の処理概要

Kubeletのイメージ管理機能は、ノード上のコンテナイメージのライフサイクル全体を管理する。Podの起動時に必要なコンテナイメージがノード上に存在するかを確認し、存在しない場合はコンテナレジストリからプルする。また、ディスク使用量を監視し、閾値を超えた場合は不要なイメージを自動的に削除する。

**業務上の目的・背景**：Kubernetesクラスターでは、多数のPodが異なるコンテナイメージを使用する。ノードのディスク容量は有限であるため、必要なイメージの確実なプルと不要イメージの適切な削除を自動化することが不可欠である。この機能がなければ、ディスク容量不足によるPod起動失敗やノード障害が発生する。

**機能の利用シーン**：Pod作成時にコンテナイメージが必要な場面、ノードのディスク使用量が閾値を超えた場面、ノードの定期的なメンテナンス時に未使用イメージを一括削除する場面で利用される。

**主要な処理内容**：
1. イメージプルポリシー（Always/IfNotPresent/Never）に基づくイメージ存在確認
2. 認証情報（Secret、ServiceAccount、CredentialProvider）を用いたイメージプル
3. 直列/並列イメージプルの制御とレート制限
4. バックオフ付きリトライによるプル失敗時のエラーハンドリング
5. ディスク使用量閾値に基づくイメージガベージコレクション
6. イメージの使用状況追跡とキャッシュ管理

**関連システム・外部連携**：CRI（Container Runtime Interface）を通じたコンテナランタイムとの通信、コンテナレジストリとの通信、外部CredentialProviderプラグインとの連携。

**権限による制御**：イメージプルにはPodに紐づくImagePullSecretsまたはServiceAccountの認証情報が使用される。KubeletEnsureSecretPulledImagesフィーチャーゲートが有効な場合、イメージが既にノード上に存在していても、Podの認証情報でアクセス可能かを検証する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Kubelet内部機能のため画面関連なし |

## 機能種別

データ連携 / リソース管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| requestedImage | string | Yes | プルするコンテナイメージ名 | タグ/ダイジェストがない場合はデフォルトタグ":latest"を付与 |
| pullPolicy | v1.PullPolicy | Yes | イメージプルポリシー | Always/IfNotPresent/Neverのいずれか |
| pullSecrets | []v1.Secret | No | レジストリ認証用Secret一覧 | - |
| podSandboxConfig | *runtimeapi.PodSandboxConfig | Yes | PodサンドボックスConfig | - |
| podRuntimeHandler | string | No | ランタイムハンドラー名 | - |
| HighThresholdPercent | int | Yes | GCトリガー閾値（上限%） | 0-100の範囲 |
| LowThresholdPercent | int | Yes | GCターゲット閾値（下限%） | 0-100、HighThreshold以下 |
| MinAge | time.Duration | Yes | GC対象最小年齢 | 0以上 |
| MaxAge | time.Duration | No | GC対象最大年齢（0で無効） | 0以上 |

### 入力データソース

- Pod仕様（v1.PodSpec）からのイメージ名、プルポリシー、ImagePullSecrets
- Kubelet設定からのGCポリシーパラメータ
- ノードのCredentialProviderからの認証情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| imageRef | string | プル成功時のイメージ参照文字列 |
| message | string | プル結果のメッセージ |
| err | error | エラー情報 |

### 出力先

- CRI経由のコンテナランタイムへのイメージ操作
- Kubernetesイベントとしての記録
- Prometheusメトリクス（image_pull_duration_seconds、image_garbage_collected_total）

## 処理フロー

### 処理シーケンス

```
1. EnsureImageExists呼び出し
   └─ イメージ名にデフォルトタグを適用
2. imagePullPrecheck実行
   └─ pullPolicyに基づきイメージ存在確認
3. 認証情報の解決
   └─ Secret、CredentialProvider、ServiceAccountから認証情報取得
4. イメージプル判定
   └─ KubeletEnsureSecretPulledImages有効時は認証情報によるアクセス検証
5. イメージプル実行
   └─ バックオフチェック後、直列/並列プーラーでCRI経由プル
6. 結果記録
   └─ メトリクス、イベント記録
```

### フローチャート

```mermaid
flowchart TD
    A[EnsureImageExists] --> B[デフォルトタグ適用]
    B --> C{pullPolicyチェック}
    C -->|Always| D[イメージプルへ]
    C -->|IfNotPresent| E{イメージ存在?}
    C -->|Never| F{イメージ存在?}
    E -->|Yes| G{認証情報アクセス検証}
    E -->|No| D
    F -->|Yes| G
    F -->|No| H[ErrImageNeverPull]
    G -->|OK| I[イメージ利用可能]
    G -->|NG| D
    D --> J{バックオフ中?}
    J -->|Yes| K[ErrImagePullBackOff]
    J -->|No| L[CRI経由プル実行]
    L --> M{プル成功?}
    M -->|Yes| N[メトリクス・イベント記録]
    M -->|No| O[バックオフ設定・エラー返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-01 | プルポリシー制御 | Alwaysの場合は常にプルを試行、IfNotPresentの場合はノード上に存在しなければプル、Neverの場合はプルしない | Pod起動時 |
| BR-51-02 | バックオフ制御 | プル失敗時はexponential backoffで再試行を制限 | プル失敗後 |
| BR-51-03 | GC閾値制御 | ディスク使用率がHighThreshold以上でGC開始、LowThresholdまで削減 | 定期GC実行時 |
| BR-51-04 | GC対象選定 | 使用中イメージ、pinned イメージ、MinAge未満のイメージはGC対象外 | GC実行時 |
| BR-51-05 | GC削除順序 | 最後に使用された時刻が古いものから削除（lastUsed, firstDetectedの順） | GC実行時 |
| BR-51-06 | 認証情報検証 | KubeletEnsureSecretPulledImages有効時、既存イメージでもPod認証情報でアクセス可能か検証 | Pod起動時 |

### 計算ロジック

- ディスク使用率 = 100 - (available * 100 / capacity)
- 解放必要量 = capacity * (100 - LowThresholdPercent) / 100 - available

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| イメージ追跡 | imageRecords（インメモリ） | INSERT/UPDATE/DELETE | イメージの検出時刻、最終使用時刻、サイズを管理 |
| イメージキャッシュ | imageCache（インメモリ） | UPDATE | ListImagesの結果を30秒間隔でキャッシュ |

### テーブル別操作詳細

#### imageRecords（インメモリMap）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | firstDetected | 初回検出時の時刻 | 新規イメージ検出時 |
| UPDATE | lastUsed | 現在時刻 | コンテナが使用中の場合 |
| UPDATE | size | イメージサイズ（バイト） | 検出時に更新 |
| DELETE | - | currentImagesに存在しない場合 | 定期検出時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ErrImagePullBackOff | 一時エラー | バックオフ期間中のプル試行 | 自動的にバックオフ期間後に再試行 |
| ErrImageInspect | 一時エラー | イメージ情報取得失敗 | CRI接続を確認 |
| ErrImagePull | 一時エラー | イメージプル失敗 | ネットワーク、認証情報を確認 |
| ErrImageNeverPull | 設定エラー | PullPolicy=Neverでイメージ不在 | イメージを事前にプルするか、PullPolicyを変更 |
| ErrInvalidImageName | 入力エラー | イメージ名のパース失敗 | イメージ名の書式を修正 |
| ErrRegistryUnavailable | 外部エラー | レジストリ接続不可 | レジストリの可用性を確認 |
| ErrSignatureValidationFailed | セキュリティエラー | イメージ署名検証失敗 | イメージの署名を確認 |

### リトライ仕様

- プル失敗時はexponential backoffで再試行（初期値は設定依存）
- バックオフ状態はpodUID_imageキーで管理
- バックオフGCはプル成功時に実行

## トランザクション仕様

内部状態管理はsync.Mutexによる排他制御。imageRecordsのロック（imageRecordsLock）とimageCacheのロック（sync.Mutex）で並行安全性を保証。

## パフォーマンス要件

- 並列プル時のmax並列数はmaxParallelImagePullsで制御可能
- イメージプルのレート制限（QPS、Burst）による帯域制御
- イメージリスト更新は30秒間隔
- イメージ検出は5分間隔
- シリアルプーラーのキュー最大サイズ: 10

## セキュリティ考慮事項

- プル認証情報はPodのImagePullSecrets、ServiceAccount、CredentialProviderPluginから取得
- KubeletEnsureSecretPulledImages機能により、認証なしでプルされたイメージへの未認証アクセスを防止
- イメージ不在時とアクセス拒否時で同一のエラーメッセージを返し、イメージ存在の推測を防止
- CRI署名検証（ErrSignatureValidationFailed）のサポート

## 備考

- RuntimeClassInImageCriAPIフィーチャーゲート有効時、イメージはimageId,runtimeHandlerのタプルで識別される
- ImageVolumeフィーチャーゲート有効時、イメージボリュームとして使用中のイメージもGC対象外となる
- MaxAge設定はKubelet起動後MaxAge経過するまで適用されない（早期GC防止）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、イメージ管理で使用されるインターフェースとデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `pkg/kubelet/images/types.go` | ImageManagerインターフェース、エラー定数の定義 |
| 1-2 | image_gc_manager.go | `pkg/kubelet/images/image_gc_manager.go` | ImageGCManagerインターフェース、ImageGCPolicy、imageRecord構造体 |

**読解のコツ**: types.goで定義されるImageManagerインターフェースはEnsureImageExistsメソッドのみを持つ。GC機能はImageGCManagerとして別インターフェースで定義されている。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | image_manager.go | `pkg/kubelet/images/image_manager.go` | NewImageManager関数でのプーラー選択（直列/並列） |

**主要処理フロー**:
1. **75-105行目**: NewImageManager - イメージプーラーの初期化（serialized設定に基づく選択）
2. **164-282行目**: EnsureImageExists - メインのイメージ確保フロー
3. **109-136行目**: imagePullPrecheck - プルポリシーに基づく事前チェック
4. **317-382行目**: pullImage - 実際のイメージプル処理（バックオフ、メトリクス記録含む）

#### Step 3: イメージプーラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | puller.go | `pkg/kubelet/images/puller.go` | parallelImagePullerとserialImagePullerの実装 |

**主要処理フロー**:
- **55-76行目**: parallelImagePuller.pullImage - goroutineでの並列プル（トークンによる並列数制限）
- **100-128行目**: serialImagePuller - チャネルベースの直列プル処理

#### Step 4: ガベージコレクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | image_gc_manager.go | `pkg/kubelet/images/image_gc_manager.go` | GCの全体フロー |

**主要処理フロー**:
- **217-236行目**: Start - 5分間隔の検出と30秒間隔のキャッシュ更新ループ
- **243-322行目**: detectImages - 使用中イメージの特定とレコード更新
- **348-417行目**: GarbageCollect - MaxAge超過イメージ削除、閾値ベースの削除
- **482-521行目**: freeSpace - 古い順にイメージを削除し目標容量を解放

### プログラム呼び出し階層図

```
Kubelet (SyncPod)
    |
    +-- imageManager.EnsureImageExists()
    |       |
    |       +-- imagePullPrecheck()
    |       |       +-- imageService.GetImageRef() [CRI]
    |       +-- makeLookupPullCredentialsFunc()
    |       |       +-- credentialproviderplugin.NewExternalCredentialProviderDockerKeyring()
    |       |       +-- credentialprovidersecrets.MakeDockerKeyring()
    |       +-- imagePullManager.MustAttemptImagePull()
    |       +-- pullImage()
    |               +-- backOff.IsInBackOffSinceUpdate()
    |               +-- puller.pullImage()
    |                       +-- imageService.PullImage() [CRI]
    |                       +-- imageService.GetImageSize() [CRI]
    |
    +-- imageGCManager.Start()
    |       +-- detectImages() [5分間隔]
    |       |       +-- runtime.ListImages() [CRI]
    |       |       +-- runtime.GetPods() [CRI]
    |       +-- runtime.ListImages() [30秒間隔 キャッシュ更新]
    |
    +-- imageGCManager.GarbageCollect()
            +-- imagesInEvictionOrder()
            +-- freeOldImages()
            +-- statsProvider.ImageFsStats()
            +-- freeSpace()
                    +-- freeImage()
                            +-- runtime.RemoveImage() [CRI]
```

### データフロー図

```
[入力]                          [処理]                              [出力]

Pod仕様
(イメージ名,
 pullPolicy,         ──▶  EnsureImageExists()  ──▶  imageRef (成功)
 pullSecrets)               |                       エラー (失敗)
                            v                       イベント記録
認証情報            ──▶  pullImage()           ──▶  メトリクス記録
(Secret,                    |
 CredentialProvider)        v
                      CRI PullImage API
                            |
                            v
                      コンテナランタイム

ディスク使用量統計   ──▶  GarbageCollect()     ──▶  イメージ削除
イメージリスト        ──▶  detectImages()        ──▶  imageRecords更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| types.go | `pkg/kubelet/images/types.go` | ソース | ImageManagerインターフェース、エラー定数定義 |
| image_manager.go | `pkg/kubelet/images/image_manager.go` | ソース | イメージプル管理の主実装 |
| image_gc_manager.go | `pkg/kubelet/images/image_gc_manager.go` | ソース | イメージGC管理の主実装 |
| puller.go | `pkg/kubelet/images/puller.go` | ソース | 直列/並列イメージプーラー実装 |
| helpers.go | `pkg/kubelet/images/helpers.go` | ソース | ヘルパー関数 |
| metrics.go | `pkg/kubelet/images/metrics.go` | ソース | Prometheusメトリクス定義 |
| pullmanager/ | `pkg/kubelet/images/pullmanager/` | ソース | イメージプル管理（認証情報追跡） |
