# 機能設計書 69-Preemption管理

## 概要

本ドキュメントは、Kubeletにおけるクリティカルポッドのプリエンプション（優先排除）機能の設計を記述する。

### 本機能の処理概要

CriticalPodAdmissionHandlerは、リソース不足でAdmission（受け入れ）に失敗したクリティカルPodを救済するため、優先度の低いPodをEvict（排除）してリソースを確保するコンポーネントである。

**業務上の目的・背景**：Kubernetesクラスターにおいて、kube-system名前空間のクリティカルPod（system-cluster-criticalまたはsystem-node-critical）は、ノードの正常動作に不可欠である。これらのPodがリソース不足で起動できない場合、優先度の低いPodを排除してリソースを確保する仕組みが必要である。

**機能の利用シーン**：(1) クリティカルPodのAdmission失敗時のリソース確保、(2) ノードのリソース逼迫時におけるクリティカルコンポーネントの優先起動。

**主要な処理内容**：
1. Admission失敗理由の分類（リソース不足 vs 非リソース問題）
2. QoSクラス（BestEffort/Burstable/Guaranteed）に基づくPod優先度の評価
3. 最小影響のPod選択アルゴリズム（最少数のPod排除で必要リソースを確保）
4. 選択されたPodの強制Kill（PodPhase=Failed、Reason=PreemptContainer）

**関連システム・外部連携**：Lifecycle Manager（Admission Handler Chain）、Eviction Manager（ActivePodsFunc/KillPodFunc）。

**権限による制御**：クリティカルPodの判定はPodPriorityに基づく。

## 関連画面

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

## 機能種別

リソース管理（プリエンプション）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| admitPod | *v1.Pod | Yes | Admission失敗したクリティカルPod | IsCriticalPodがtrueであること |
| failureReasons | []PredicateFailureReason | Yes | Admission失敗理由リスト | InsufficientResourceError含む |
| getPodsFunc | ActivePodsFunc | Yes (初期化時) | 実行中Podの取得関数 | - |
| killPodFunc | KillPodFunc | Yes (初期化時) | Pod強制Kill関数 | - |

### 入力データソース

- Lifecycle Manager: Admission失敗通知とその理由
- Active Pods: 現在ノード上で実行中のPodリスト
- Pod Spec: resourceRequestsによるリソース要求量

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 排除されたPod | []*v1.Pod | 強制Killされたpodリスト |
| PodStatus | v1.PodStatus | Phase=Failed, Reason=PreemptContainer |
| Events | v1.Event | PreemptContainerイベント |
| Metrics | Counter | Preemptionsメトリクス（リソースタイプ別） |

### 出力先

- Pod Kill: コンテナランタイムへのKillリクエスト
- Events: Kubernetesイベント記録
- Metrics: /metricsエンドポイント

## 処理フロー

### 処理シーケンス

```
1. HandleAdmissionFailure（Admission失敗ハンドリング）
   └─ クリティカルPod判定 → 失敗理由分類 → evictPodsToFreeRequests
2. evictPodsToFreeRequests（リソース確保のためのPod排除）
   └─ getPodsToPreempt → 各Podをkillする → メトリクス記録
3. getPodsToPreempt（排除対象Pod選択）
   └─ QoS分類 → Guaranteed排除候補 → Burstable排除候補 → BestEffort排除候補
4. getPodsToPreemptByDistance（距離ベースの最適Pod選択）
   └─ 要件までの距離計算 → 最近距離のPod選択 → 要件充足まで繰り返し
```

### フローチャート

```mermaid
flowchart TD
    A[Admission失敗] --> B{クリティカルPod?}
    B -->|No| C[失敗理由をそのまま返却]
    B -->|Yes| D{リソース不足のみ?}
    D -->|No| E[非リソース理由のみ返却]
    D -->|Yes| F[evictPodsToFreeRequests]
    F --> G[QoSクラス分類]
    G --> H[BestEffort候補]
    G --> I[Burstable候補]
    G --> J[Guaranteed候補]
    H --> K[最小影響Pod選択]
    I --> K
    J --> K
    K --> L[選択PodをKill]
    L --> M[メトリクス・イベント記録]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-69-01 | クリティカルPod限定 | プリエンプションはクリティカルPod（IsCriticalPod=true）のみ対象 | HandleAdmissionFailure |
| BR-69-02 | リソース不足限定 | 非リソース理由（ノードアフィニティ等）によるAdmission失敗はプリエンプション対象外 | HandleAdmissionFailure |
| BR-69-03 | QoS優先順位 | 排除優先順位: BestEffort > Burstable > Guaranteed（BestEffortから先に排除） | getPodsToPreempt |
| BR-69-04 | 最小影響 | 最少数のPod排除で必要リソースを確保する | getPodsToPreemptByDistance |
| BR-69-05 | Preemptable判定 | preemptor Podより低い優先度のPodのみ排除対象 | sortPodsByQOS |

### 計算ロジック

- 距離計算: `distance = sum(max(0, (remaining - podRequest) / total)^2)` for each resource
- smallerResourceRequest: Memory > CPUの優先順位で比較
- 必要リソース量: `InsufficientResourceError.GetInsufficientAmount()`

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

本機能はデータベースを直接操作しない。PodのKillはコンテナランタイムへの直接呼び出しで行われる。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | リソース不足 | 排除可能なPodが存在しても必要リソースを確保できない | エラー返却 |
| - | Kill失敗 | Pod強制Kill処理の失敗 | エラーログ出力、次回syncPodループでリトライ |
| - | Pod不存在 | 排除対象Podが既に終了済み | エラーログ出力、処理継続 |

### リトライ仕様

Pod Kill失敗時は、次回のsyncPodループでPod削除ステップがリトライされる。

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

該当なし。Pod KillはブロッキングCall（Podとコンテナが完全にKillされるまで待機）であり、個別に処理される。

## パフォーマンス要件

- getPodsToPreemptByDistanceは距離ベースの貪欲アルゴリズムで、Pod数に対してO(n^2)の計算量
- Pod Killはブロッキング操作のため、排除するPod数が多い場合は処理時間が増加

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

- クリティカルPodの判定はPodPriorityに基づく（Priority Based Preemption）
- 排除されたPodにはDisruptionTarget Condition（PodReasonTerminationByKubelet）が設定される
- KillされたPodのPodPhaseはFailedに設定され、ReasonがPreemptContainerとなる

## 備考

- Kubeletのプリエンプションはスケジューラーのプリエンプション（クラスター全体のPod配置最適化）とは異なり、ノード単位のリソース確保を目的とする
- メトリクス（Preemptions）はリソースタイプ別にカウントされる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | preemption.go | `pkg/kubelet/preemption/preemption.go` | CriticalPodAdmissionHandler構造体（46-50行目）: getPodsFunc/killPodFunc/recorder |
| 1-2 | preemption.go | `pkg/kubelet/preemption/preemption.go` | admissionRequirement構造体（193-196行目）: リソース名と必要量 |
| 1-3 | preemption.go | `pkg/kubelet/preemption/preemption.go` | admissionRequirementList型（198行目）: distance/subtractメソッド |

**読解のコツ**: `admissionRequirementList`の`distance`メソッドが最適Pod選択の核心。各リソース要件に対する「残り要求量/元の要求量」の二乗和でPodの「距離」を計算し、この距離が最小のPodを排除対象にする。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | preemption.go | `pkg/kubelet/preemption/preemption.go` | HandleAdmissionFailure（64-89行目）: メインエントリーポイント |

**主要処理フロー**:
- **65行目**: IsCriticalPod判定（falseならそのまま失敗理由を返す）
- **72-81行目**: InsufficientResourceError（リソース不足理由）とそれ以外を分類
- **82-84行目**: 非リソース理由がある場合はプリエンプションせず返却
- **86行目**: evictPodsToFreeRequestsを呼び出し

#### Step 3: Pod排除ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | preemption.go | `pkg/kubelet/preemption/preemption.go` | evictPodsToFreeRequests（94-130行目）: Pod排除の実行 |
| 3-2 | preemption.go | `pkg/kubelet/preemption/preemption.go` | getPodsToPreempt（133-157行目）: 排除候補の選択 |
| 3-3 | preemption.go | `pkg/kubelet/preemption/preemption.go` | sortPodsByQOS（246-262行目）: QoSクラス分類 |
| 3-4 | preemption.go | `pkg/kubelet/preemption/preemption.go` | getPodsToPreemptByDistance（165-191行目）: 距離ベース最適選択 |

**主要処理フロー**:
- **134行目**: BestEffort/Burstable/GuaranteedにQoS分類
- **137-140行目**: 全Pod排除でもリソース不足の場合はエラー
- **142-156行目**: Guaranteed→Burstable→BestEffortの順で最小排除セットを計算
- **100-128行目**: 選択されたPodをkillし、DisruptionTarget Conditionを設定

#### Step 4: 距離計算アルゴリズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | preemption.go | `pkg/kubelet/preemption/preemption.go` | distance（203-212行目）: Pod-要件間距離の計算 |
| 4-2 | preemption.go | `pkg/kubelet/preemption/preemption.go` | subtract（216-234行目）: Pod排除後の残り要件計算 |
| 4-3 | preemption.go | `pkg/kubelet/preemption/preemption.go` | smallerResourceRequest（265-280行目）: 同距離Pod間の優先順位 |

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

```
Lifecycle Manager (AdmissionHandler chain)
    │
    └─ HandleAdmissionFailure()
           ├─ IsCriticalPod()
           ├─ InsufficientResourceError分類
           └─ evictPodsToFreeRequests()
                  ├─ getPodsToPreempt()
                  │      ├─ sortPodsByQOS()
                  │      └─ getPodsToPreemptByDistance()
                  │             ├─ admissionRequirementList.distance()
                  │             ├─ admissionRequirementList.subtract()
                  │             └─ smallerResourceRequest()
                  │
                  ├─ recorder.Eventf() [PreemptContainer]
                  ├─ killPodFunc() [ブロッキング]
                  │      └─ PodStatus設定: Phase=Failed, Reason=PreemptContainer
                  └─ metrics.Preemptions.Inc()
```

### データフロー図

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

Admission失敗理由 ─────▶ HandleAdmissionFailure ──▶ リソース/非リソース分類
実行中Pod一覧 ─────────▶ sortPodsByQOS ───────────▶ QoSクラス別リスト
リソース要件 ──────────▶ getPodsToPreemptByDistance ▶ 排除対象Podリスト
排除対象Pod ──────────▶ killPodFunc ──────────────▶ Pod Kill + Event + Metrics
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| preemption.go | `pkg/kubelet/preemption/preemption.go` | ソース | プリエンプション管理の中核実装 |
| preemption_test.go | `pkg/kubelet/preemption/preemption_test.go` | テスト | プリエンプション管理のテスト |
| lifecycle.go | `pkg/kubelet/lifecycle/interfaces.go` | ソース | AdmissionFailureHandlerインターフェース |
| types.go | `pkg/kubelet/types/types.go` | ソース | IsCriticalPod/Preemptable関数 |
| eviction/ | `pkg/kubelet/eviction/` | ソース | ActivePodsFunc/KillPodFunc定義 |
