# 機能設計書 45-PodTopologySpreadプラグイン

## 概要

本ドキュメントは、Kubernetesスケジューラーの`PodTopologySpread`プラグインの機能設計を記述する。本プラグインはPodのTopologySpreadConstraintsに基づいて、トポロジードメイン（ゾーン、ノード等）間でのPodの分散配置を制御する。

### 本機能の処理概要

**業務上の目的・背景**：高可用性の実現のため、同一アプリケーションのPodを複数のトポロジードメインに分散配置する必要がある。TopologySpreadConstraintsにより、MaxSkew（最大偏り度）を指定して均等な分散を制御できる。

**機能の利用シーン**：Pod SpecにtopologySpreadConstraintsが定義されている場合、またはシステムデフォルト制約が設定されている場合に動作する。

**主要な処理内容**：
1. PreFilter: トポロジー制約を解析し、各トポロジードメインの既存マッチPod数を計算
2. Filter: MaxSkewを超過するノードを除外（WhenUnsatisfiable=DoNotSchedule時）
3. PreScore: Preferred制約（WhenUnsatisfiable=ScheduleAnyway）のトポロジースコアを計算
4. Score: 各ノードのトポロジードメインにおけるPod分散度に基づきスコアリング

**関連システム・外部連携**：Service、ReplicationController、ReplicaSet、StatefulSetのListerを使用してデフォルト制約のラベルセレクターを取得。

**権限による制御**：フィーチャーゲート（EnableNodeInclusionPolicyInPodTopologySpread、EnableMatchLabelKeysInPodTopologySpread、EnableSchedulingQueueHint、EnableTaintTolerationComparisonOperators）により動作が制御される。

## 関連画面

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

## 機能種別

フィルタリング / スコアリング / 分散配置制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| PodTopologySpreadArgs | config.PodTopologySpreadArgs | Yes | DefaultConstraints、DefaultingType | ValidatePodTopologySpreadArgs |
| Pod | v1.Pod | Yes | スケジュール対象Pod（TopologySpreadConstraints含む） | - |
| NodeInfo | fwk.NodeInfo | Yes | ノード情報（ラベル含む） | - |

### 入力データソース

- Pod.Spec.TopologySpreadConstraints
- 全ノードの既存Pod情報（SharedLister経由）
- Service/RC/RS/SSのLister（デフォルト制約のラベルセレクター取得用）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FilterStatus | fwk.Status | フィルタリング結果 |
| Score | int64 | トポロジー分散度スコア |

## 処理フロー

### 処理シーケンス

```
1. PreFilter: トポロジー制約の解析と既存Pod数の計算
   ├─ getConstraints: Pod SpecまたはデフォルトからDoNotSchedule制約を取得
   ├─ filterTopologySpreadConstraints/buildDefaultConstraints で制約を構築
   └─ 各トポロジードメインのマッチPod数を並列計算

2. Filter: MaxSkew検証
   └─ 各ノードのトポロジードメインにPodを追加した場合のskewを計算
   └─ MaxSkewを超過するノードを除外

3. PreScore: Preferred制約のトポロジースコア計算
   └─ ScheduleAnyway制約を取得
   └─ 各トポロジードメインのマッチPod数を並列計算

4. Score: トポロジー分散スコアの算出
   └─ 各制約のMaxSkew、トポロジー値毎のPod数に基づきスコアを計算
```

### フローチャート

```mermaid
flowchart TD
    A[PreFilter: 制約解析] --> B{DoNotSchedule制約あり?}
    B -->|No| C[Skip Filter]
    B -->|Yes| D[Filter: MaxSkew検証]
    D --> E{MaxSkew超過?}
    E -->|Yes| F[Unschedulable]
    E -->|No| G[フィルタ通過]
    G --> H[PreScore: ScheduleAnyway制約解析]
    H --> I[Score: 分散度スコアリング]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | DoNotSchedule | MaxSkewを超過するノードへの配置を禁止 | WhenUnsatisfiable=DoNotSchedule |
| BR-02 | ScheduleAnyway | MaxSkew超過でも配置可能だがスコアで不利 | WhenUnsatisfiable=ScheduleAnyway |
| BR-03 | SystemDefault | デフォルト制約なし/Pod制約なしの場合、hostname:MaxSkew=3/zone:MaxSkew=5 | DefaultingType=SystemDefaulting |
| BR-04 | NodeInclusionPolicy | Honor設定でTaint/Labelのフィルタリングを考慮 | EnableNodeInclusionPolicyInPodTopologySpread |
| BR-05 | MatchLabelKeys | MatchLabelKeysによる動的ラベルセレクター生成 | EnableMatchLabelKeysInPodTopologySpread |
| BR-06 | Signable制約 | TopologySpreadConstraintsを持つPodはSignable対象外 | SignPod呼び出し時 |

### 計算ロジック

**Filter**: ノードに新Podを追加した場合のskew（同一トポロジードメイン内のPod数差）がMaxSkewを超えるかを判定。

**Score**: 各制約について、Pod数が最小のトポロジードメインに近いノードほど高スコア。

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

本機能はデータベースへの直接操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Unschedulable | 制約不一致 | MaxSkew超過 | プリエンプションまたは別ノード検索 |
| ErrReasonNodeLabelNotMatch | ラベル不在 | トポロジーキーラベルがノードにない | 該当ノードをスキップ |

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

トランザクションは使用しない。

## パフォーマンス要件

- Parallelizerを使用した並列Pod数計算
- QueueingHintによりPod/Nodeの関連変更時のみ再スケジュール
- SystemDefault制約はScheduleAnywayのみで計算コストを抑制

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

- Namespace境界のラベルセレクター制約

## 備考

- SystemDefault制約: hostname MaxSkew=3、zone MaxSkew=5（ScheduleAnyway）
- NodeTaintsPolicy=Honor使用時はToleration変更でも再スケジュール対象

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | plugin.go | `pkg/scheduler/framework/plugins/podtopologyspread/plugin.go` | PodTopologySpread構造体（60-73行目）、systemDefaultConstraints（46-57行目） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | plugin.go | `pkg/scheduler/framework/plugins/podtopologyspread/plugin.go` | New関数（106-137行目）- SystemDefaulting判定、Lister設定 |

#### Step 3: イベント処理とQueueingHintを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | plugin.go | `pkg/scheduler/framework/plugins/podtopologyspread/plugin.go` | EventsToRegister（156-183行目）、isSchedulableAfterPodChange（206-274行目）、isSchedulableAfterNodeChange（302-362行目） |

**主要処理フロー**:
- **206-274行目**: Pod追加/更新/削除のQueueingHint - 制約セレクターとのマッチを検証
- **302-362行目**: Node追加/更新/削除のQueueingHint - トポロジーキーラベルの存在・変更を検証

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

```
New (初期化)
    ├─ systemDefaultConstraints の設定
    └─ setListers (Service/RC/RS/SS)
    │
    ├─ PreFilter
    │      ├─ getConstraints (DoNotSchedule)
    │      └─ 並列: 各ノードのマッチPod数計算
    │
    ├─ Filter
    │      └─ MaxSkew検証
    │
    ├─ PreScore
    │      ├─ getConstraints (ScheduleAnyway)
    │      └─ 並列: 各ノードのマッチPod数計算
    │
    └─ Score
           └─ トポロジー分散度に基づくスコア算出
```

### データフロー図

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

Pod.Spec.TopologySpreadConstraints ───▶  PreFilter             ───▶  preFilterState
systemDefaultConstraints                  (制約解析+Pod数計算)

preFilterState                     ───▶  Filter                ───▶  FilterStatus
NodeInfo.Labels                           (MaxSkew検証)

Pod制約(ScheduleAnyway)            ───▶  PreScore              ───▶  preScoreState
                                         (Preferred制約解析)

preScoreState                      ───▶  Score                 ───▶  Score (0-100)
NodeInfo.Labels                           (分散度スコアリング)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| plugin.go | `pkg/scheduler/framework/plugins/podtopologyspread/plugin.go` | ソース | プラグイン初期化、イベント登録、QueueingHint |
| filtering.go | `pkg/scheduler/framework/plugins/podtopologyspread/filtering.go` | ソース | PreFilter/Filterの実装 |
| scoring.go | `pkg/scheduler/framework/plugins/podtopologyspread/scoring.go` | ソース | PreScore/Scoreの実装 |
| common.go | `pkg/scheduler/framework/plugins/podtopologyspread/common.go` | ソース | 共通データ構造と制約構築 |
