# 通知設計書 20-Pulled

## 概要

本ドキュメントは、Kubernetesのkubeletがコンテナイメージのプルを完了した際に発行されるイベント通知「Pulled」の設計を記述する。

### 本通知の処理概要

kubeletのimageManagerがPodのコンテナに必要なイメージのプルを完了した際、またはイメージが既にローカルに存在する場合に本通知を発行する。イメージプルの完了を示す通知であり、Pullingイベントと対になる。

**業務上の目的・背景**：コンテナイメージのプル完了はPod起動の重要なマイルストーンである。この通知はPodのコンテナイメージが利用可能になったことを示す。プル所要時間やイメージサイズの情報も含まれるため、パフォーマンス分析やトラブルシューティングに活用できる。また、イメージが既にローカルに存在する場合も本通知が発行され、プル不要であったことを示す。

**通知の送信タイミング**：以下の3つのケースで発行される。(1) イメージが既にローカルに存在し再プル不要の場合（EnsureImageExists内）、(2) KubeletEnsureSecretPulledImages機能ゲート有効時にイメージがアクセス可能と判定された場合、(3) 実際のイメージプルが成功した場合（pullImage内）。

**通知の受信者**：Pod作成を要求したユーザー、Namespace管理者。Kubernetes Eventとして記録される。

**通知内容の概要**：イメージがローカルに存在する場合は「Container image "{イメージ名}" already present on machine」、プル完了時は「Successfully pulled image "{イメージ名}" in {プル時間} ({待機時間含む総時間} including waiting). Image size: {サイズ} bytes.」という形式。

**期待されるアクション**：通常は情報通知であり、ユーザーの介入は不要。プル所要時間が長い場合は、イメージサイズの最適化やレジストリの性能改善を検討する。

## 通知種別

Kubernetes Event（クラスタ内部イベント通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（EnsureImageExists/pullImage処理フロー内で即時発行） |
| 優先度 | 低（Normal） |
| リトライ | なし（完了通知のため） |

### 送信先決定ロジック

イベントの対象オブジェクトは、イメージプルが完了したコンテナの参照オブジェクト（ObjectReference）である。

## 通知テンプレート

### Kubernetes Eventの場合

| 項目 | 内容 |
|-----|------|
| EventType | Normal |
| Reason | Pulled |
| Regarding | 対象コンテナのObjectReference |
| 発行元 | kubelet |

### 本文テンプレート

ケース1: イメージがローカルに既存（KubeletEnsureSecretPulledImages無効時）
```
Container image "{requestedImage}" already present on machine
```

ケース2: イメージがローカルに既存かつアクセス可能（KubeletEnsureSecretPulledImages有効時）
```
Container image "{requestedImage}" already present on machine and can be accessed by the pod
```

ケース3: イメージプル完了
```
Successfully pulled image "{image}" in {pullDuration} ({imagePullDuration} including waiting). Image size: {imageSize} bytes.
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| requestedImage / image | コンテナイメージ名 | EnsureImageExistsの引数 | Yes |
| pullDuration | 実際のプル所要時間（ミリ秒単位切り捨て） | imagePullResult.pullDuration | ケース3のみ |
| imagePullDuration | プル開始からの総所要時間（待機含む） | time.Since(startTime) | ケース3のみ |
| imageSize | プルしたイメージのサイズ（バイト） | imagePullResult.imageSize | ケース3のみ |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | EnsureImageExists | imageRefが空でない かつ KubeletEnsureSecretPulledImages無効 | ローカルイメージ存在 |
| 内部処理 | EnsureImageExists | imageRefが空でない かつ pullRequired=false（KubeletEnsureSecretPulledImages有効時） | アクセス可能なイメージ存在 |
| 内部処理 | pullImage | puller.pullImageが成功 | プル完了 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| プル失敗 | puller.pullImageがエラーを返した場合、FailedToPullImageイベントが代わりに発行される |
| バックオフ中 | BackOffイベントが発行され、Pulledは発行されない |
| objRefがnil | logIt関数内でイベント記録がスキップされる |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[EnsureImageExists] --> B[imagePullPrecheck]
    B --> C{imageRef存在?}
    C -->|Yes| D{KubeletEnsureSecretPulledImages有効?}
    D -->|No| E[Event発行: Pulled - already present]
    D -->|Yes| F[MustAttemptImagePull]
    F --> G{pullRequired?}
    G -->|No| H[Event発行: Pulled - already present and accessible]
    G -->|Yes| I[pullImage]
    C -->|No| I
    I --> J[バックオフチェック]
    J -->|OK| K[Pullingイベント発行]
    K --> L[puller.pullImage実行]
    L --> M{プル成功?}
    M -->|Yes| N[RecordImageFinishedPulling]
    N --> O[Event発行: Pulled - Successfully pulled]
    M -->|No| P[FailedToPullImageイベント発行]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| コンテナランタイム | イメージ存在確認 | GetImageRef呼び出し |
| コンテナランタイム | イメージサイズ取得 | GetImageSize呼び出し |

### テーブル別参照項目詳細

#### Pod リソース

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| spec.containers[].image | プル対象イメージ名 | syncPod対象のPod |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| etcd (Event) | INSERT | Eventオブジェクトの作成 |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | reason | "Pulled" | イベント理由 |
| INSERT | message | 上記3パターンのいずれか | イメージ情報 |
| INSERT | type | "Normal" | イベントタイプ |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 該当なし | Pulledイベント自体はプル成功の通知であり、エラーは発生しない | - |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（Pulled通知は完了の情報通知） |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Event Recorderのデフォルトレート制限に準拠 |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

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

- イベントメッセージにはコンテナイメージ名が含まれる。プライベートレジストリのURL情報が含まれる可能性がある。
- イメージサイズ情報が含まれるが、機密性は低い。
- 認証情報はメッセージに含まれない。

## 備考

- imageManager.go内に3箇所のPulledイベント発行ポイントがある:
  1. 245行目: ローカルイメージ存在時（KubeletEnsureSecretPulledImages無効）
  2. 258行目: ローカルイメージがアクセス可能と判定された場合
  3. 374行目: 実際のイメージプル完了時
- プル完了時のメッセージにはpullDuration（実際のプル時間）とimagePullDuration（待機含む総時間）の2つの時間情報が含まれる（374-375行目）。
- ImagePullDurationメトリクスがイメージサイズバケット別に記録される（376行目）。
- podPullingTimeRecorder.RecordImageFinishedPulling（372行目、249行目、262行目）でプル完了時刻が記録される。
- バックオフのGC（ガベージコレクション）がプル成功時に実行される（377行目）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.go | `pkg/kubelet/events/event.go` | 48行目: `PulledImage = "Pulled"` 定数 |

**読解のコツ**: イベント定数名はPulledImageだが、Reason文字列は "Pulled" である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | image_manager.go | `pkg/kubelet/images/image_manager.go` | 164行目: EnsureImageExists関数 |

**主要処理フロー**:
1. **240-252行目**: イメージがローカルに存在する場合の処理（KubeletEnsureSecretPulledImages無効）
   - **244-245行目**: "already present on machine" メッセージでPulledイベント発行
2. **253-265行目**: KubeletEnsureSecretPulledImages有効時の処理
   - **257-258行目**: "already present on machine and can be accessed by the pod" メッセージ
3. **281行目**: pullImage呼び出し

#### Step 3: プル完了時のイベント発行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | image_manager.go | `pkg/kubelet/images/image_manager.go` | 371-381行目: プル成功後の処理 |

**主要処理フロー**:
- **372行目**: `RecordImageFinishedPulling` でプル完了記録
- **373行目**: プル所要時間の計算（ミリ秒単位切り捨て）
- **374-375行目**: "Successfully pulled image" メッセージでPulledイベント発行
- **376行目**: `ImagePullDuration` メトリクス記録
- **377行目**: バックオフのGC実行

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

```
imageManager.EnsureImageExists (image_manager.go:164)
    |
    +-- imagePullPrecheck
    |       +-- imageService.GetImageRef
    |
    +-- (ケース1: ローカル存在)
    |       +-- logIt (Pulled: already present)
    |       +-- RecordImageFinishedPulling
    |
    +-- (ケース2: KubeletEnsureSecretPulledImages)
    |       +-- imagePullManager.MustAttemptImagePull
    |       +-- logIt (Pulled: already present and accessible)
    |       +-- RecordImageFinishedPulling
    |
    +-- pullImage (image_manager.go:317)
            |
            +-- puller.pullImage
            +-- RecordImageFinishedPulling
            +-- logIt (Pulled: Successfully pulled)
            +-- ImagePullDuration メトリクス記録
            +-- backOff.GC
```

### データフロー図

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

Pod Spec (image) ----------> EnsureImageExists
                                |
                                +-- GetImageRef --> (存在チェック)
                                |       |
                                |       +-- 存在 --> Event (Normal/Pulled - already present)
                                |       |
                                |       +-- 不存在 --> pullImage
                                |                       |
                                |                       +-- puller.pullImage
                                |                       |       |
                                |                       |       +-- コンテナランタイム
                                |                       |
                                |                       +-- Event (Normal/Pulled - Successfully pulled)
                                |                       +-- ImagePullDuration メトリクス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/kubelet/events/event.go` | ソース | イベント理由定数の定義 |
| image_manager.go | `pkg/kubelet/images/image_manager.go` | ソース | イメージプル処理とイベント発行 |
