# 機能設計書 61-ステータス管理

## 概要

本ドキュメントは、KubeletにおけるPodおよびコンテナのステータスをAPI Serverに同期する「ステータス管理」機能の設計を記述する。

### 本機能の処理概要

KubeletのStatus Managerは、ノード上で実行中のPodおよびコンテナの状態をキャッシュし、API Serverとの間でステータス情報を同期する中核コンポーネントである。

**業務上の目的・背景**：Kubernetesクラスターにおいて、各ノード上のPodの正確な状態をAPI Serverに反映することは、コントローラーやスケジューラーが正しい判断を下すために不可欠である。Status Managerがなければ、Pod Phase（Pending/Running/Succeeded/Failed）、コンテナの準備状態（Ready/NotReady）、起動状態（Started）などの情報がAPI Serverに伝わらず、クラスター全体の状態管理が破綻する。

**機能の利用シーン**：(1) Podが起動・停止・再起動した際のステータス更新、(2) Liveness/Readiness/Startupプローブの結果に基づくコンテナ状態の変更、(3) Pod終了時のターミナルフェーズ移行、(4) Podリサイズ操作時のCondition管理、(5) Static Podのミラーポッドとのステータス同期。

**主要な処理内容**：
1. Pod/コンテナのステータスをバージョン付きでキャッシュに保持する
2. 10秒周期またはイベント駆動でAPI Serverにステータスをバッチ同期する
3. コンテナのReadiness/Startup状態の変更をPodConditionに反映する
4. Pod終了時に全コンテナのターミナル状態を保証する
5. API Serverとの間でステータスの整合性を検出・修復する（reconciliation）
6. Podリサイズに伴うPodResizePending/PodResizeInProgress Conditionの管理

**関連システム・外部連携**：API Server（Pod Status Patch API）、Pod Manager（Pod/MirrorPodの取得）、コンテナランタイム（コンテナ状態の取得元）。

**権限による制御**：Kubeletは自ノード上のPodのステータスのみ更新可能であり、NodeAuthorizer/NodeRestrictionプラグインにより他ノードのPod更新は禁止される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCLI画面との直接的な関連はなく、Kubelet内部コンポーネントとして動作する |

## 機能種別

データ連携（Kubelet内部キャッシュとAPI Server間のステータス同期）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pod | *v1.Pod | Yes | ステータスを更新する対象のPodオブジェクト | Pod UIDの存在確認 |
| status | v1.PodStatus | Yes | 新しいPodステータス | コンテナ状態遷移の正当性チェック |
| containerID | ContainerID | Yes (SetContainerReadiness/Startup) | 対象コンテナのID | Pod内に存在するコンテナIDであること |
| ready/started | bool | Yes (SetContainerReadiness/Startup) | コンテナの準備/起動状態 | - |

### 入力データソース

- Kubeletのsyncloop（Pod同期ループ）からのPodStatus
- ProberからのReadiness/Startup結果
- コンテナランタイムからのコンテナ状態変化イベント

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PodStatus | v1.PodStatus | API Serverに送信されるPodステータス（Phase、Conditions、ContainerStatuses含む） |
| PatchBytes | []byte | API Serverへ送信されるJSON Patchバイト列 |

### 出力先

- API Server: PATCH /api/v1/namespaces/{namespace}/pods/{name}/status
- ローカルキャッシュ: manager.podStatuses マップ

## 処理フロー

### 処理シーケンス

```
1. SetPodStatus/SetContainerReadiness/SetContainerStartup/TerminatePod
   └─ updateStatusInternalでキャッシュを更新しチャネルに通知
2. syncBatchがチャネル通知またはタイマー（10秒周期）で起動
   └─ 更新が必要なPodを選別
3. syncPodで個別Podのステータスを同期
   └─ API ServerからPodを取得し、mergePodStatusでステータスをマージ
4. PatchPodStatusでAPI Serverにパッチ送信
   └─ 成功時にapiStatusVersionsを更新
5. canBeDeletedの判定
   └─ 条件を満たせばPodを削除（DeletionTimestampが設定済み＋ターミナルフェーズ＋podIsFinished）
```

### フローチャート

```mermaid
flowchart TD
    A[ステータス変更イベント] --> B[updateStatusInternal]
    B --> C{キャッシュと同一か?}
    C -->|Yes| D[無視]
    C -->|No| E[キャッシュ更新・チャネル通知]
    E --> F[syncBatch]
    F --> G{更新必要?}
    G -->|No| H[スキップ]
    G -->|Yes| I[syncPod]
    I --> J[API ServerからPod取得]
    J --> K[mergePodStatus]
    K --> L[PatchPodStatus]
    L --> M{成功?}
    M -->|No| N[エラーログ・次回リトライ]
    M -->|Yes| O[apiStatusVersions更新]
    O --> P{削除可能?}
    P -->|Yes| Q[Pod削除]
    P -->|No| R[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-61-01 | バージョニング | 各Podのステータスは単調増加するバージョンで管理され、古いステータスは送信されない | 常時 |
| BR-61-02 | コンテナ状態遷移チェック | RestartPolicy=Always以外では、terminated状態からnon-terminated状態への遷移は禁止 | RestartPolicy != Always |
| BR-61-03 | ターミナルフェーズ遅延 | 実行中コンテナが存在する場合、PodPhaseのターミナル遷移は遅延される | Pod終了時 |
| BR-61-04 | Kubelet所有Condition | KubeletはPodReady, ContainersReady等の自身が所有するConditionのみ更新する | 常時 |
| BR-61-05 | StartTime不変 | 一度設定されたPodのStartTimeは変更されない | 常時 |

### 計算ロジック

- バージョン管理: `newStatus.version = cachedStatus.version + 1`（単調増加）
- Pod同期期間: `syncPeriod = 10 * time.Second`
- ステータス同期遅延メトリクス: `time.Since(status.at)`

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ステータス更新 | etcd (pods/status) | PATCH | PodStatusサブリソースのパッチ更新 |
| Pod削除 | etcd (pods) | DELETE | ターミナルPodの削除 |
| Pod取得 | etcd (pods) | GET | 同期前の最新Pod取得 |

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

#### etcd (pods/status)

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| PATCH | status.phase | Pending/Running/Succeeded/Failed | ターミナルフェーズ遷移は一方向 |
| PATCH | status.conditions | PodReady/ContainersReady等 | Kubelet所有Conditionのみ |
| PATCH | status.containerStatuses | コンテナ毎の状態 | Ready/Started/State等 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NotFound | API応答 | Pod が API Serverに存在しない | ログ出力しスキップ、RemoveOrphanedStatusesで削除 |
| Conflict | API応答 | UID不一致（Podが再作成された） | 古いステータスを削除 |
| 状態遷移エラー | 内部バリデーション | terminated -> non-terminated遷移 | ステータス更新を中止しエラーログ |

### リトライ仕様

- syncBatchは10秒間隔で全Podの同期を再試行する
- 個別のsyncPod失敗時は次回のsyncBatch実行時にリトライされる

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

各Podのステータス更新は個別のAPI呼び出し（PatchPodStatus）で行われ、Pod UIDをPreconditionとして使用することで再作成されたPodへの誤更新を防止する。

## パフォーマンス要件

- syncPeriod: 10秒ごとの定期同期
- イベント駆動: ステータス変更時はチャネル経由で即時同期
- バッチ処理: 複数Podの更新を一度のsyncBatchで処理
- メトリクス: PodStatusSyncDurationで同期遅延を監視

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

- NodeAuthorizer/NodeRestrictionにより、Kubeletは自ノードのPodのステータスのみ更新可能
- TerminationMessageは最大長（MaxPodTerminationMessageLogLength）で切り詰められ、過大なメッセージの送信を防止
- ステータス更新時にDeepCopyを使用し、キャッシュの意図しない変更を防止

## 備考

- Static Podはミラーポッド経由でステータスが管理される
- InPlacePodVerticalScalingフィーチャーゲートが有効な場合、PodResize関連のConditionが追加管理される

---

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

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

### 推奨読解順序

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

まず、ステータス管理の中心的なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | status_manager.go | `pkg/kubelet/status/status_manager.go` | versionedPodStatus構造体（51-64行目）: バージョン付きPodステータスの定義 |
| 1-2 | status_manager.go | `pkg/kubelet/status/status_manager.go` | manager構造体（68-82行目）: Status Managerの内部状態 |
| 1-3 | status_manager.go | `pkg/kubelet/status/status_manager.go` | Managerインターフェース（131-187行目）: 公開API定義 |

**読解のコツ**: `versionedPodStatus`のversionフィールドが単調増加するバージョン番号であり、古いステータスの上書きを防止する仕組みの核心である。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | status_manager.go | `pkg/kubelet/status/status_manager.go` | NewManager関数（192-203行目）: 初期化処理 |
| 2-2 | status_manager.go | `pkg/kubelet/status/status_manager.go` | Start関数（239-267行目）: 同期ループの開始 |

**主要処理フロー**:
1. **239-247行目**: kubeClientがnilの場合は起動しない（マスターノードでのブートストラップ対応）
2. **252行目**: 10秒間隔のTickerを生成
3. **255-266行目**: wait.Foreverで無限ループを開始し、チャネル通知またはタイマーでsyncBatchを呼び出す

#### Step 3: ステータス更新処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | status_manager.go | `pkg/kubelet/status/status_manager.go` | SetPodStatus（425-439行目）: Pod全体のステータス設定 |
| 3-2 | status_manager.go | `pkg/kubelet/status/status_manager.go` | updateStatusInternal（779-903行目）: 内部キャッシュ更新の中核ロジック |
| 3-3 | status_manager.go | `pkg/kubelet/status/status_manager.go` | syncBatch（956-1029行目）: バッチ同期処理 |
| 3-4 | status_manager.go | `pkg/kubelet/status/status_manager.go` | syncPod（1032-1106行目）: 個別Pod同期 |

**主要処理フロー**:
- **779-801行目**: コンテナ状態遷移の正当性チェック
- **804-820行目**: 各Conditionの LastTransitionTime更新
- **874-877行目**: 同一ステータスの場合はスキップ
- **1062行目**: mergePodStatusでKubelet所有/非所有のConditionをマージ
- **1064行目**: PatchPodStatusでAPI Serverにパッチ送信

#### Step 4: ステータス生成ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | generate.go | `pkg/kubelet/status/generate.go` | GenerateContainersReadyCondition（50-121行目）: ContainersReady条件生成 |
| 4-2 | generate.go | `pkg/kubelet/status/generate.go` | GeneratePodReadyCondition（126-168行目）: PodReady条件生成 |
| 4-3 | generate.go | `pkg/kubelet/status/generate.go` | GeneratePodInitializedCondition（185-268行目）: PodInitialized条件生成 |

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

```
Kubelet SyncLoop / Prober
    │
    ├─ SetPodStatus()
    │      └─ updateStatusInternal()
    │             ├─ checkContainerStateTransition()
    │             ├─ updateLastTransitionTime()
    │             ├─ normalizeStatus()
    │             └─ podStatusChannel <- notification
    │
    ├─ SetContainerReadiness()
    │      ├─ GeneratePodReadyCondition()
    │      ├─ GenerateContainersReadyCondition()
    │      └─ updateStatusInternal()
    │
    ├─ SetContainerStartup()
    │      └─ updateStatusInternal()
    │
    ├─ TerminatePod()
    │      └─ updateStatusInternal(forceUpdate=true, podIsFinished=true)
    │
    └─ Start() -> syncBatch loop
           ├─ needsUpdate() / needsReconcile()
           └─ syncPod()
                  ├─ kubeClient.CoreV1().Pods().Get()
                  ├─ mergePodStatus()
                  ├─ PatchPodStatus()
                  └─ canBeDeleted() -> kubeClient.CoreV1().Pods().Delete()
```

### データフロー図

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

コンテナランタイム状態 ───▶ SetPodStatus() ───▶ ローカルキャッシュ
                                                     │
Prober結果 ───────────▶ SetContainerReadiness() ──▶  │
                                                     │
Pod終了通知 ──────────▶ TerminatePod() ───────────▶  │
                                                     ▼
                                              syncBatch() ───▶ API Server (PATCH)
                                                     │
                                              canBeDeleted() ──▶ API Server (DELETE)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| status_manager.go | `pkg/kubelet/status/status_manager.go` | ソース | Status Managerの中核実装 |
| generate.go | `pkg/kubelet/status/generate.go` | ソース | Pod Condition生成ロジック |
| status_manager_test.go | `pkg/kubelet/status/status_manager_test.go` | テスト | Status Managerのユニットテスト |
| generate_test.go | `pkg/kubelet/status/generate_test.go` | テスト | Condition生成のユニットテスト |
| pod.go | `pkg/util/pod/pod.go` | ソース | PatchPodStatusユーティリティ |
| types.go | `pkg/kubelet/types/pod_update.go` | ソース | PodConditionByKubelet等の定義 |
