# 機能設計書 60-PLEG（Pod Lifecycle Event Generator）

## 概要

本ドキュメントは、Kubeletのコンテナランタイムの状態変化を検知してPodのライフサイクルイベントを生成するPLEG（Pod Lifecycle Event Generator）機能の設計を記載する。

### 本機能の処理概要

PLEGは、コンテナランタイムの現在の状態を定期的にポーリング（Relist）し、前回の状態との差分を比較してPodLifecycleEventを生成する。生成されたイベントはKubeletのメインSyncLoopに送信され、Podの状態同期をトリガーする。PLEGはKubeletがコンテナの状態変化を検知する主要なメカニズムであり、コンテナの起動、停止、削除を追跡する。

**業務上の目的・背景**：Kubeletはノード上のコンテナの実際の状態を常に把握し、API ServerのPodSpec（望ましい状態）と照合する必要がある。PLEGにより、コンテナランタイムの状態変化を効率的に検知し、必要なPod同期処理をトリガーする。PLEGが機能しないとKubeletはコンテナの変化を検知できず、ノードがNotReady状態になる。

**機能の利用シーン**：コンテナの起動完了検知、コンテナのクラッシュ/終了検知、コンテナの削除検知、Pod Watch Condition（特定状態変化の監視）。

**主要な処理内容**：
1. 定期的なRelist: コンテナランタイムからPod/コンテナ一覧を取得
2. 状態差分検出: 前回のPodレコードと現在の状態を比較
3. イベント生成: ContainerStarted、ContainerDied、ContainerRemoved、ContainerChanged、PodSync
4. キャッシュ更新: PodStatus情報をキャッシュに反映
5. Watch Condition: 特定条件を満たすまでPodを監視
6. ヘルスチェック: RelistのThreshold監視によるPLEGの健全性確認

**関連システム・外部連携**：CRI（GetPods、GetPodStatus API）、Kubelet SyncLoop（イベントチャネル経由）、Kubelet Cache（PodStatus情報）。

**権限による制御**：PLEGはKubelet内部コンポーネントであり、特別な権限制御はない。

## 関連画面

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

## 機能種別

監視処理 / イベント生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| RelistPeriod | time.Duration | Yes | Relist実行間隔 | 1秒以上推奨 |
| RelistThreshold | time.Duration | Yes | ヘルスチェック閾値 | RelistPeriodより大きい |
| cache | kubecontainer.Cache | Yes | PodStatusキャッシュ | nilでないこと |

### 入力データソース

- CRI GetPods API: ランタイム上のPod/コンテナ一覧
- CRI GetPodStatus API: 個別PodのPodStatus

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PodLifecycleEvent | *PodLifecycleEvent | Pod/コンテナの状態変化イベント |
| PodStatus | *kubecontainer.PodStatus | 更新されたPodStatus情報 |

### 出力先

- eventChannel: KubeletのSyncLoopへのイベント送信チャネル
- cache: PodStatus情報のキャッシュ更新
- Prometheusメトリクス（pleg_relist_interval_seconds、pleg_relist_duration_seconds、pleg_last_seen_seconds）

## 処理フロー

### 処理シーケンス

```
1. PLEG起動（Start）
   └─ RelistPeriod間隔でRelistを実行するgoroutine開始
2. Relist実行
   └─ CRI GetPods → 前回との差分検出 → イベント生成
3. イベント送信
   └─ eventChannelへPodLifecycleEvent送信
4. キャッシュ更新
   └─ CRI GetPodStatus → cacheに反映
5. Watch Condition評価
   └─ 設定された条件をPodStatusに対して評価、条件成立時にConditionMetイベント送信
6. ヘルスチェック
   └─ Healthy()でRelistThreshold以内にRelistが実行されたか確認
```

### フローチャート

```mermaid
flowchart TD
    A[Start] --> B[Relistループ開始]
    B --> C[CRI GetPods]
    C --> D[podRecords更新]
    D --> E[各PodのコンテナID比較]
    E --> F{状態変化あり?}
    F -->|Yes| G[generateEvents]
    F -->|No| H{watchCondition/reinspect?}
    G --> I[updateCache]
    H -->|Yes| I
    H -->|No| J[次回Relistまで待機]
    I --> K{キャッシュ更新成功?}
    K -->|Yes| L[eventChannel送信]
    K -->|No| M[needsReinspectに追加]
    L --> N[watchCondition評価]
    N --> O{条件成立?}
    O -->|Yes| P[ConditionMetイベント送信]
    O -->|No| Q[podRecords.old更新]
    P --> Q
    M --> J
    Q --> J
    J --> B
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-60-01 | 状態遷移イベント | running→exited=ContainerDied、non-existent→running=ContainerStarted等 | Relist時 |
| BR-60-02 | ヘルスチェック | RelistThreshold以内にRelistが実行されなければUnhealthy | Healthy()呼び出し時 |
| BR-60-03 | Reinspect | キャッシュ更新失敗のPodは次回Relistで再検査 | Relist時 |
| BR-60-04 | Watch Condition | SetPodWatchConditionで設定された条件が成立するまでPodを毎回検査 | Relist時 |
| BR-60-05 | Evented PLEG連携 | EventedPLEGフィーチャーゲート有効時はCRIイベント駆動と併用 | EventedPLEG有効時 |

### 計算ロジック

- plegContainerState遷移マトリクス:
  - running → exited: ContainerDied
  - non-existent → running: ContainerStarted
  - running → unknown: ContainerChanged
  - exited → non-existent: ContainerRemoved
  - running → non-existent: ContainerDied + ContainerRemoved

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Pod追跡 | podRecords（インメモリ） | INSERT/UPDATE/DELETE | Pod/コンテナ状態の追跡 |
| キャッシュ | cache（インメモリ） | UPDATE | PodStatusのキャッシュ更新 |
| 再検査 | podsToReinspect（インメモリ） | INSERT/DELETE | 再検査対象Podの管理 |

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

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

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | old | 前回のPod状態 | Relist完了後にcurrentをoldに移動 |
| UPDATE | current | 現在のPod状態 | Relist時にGetPodsの結果で更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| GetPodsError | CRIエラー | コンテナランタイムからPod一覧取得失敗 | ログ記録、次回Relistで再試行 |
| GetPodStatusError | CRIエラー | PodStatus取得失敗 | podsToReinspectに追加、次回再試行 |
| PLEGNotHealthy | ヘルスエラー | RelistThreshold超過 | ノードNotReady、Kubelet再起動検討 |

### リトライ仕様

- GetPods失敗: 次回Relistで自動再試行
- GetPodStatus失敗: podsToReinspectに追加し次回Relistで再検査
- Relist間隔: RelistPeriod（デフォルト1秒）

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

relistLock（sync.Mutex）によるRelist処理の排他制御。watchConditionsLock（sync.Mutex）によるWatch Condition管理の排他制御。runningMu（sync.Mutex）による開始/停止の排他制御。

## パフォーマンス要件

- Relist間隔: RelistPeriod（デフォルト1秒）
- Relist処理時間: RelistThreshold以内に完了する必要がある
- 大量のPod変更時はRelist処理時間が増加するため注意
- メトリクス: pleg_relist_duration_secondsで監視

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

- CRIとの通信はUnix Domainソケット
- PLEGはKubelet内部コンポーネントであり外部からのアクセスはない

## 備考

- GenericPLEGはポーリングベースの実装。EventedPLEGフィーチャーゲート有効時はCRIイベント駆動のEventedPLEGと併用される
- PLEGのUnhealthyはKubeletのヘルスチェックに直結し、ノードがNotReady状態になる主要な原因の1つ
- WatchCondition機能はRunningContainerWatchConditionヘルパーにより、コンテナの特定状態を監視可能
- ConditionMetイベントはWatch Condition成立時に送信される新しいイベント型

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pleg.go | `pkg/kubelet/pleg/pleg.go` | PodLifeCycleEventType、PodLifecycleEvent、PodLifecycleEventGenerator インターフェース |

**読解のコツ**: pleg.goはインターフェース定義のみ。PodLifeCycleEventTypeの各定数（ContainerStarted、ContainerDied等）とPodLifecycleEventGeneratorインターフェース（Start、Watch、Healthy、SetPodWatchCondition）を理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | generic.go | `pkg/kubelet/pleg/generic.go` | GenericPLEG構造体、NewGenericPLEG、Start |

**主要処理フロー**:
1. **53-85行目**: GenericPLEG構造体 - runtime、eventChannel、podRecords、cache、watchConditions
2. **128-145行目**: NewGenericPLEG - インスタンス初期化
3. **155-163行目**: Start - Relistをgoroutineで定期実行
4. **180-192行目**: Healthy - RelistThresholdとの比較でヘルスチェック

#### Step 3: Relist処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | generic.go | `pkg/kubelet/pleg/generic.go` | Relist、generateEvents、updateCache |

**主要処理フロー**:
- **234-335行目**: Relist - メインのポーリングループ（GetPods → 差分検出 → イベント生成 → キャッシュ更新）
- **194-218行目**: generateEvents - 状態遷移に基づくイベント生成
- **98-103行目**: plegContainerState定数（running、exited、unknown、non-existent）
- **105-119行目**: convertState - kubecontainer.StateからplegContainerStateへの変換

#### Step 4: Evented PLEGを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | evented.go | `pkg/kubelet/pleg/evented.go` | EventedPLEG - CRIイベント駆動の実装 |

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

```
Kubelet.Run()
    |
    +-- GenericPLEG.Start()
    |       +-- Relist() [RelistPeriod間隔]
    |               +-- runtime.GetPods(ctx, true) [CRI]
    |               +-- podRecords.setCurrent()
    |               +-- [各Podに対して]
    |               |       +-- computeEvents() / generateEvents()
    |               |       +-- updateCache()
    |               |       |       +-- runtime.GetPodStatus() [CRI]
    |               |       |       +-- cache.Set()
    |               |       +-- eventChannel <- PodLifecycleEvent
    |               |
    |               +-- [WatchCondition評価]
    |                       +-- condition(status)
    |                       +-- eventChannel <- ConditionMet
    |
    +-- Kubelet.syncLoop()
            +-- <- plegCh (eventChannel)
            +-- SyncPod()
```

### データフロー図

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

CRI GetPods              ──▶  Relist()              ──▶  podRecords更新
(コンテナ一覧)

前回podRecords(old)      ──▶  generateEvents()      ──▶  PodLifecycleEvent
現在podRecords(current)        |
                               v
CRI GetPodStatus         ──▶  updateCache()          ──▶  cache更新
                               |
                               v
                         eventChannel              ──▶  Kubelet SyncLoop
                                                         (Pod同期トリガー)

WatchCondition           ──▶  condition(status)      ──▶  ConditionMetイベント
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pleg.go | `pkg/kubelet/pleg/pleg.go` | ソース | インターフェース・型定義 |
| generic.go | `pkg/kubelet/pleg/generic.go` | ソース | GenericPLEG（ポーリングベース）実装 |
| evented.go | `pkg/kubelet/pleg/evented.go` | ソース | EventedPLEG（CRIイベント駆動）実装 |
| doc.go | `pkg/kubelet/pleg/doc.go` | ソース | パッケージドキュメント |
