# 機能設計書 46-Preemptionプラグイン

## 概要

本ドキュメントは、Kubernetesスケジューラーの`DefaultPreemption`プラグインの機能設計を記述する。本プラグインは、通常のスケジューリングで配置先が見つからなかったPodに対して、低優先度Podの退避（Preemption）を実行し、配置先を確保するPostFilterプラグインである。

### 本機能の処理概要

**業務上の目的・背景**：クラスターのリソースが逼迫した場合に、優先度（Priority）の高いPodを配置するために、優先度の低いPodを退避させるメカニズムが必要である。DefaultPreemptionプラグインはこのプリエンプションロジックを実装する。

**機能の利用シーン**：Podが全ノードでフィルタ不合格となった場合にPostFilterとして呼び出される。PreemptionPolicy=Neverのpodは対象外。

**主要な処理内容**：
1. PostFilter: Evaluator.Preemptを呼び出してプリエンプション候補を評価
2. SelectVictimsOnNode: ノード上の最小限のVictim（被退避Pod）セットを選定
3. PodEligibleToPreemptOthers: Podのプリエンプション適格性を判定
4. PreEnqueue: 非同期プリエンプション実行中のPodを再エンキュー制限

**関連システム・外部連携**：PodDisruptionBudget（PDB）との連携、Extender APIとの連携。

**権限による制御**：フィーチャーゲート（EnableAsyncPreemption）により非同期プリエンプションが制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | スケジューラー内部プラグインとして自動実行 |

## 機能種別

プリエンプション / PostFilter

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| DefaultPreemptionArgs | config.DefaultPreemptionArgs | Yes | MinCandidateNodesPercentage、MinCandidateNodesAbsolute | ValidateDefaultPreemptionArgs |
| Pod | v1.Pod | Yes | プリエンプターPod | - |
| NodeToStatusReader | fwk.NodeToStatusReader | Yes | 各ノードのフィルタ結果 | - |

### 入力データソース

- Pod Priority（scheduling.k8s.io/v1）
- PodDisruptionBudget（policy/v1）
- ノード上の既存Pod情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PostFilterResult | fwk.PostFilterResult | プリエンプション結果（NominatedNodeName等） |
| VictimPods | []*v1.Pod | 退避対象Pod一覧 |

## 処理フロー

### 処理シーケンス

```
1. PostFilter: プリエンプション実行
   └─ Evaluator.Preempt
       ├─ PodEligibleToPreemptOthers で適格性チェック
       ├─ GetOffsetAndNumCandidates で候補ノード数決定
       └─ 各候補ノードに対して SelectVictimsOnNode を実行

2. SelectVictimsOnNode: Victim選定アルゴリズム
   ├─ 全eligible Pod（低優先度 + IsEligiblePod条件）を除去
   ├─ preemptorがフィットするか確認
   ├─ MoreImportantPod順で降順ソート
   ├─ PDB違反Victimから先にreprieve試行
   └─ 非PDB違反Victimのreprieve試行
       └─ reprieve: Victimを追加してフィルタを再実行、フィットすればVictimから除外

3. PodEligibleToPreemptOthers: 適格性判定
   ├─ PreemptionPolicy=Never なら不適格
   └─ NominatedNodeにTerminating Victimがいれば不適格

4. PreEnqueue: 非同期プリエンプション中の制限
   └─ IsPodRunningPreemptionがtrueなら再エンキュー拒否
```

### フローチャート

```mermaid
flowchart TD
    A[PostFilter: プリエンプション開始] --> B{Pod適格?}
    B -->|No: PreemptNever| C[プリエンプションなし]
    B -->|No: Terminating Victim存在| C
    B -->|Yes| D[候補ノード選定]
    D --> E[SelectVictimsOnNode: Victim選定]
    E --> F[全eligible Podを仮除去]
    F --> G{Preemptorフィット?}
    G -->|No| H[候補ノード不適格]
    G -->|Yes| I[重要度降順でソート]
    I --> J[PDB違反Victimのreprieve試行]
    J --> K[非PDB違反Victimのreprieve試行]
    K --> L[最終Victim一覧決定]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 優先度前提 | VictimのPriorityがPreemptorより低い必要あり | 常時 |
| BR-02 | PreemptNever | PreemptionPolicy=NeverのPodはプリエンプション不可 | PreemptionPolicy設定時 |
| BR-03 | PDB尊重 | PDB違反Victimを先にreprieve試行し、可能な限りPDBを守る | PDB存在時 |
| BR-04 | 最小Victim選定 | Victimセットを最小化するため、重要度の高いPodから順にreprieveを試行 | 常時 |
| BR-05 | Terminating Victim待ち | NominatedNodeにTerminating Victimがいる場合はプリエンプション猶予 | NominatedNode存在時 |
| BR-06 | 候補ノード数制限 | MinCandidateNodesPercentage/MinCandidateNodesAbsoluteで候補ノード数を制限 | 常時 |
| BR-07 | ランダムオフセット | 候補ノードの開始位置はランダムに決定 | 常時 |
| BR-08 | 非同期プリエンプション | EnableAsyncPreemption時、プリエンプション中のPodは再エンキュー制限 | フィーチャーゲート有効時 |

### 計算ロジック

**候補ノード数**: `n = max(numNodes * MinCandidateNodesPercentage / 100, MinCandidateNodesAbsolute)`（numNodesを上限）

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

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

| 操作 | 対象 | 内容 |
|------|------|------|
| Delete | Pod | Victim Podの削除（DisruptionTarget Condition設定後） |
| Update | Pod | Preemptor PodのNominatedNodeNameの設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UnschedulableAndUnresolvable | Victim不在 | eligible Victimが見つからない | 配置不可 |
| Error | プリエンプション失敗 | API呼び出し失敗 | 再試行 |

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

プリエンプションはAPI操作を伴うため、失敗時は状態を元に戻す。非同期プリエンプション（EnableAsyncPreemption）では、プリエンプション完了までPodの再エンキューを制限する。

## パフォーマンス要件

- 候補ノード数をMinCandidateNodesPercentage/Absoluteで制限し、大規模クラスターでの計算コストを抑制
- ランダムオフセットにより候補ノードの分散選択を実現

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

- PriorityベースのプリエンプションはRBACで制御されたPriorityClassに基づく
- PDB尊重によりサービス可用性を維持

## 備考

- IsEligiblePodFunc/MoreImportantPodFuncはカスタマイズ可能
- メトリクス: PreemptionAttempts カウンターが増加

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | default_preemption.go | `pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go` | DefaultPreemption構造体（64-81行目）、IsEligiblePodFunc/MoreImportantPodFuncの型定義（51-61行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | default_preemption.go | 同上 | New関数（92-118行目）、PostFilter（121-132行目） |

**主要処理フロー**:
- **92-118行目**: New - Evaluator初期化、デフォルトIsEligiblePod/MoreImportantPodの設定
- **121-132行目**: PostFilter - Evaluator.Preemptの呼び出し

#### Step 3: Victim選定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | default_preemption.go | 同上 | SelectVictimsOnNode（207-309行目） |

**主要処理フロー**:
- **235-244行目**: eligible Pod（低優先度+IsEligiblePod条件）の特定と仮除去
- **257-259行目**: Preemptorのフィット確認
- **264-266行目**: MoreImportantPod順ソート
- **270行目**: PDB違反/非違反の分類（filterPodsWithPDBViolation）
- **271-298行目**: reprieve試行ループ

#### Step 4: 適格性判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | default_preemption.go | 同上 | PodEligibleToPreemptOthers（319-343行目）、isPreemptionAllowed（351-354行目） |

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

```
New (初期化)
    └─ preemption.NewEvaluator
    │
    ├─ PostFilter
    │      └─ Evaluator.Preempt
    │             ├─ PodEligibleToPreemptOthers
    │             ├─ GetOffsetAndNumCandidates
    │             │      └─ calculateNumCandidates
    │             ├─ SelectVictimsOnNode
    │             │      ├─ isPreemptionAllowed
    │             │      │      └─ IsEligiblePod (カスタマイズ可)
    │             │      ├─ RunFilterPluginsWithNominatedPods
    │             │      ├─ MoreImportantPod (ソート)
    │             │      ├─ filterPodsWithPDBViolation
    │             │      └─ reprievePod (ループ)
    │             └─ CandidatesToVictimsMap
    │
    └─ PreEnqueue
           └─ Evaluator.IsPodRunningPreemption
```

### データフロー図

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

Pod (Preemptor)          ───▶  PodEligibleToPreemptOthers   ───▶  適格/不適格
Pod.Spec.PreemptionPolicy

NodeToStatusReader       ───▶  GetOffsetAndNumCandidates    ───▶  オフセット+候補数
DefaultPreemptionArgs

NodeInfo (既存Pod)       ───▶  SelectVictimsOnNode          ───▶  Victim一覧
PodDisruptionBudget             (Victim選定アルゴリズム)           numViolatingVictim
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| default_preemption.go | `pkg/scheduler/framework/plugins/defaultpreemption/default_preemption.go` | ソース | プラグイン全機能の実装 |
| evaluator.go | `pkg/scheduler/framework/preemption/evaluator.go` | ソース | Evaluator（Preemptメインロジック） |
