# 機能設計書 44-VolumeBindingプラグイン

## 概要

本ドキュメントは、Kubernetesスケジューラーの`VolumeBinding`プラグインの機能設計を記述する。本プラグインはPodが参照するPersistentVolumeClaim（PVC）のバインディング状態を評価し、ボリュームの可用性とノード親和性に基づいてフィルタリング・スコアリング・ボリュームバインドを行う。

### 本機能の処理概要

**業務上の目的・背景**：ステートフルアプリケーションはPersistentVolumeを使用するため、Podのスケジューリング時にボリュームの可用性とノードの互換性を考慮する必要がある。WaitForFirstConsumer（遅延バインディング）モードでは、Podが実際にスケジュールされるノードに基づいてPVのバインドを行う。

**機能の利用シーン**：PVCを参照するPodのスケジューリング時に動作。特にStorageClassのvolumeBindingModeがWaitForFirstConsumerの場合に重要。

**主要な処理内容**：
1. PreFilter: PodのPVC参照を解析し、即時バインド未完了のPVCを検出
2. Filter: バインド済みPVのノード親和性、未バインドPVCの利用可能PV候補を評価
3. PreScore/Score: ストレージ容量に基づくスコアリング（EnableStorageCapacityScoring有効時）
4. Reserve: ボリュームバインドの仮定（Assume）
5. PreBind: PV ControllerへのAPIリクエストを発行し、実際のバインドを実行
6. Unreserve: 仮定の取消

**関連システム・外部連携**：PV Controller、CSI Driver、CSIStorageCapacity、StorageClass。

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

## 関連画面

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

## 機能種別

フィルタリング / スコアリング / バインディング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| VolumeBindingArgs | config.VolumeBindingArgs | Yes | BindTimeoutSeconds、Shape（スコアリング形状） | ValidateVolumeBindingArgs |
| Pod | v1.Pod | Yes | スケジュール対象Pod（Volumes参照含む） | - |
| NodeInfo | fwk.NodeInfo | Yes | ノード情報 | - |

### 入力データソース

- Pod.Spec.Volumes（PersistentVolumeClaim、Ephemeral）
- PersistentVolumeClaim（PVCLister経由）
- PersistentVolume（PVInformer経由）
- StorageClass（StorageClassInformer経由）
- CSINode/CSIDriver/CSIStorageCapacity（各Informer経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FilterStatus | fwk.Status | フィルタリング結果 |
| Score | int64 | ストレージ容量ベースのスコア |
| PodVolumes | *PodVolumes | ノード毎のボリュームバインド情報 |

## 処理フロー

### 処理シーケンス

```
1. PreFilter: PVC参照解析
   ├─ podHasPVCs でPVCの存在確認
   ├─ PVC未参照の場合はSkip
   ├─ GetPodVolumeClaims でPVCを分類
   │   ├─ boundClaims (バインド済み)
   │   ├─ unboundClaimsImmediate (即時バインド未完了)
   │   └─ unboundClaimsDelayBinding (遅延バインド)
   └─ unboundClaimsImmediateがあればUnschedulableAndUnresolvable

2. Filter: ボリューム適合チェック
   └─ FindPodVolumes
       ├─ バインド済みPVのノード親和性チェック
       ├─ 未バインドPVCに対する利用可能PV候補の検索
       └─ CSIストレージ容量チェック

3. PreScore/Score: ストレージ容量スコアリング
   └─ staticBindingsまたはdynamicProvisionsの容量使用率を計算
   └─ buildScorerFunction（Shape関数）によるスコア算出

4. Reserve: ボリュームバインド仮定
   └─ AssumePodVolumes でPV/PVCのバインドを仮定

5. PreBind: 実際のバインド実行
   └─ BindPodVolumes でAPI更新を実行し完了待ち

6. Unreserve: 仮定の取消
   └─ RevertAssumedPodVolumes でキャッシュを元に戻す
```

### フローチャート

```mermaid
flowchart TD
    A[PreFilter: PVC参照解析] --> B{PVCあり?}
    B -->|No| C[Skip]
    B -->|Yes| D{即時バインド未完了?}
    D -->|Yes| E[UnschedulableAndUnresolvable]
    D -->|No| F[Filter: ボリューム適合チェック]
    F --> G{PV/PVCマッチ?}
    G -->|No| H[UnschedulableAndUnresolvable]
    G -->|Yes| I[Score: 容量スコアリング]
    I --> J[Reserve: ボリュームバインド仮定]
    J --> K[PreBind: API更新でバインド実行]
    K --> L{バインド成功?}
    L -->|No| M[Unreserve: 仮定取消]
    L -->|Yes| N[完了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | PVCなしスキップ | PVCを参照しないPodは本プラグインの処理をスキップ | 常時 |
| BR-02 | 即時バインド要求 | Immediate bindingのPVCが未バインドの場合はUnschedulableAndUnresolvable | unboundClaimsImmediate > 0 |
| BR-03 | PVC消失エラー | PVCがClaimLost状態の場合はエラー | PVC.Status.Phase==ClaimLost |
| BR-04 | PVC削除中エラー | PVCにDeletionTimestampが設定されている場合はエラー | DeletionTimestamp != nil |
| BR-05 | Ephemeral Volume検証 | Ephemeral VolのPVCがPodに紐づいていることを検証 | Ephemeral Volume使用時 |
| BR-06 | ストレージ容量スコア | staticBindingsのCapacity/Requested比率に基づくスコアリング | EnableStorageCapacityScoring時 |
| BR-07 | バインドタイムアウト | BindPodVolumesはBindTimeoutSeconds後にタイムアウト | 常時 |

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

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

本プラグインはKubernetes APIサーバーを通じてPV/PVCリソースを更新する。

| 操作 | 対象 | 内容 |
|------|------|------|
| Update | PersistentVolume | PVのClaimRef設定 |
| Update | PersistentVolumeClaim | PVCのVolumeName設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UnschedulableAndUnresolvable | 即時バインド未完了 | ImmediateバインドPVCが未バインド | PV Controllerのバインド待ち |
| UnschedulableAndUnresolvable | PVノード親和性不一致 | バインド済みPVのノード親和性不一致 | 別ノード検索 |
| Error | バインド失敗 | PreBindでのAPI更新失敗 | Unreserve後に再試行 |

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

ボリュームバインドはAssume-Bind-Revertパターンで管理。Reserveで仮定、PreBindで確定、失敗時はUnreserveで仮定を取消。

## パフォーマンス要件

- FilterでのPodVolumes結果はノード毎にキャッシュ（stateData.podVolumesByNode）
- 並列Filterアクセスにはsync.Mutexで保護
- QueueingHintにより関連PVC/PV/StorageClassの変更時のみ再スケジュール

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

- PVCのNamespace制約を検証
- Ephemeral VolumeのPod所有者チェック

## 備考

- PreBindPreFlight: PreBind実行前に並列実行可能かを判定し、AllowParallel=trueを返す

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | volume_binding.go | `pkg/scheduler/framework/plugins/volumebinding/volume_binding.go` | stateData構造体（53-64行目）、VolumeBinding構造体（73-79行目） |

#### Step 2: プラグインライフサイクルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | volume_binding.go | `pkg/scheduler/framework/plugins/volumebinding/volume_binding.go` | New関数（618-662行目）でBinder/PVCLister/scorer等を初期化 |
| 2-2 | volume_binding.go | 同上 | PreFilter（360-390行目）→ Filter（424-453行目）→ Reserve（531-549行目）→ PreBind（577-600行目）→ Unreserve（604-615行目） |

**主要処理フロー**:
- **313-355行目**: podHasPVCs - PVC参照の存在確認とバリデーション
- **360-390行目**: PreFilter - PVC分類とstateDataの初期化
- **424-453行目**: Filter - FindPodVolumesの呼び出しとpodVolumesByNodeへの保存
- **531-549行目**: Reserve - AssumePodVolumesの呼び出し
- **577-600行目**: PreBind - BindPodVolumesの呼び出し

#### Step 3: スコアリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | volume_binding.go | `pkg/scheduler/framework/plugins/volumebinding/volume_binding.go` | Score（471-523行目）- staticBindings/dynamicProvisionsの容量計算 |

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

```
New (初期化)
    ├─ NewVolumeBinder
    └─ buildScorerFunction
    │
    ├─ PreFilter
    │      ├─ podHasPVCs
    │      └─ Binder.GetPodVolumeClaims
    │
    ├─ Filter
    │      └─ Binder.FindPodVolumes
    │
    ├─ Score
    │      └─ scorer(classResources)
    │
    ├─ Reserve
    │      └─ Binder.AssumePodVolumes
    │
    ├─ PreBind
    │      └─ Binder.BindPodVolumes
    │
    └─ Unreserve
           └─ Binder.RevertAssumedPodVolumes
```

### データフロー図

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

Pod.Spec.Volumes       ───▶  PreFilter                 ───▶  stateData (CycleState)
PVCLister                     (PVC分類)

stateData              ───▶  Filter                    ───▶  podVolumesByNode
NodeInfo                      (PV/PVCマッチング)

podVolumesByNode       ───▶  Score                     ───▶  Score (容量ベース)
                              (容量使用率計算)

podVolumesByNode       ───▶  Reserve                   ───▶  allBound (仮定完了)
                              (AssumePodVolumes)

podVolumesByNode       ───▶  PreBind                   ───▶  API更新完了
                              (BindPodVolumes)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| volume_binding.go | `pkg/scheduler/framework/plugins/volumebinding/volume_binding.go` | ソース | プラグイン全機能の実装 |
| binder.go | `pkg/scheduler/framework/plugins/volumebinding/binder.go` | ソース | SchedulerVolumeBinder実装 |
| scorer.go | `pkg/scheduler/framework/plugins/volumebinding/scorer.go` | ソース | スコアリング関数 |
