# 通知設計書 24-BackOff (PullImage)

## 概要

本ドキュメントは、コンテナイメージのプルがバックオフ状態にある場合に発行されるイベント通知「BackOff (PullImage)」の設計を定義する。

### 本通知の処理概要

以前のイメージプル失敗後のバックオフ期間中に再度イメージプルが要求された場合に、kubeletのimageManagerがNormalイベントとしてKubernetes Event APIに記録する通知である。

**業務上の目的・背景**：イメージプル失敗後、kubeletはexponential backoffメカニズムにより一定時間の待機を行う。この待機期間中のプル試行を抑止し、レジストリへの過負荷を防止する。本通知は、イメージプルがバックオフ状態にあることを運用者に伝え、前回のプル失敗の原因解決を促すために発行される。

**通知の送信タイミング**：kubeletがイメージプルを試行する際、backoff期間チェック（`backOff.IsInBackOffSinceUpdate()`）でバックオフ中と判定された時点で発行される。実際のCRIランタイムへのプルリクエストは送信されない。

**通知の受信者**：Kubernetes Event APIを通じて、対象PodのObjectReferenceに紐づくイベントとして記録される。kubectl describe pod等で確認可能。

**通知内容の概要**：バックオフ中のイメージ名と、前回のプル失敗時のエラーメッセージ（利用可能な場合）を含むメッセージが通知される。

**期待されるアクション**：受信者はこのイベントが繰り返し発生している場合、前回のイメージプル失敗（No.21 Failed PullImage）の原因を調査・解決する必要がある。具体的には、レジストリの可用性確認、認証情報の修正、イメージ名の確認などを行う。

## 通知種別

Kubernetes Event（APIリソース）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（イメージプル処理内で即時実行） |
| 優先度 | 中（EventType: Normal） |
| リトライ | バックオフ期間終了後に自動的にイメージプルが再試行される |

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

対象PodのObjectReference（`*v1.ObjectReference`）に対してイベントが記録される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | N/A（Kubernetes Event） |
| 送信元名称 | kubelet |
| 件名 | N/A |
| 形式 | テキスト |

### 本文テンプレート

基本メッセージ:
```
Back-off pulling image "{イメージ名}"
```

前回のエラー情報が利用可能な場合:
```
Back-off pulling image "{イメージ名}": {前回のエラーメッセージ}
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | - | - | Kubernetes Eventのため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| image | プル対象のコンテナイメージ名 | pullImage引数 | Yes |
| prevPullErrMsg | 前回のプル失敗時のエラーメッセージ | sync.Mapに保存された前回エラー | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部処理 | pullImage呼び出し時のbackoffチェック | backOff.IsInBackOffSinceUpdate()がtrueの場合 | pullImage関数337-350行目 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| バックオフ期間外 | バックオフ期間が終了している場合は通常のプル処理が実行される |
| ObjectReferenceがnil | klogへのInfoログ出力のみ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[pullImage呼び出し] --> B{backoff期間中?}
    B -->|はい| C[BackOffイベント発行]
    C --> D{前回エラーメッセージあり?}
    D -->|あり| E[メッセージに前回エラーを付加]
    D -->|なし| F[基本メッセージのみ]
    E --> G[ErrImagePullBackOff返却]
    F --> G
    B -->|いいえ| H[Pullingイベント発行]
    H --> I[CRIランタイムへプルリクエスト]
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| N/A | - | sync.Mapに保存された前回エラーメッセージを参照 |

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

本通知はデータベースを直接参照しない。インメモリのsync.Map（prevPullErrMsg）から前回のエラーメッセージを取得する。

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event APIリソース（etcd） | INSERT | Normalイベントの記録 |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Type | Normal | EventType |
| INSERT | Reason | BackOff | イベント理由 |
| INSERT | Message | "Back-off pulling image..." | バックオフメッセージ |
| INSERT | InvolvedObject | Pod ObjectReference | 対象Pod |
| INSERT | Source.Component | kubelet | 発行元コンポーネント |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ErrImagePullBackOff | バックオフ期間中のプル要求 | バックオフ期間の終了を待つ、または根本原因を解決 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | バックオフ期間終了後に自動リトライ |
| リトライ間隔 | exponential backoff（flowcontrol.Backoff） |
| リトライ対象エラー | ErrImagePullBackOff |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | EventRecorderのバースト設定に依存 |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（24時間365日）

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

- 前回のプル失敗時のエラーメッセージが付加されるため、レジストリURLやエラー詳細が含まれる可能性がある
- RBACによるEventリソースへのアクセス制御が適用される

## 備考

- backoffキーは`{podUID}_{image}`形式で生成され、Pod単位・イメージ単位でバックオフが管理される（image_manager.go 336行目）
- backOff.GC()によるガベージコレクションが、プル成功時に実行される（377行目）
- prevPullErrMsg.Delete()により、バックオフ期間外のプル再試行時に前回エラーがクリアされる（352行目）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `pkg/kubelet/images/types.go` | ErrImagePullBackOff = errors.New("ImagePullBackOff") 定義（29行目） |
| 1-2 | event.go | `pkg/kubelet/events/event.go` | BackOffPullImage = "BackOff" 定数定義（52行目） |
| 1-3 | image_manager.go | `pkg/kubelet/images/image_manager.go` | imageManager構造体のbackOff, prevPullErrMsgフィールド（62-63行目） |

**読解のコツ**: backOffフィールドはflowcontrol.Backoff型であり、exponential backoffのロジックはclient-goライブラリに実装されている。

#### Step 2: BackOffイベント発行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | image_manager.go | `pkg/kubelet/images/image_manager.go` | pullImage関数内のbackoffチェック（337-350行目） |

**主要処理フロー**:
1. **336行目**: backOffKey生成（podUID_image形式）
2. **337行目**: IsInBackOffSinceUpdateでバックオフ期間判定
3. **338行目**: "Back-off pulling image" メッセージ生成
4. **339行目**: logItによるBackOffイベント発行（events.BackOffPullImage使用、EventType: Normal）
5. **344-347行目**: prevPullErrMsgから前回エラーを取得し、メッセージに付加
6. **349行目**: ErrImagePullBackOffを返却

#### Step 3: バックオフ設定処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | image_manager.go | `pkg/kubelet/images/image_manager.go` | プル失敗時のbackoff設定（363行目）とエラーメッセージ保存（368行目） |
| 3-2 | image_manager.go | `pkg/kubelet/images/image_manager.go` | プル成功時のbackoff GC（377行目）とエラーメッセージ削除（352行目） |

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

```
kuberuntime_manager.go: startContainer()
    |
    +-- imagePuller.EnsureImageExists()         [image_manager.go:164]
            |
            +-- pullImage()                      [image_manager.go:317]
                    |
                    +-- backOff.IsInBackOffSinceUpdate()  [337行目]
                    |       |
                    |       +-- (true) logIt() --> BackOffイベント発行 [339行目]
                    |       +-- prevPullErrMsg.Load()     [344行目]
                    |       +-- return ErrImagePullBackOff [349行目]
                    |
                    +-- (false) puller.pullImage()  (通常プル処理)
                            +-- (失敗) backOff.Next()    [363行目]
                            +-- (失敗) prevPullErrMsg.Store() [368行目]
                            +-- (成功) backOff.GC()      [377行目]
```

### データフロー図

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

Pod spec               --> pullImage()                     --> ErrImagePullBackOff
  podUID + image            |
                            +-- backOff.IsInBackOffSinceUpdate()
                            |       (backOffKey = podUID_image)
                            |
prevPullErrMsg         --> Load(backOffKey)                 --> メッセージ付加
  (sync.Map)                |
                            +-- logIt()                     --> Kubernetes Event API
                                recorder.Event()                (Normal/BackOff)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/kubelet/events/event.go` | ソース | BackOffPullImage定数定義 |
| types.go | `pkg/kubelet/images/types.go` | ソース | ErrImagePullBackOffエラー定義 |
| image_manager.go | `pkg/kubelet/images/image_manager.go` | ソース | バックオフチェック、BackOffイベント発行、エラーメッセージ管理 |
| kubelet.go | `pkg/kubelet/kubelet.go` | ソース | imageBackOff初期化パラメータの設定 |
