# 機能設計書 41-NodeResourcesプラグイン

## 概要

本ドキュメントは、Kubernetesスケジューラーの`NodeResourcesFit`プラグインおよび`NodeResourcesBalancedAllocation`プラグインの機能設計を記述する。これらのプラグインはノードのリソース容量（CPU、メモリ、エフェメラルストレージ、スカラーリソース）に基づいて、Podのスケジューリング時にフィルタリングとスコアリングを行う。

### 本機能の処理概要

**業務上の目的・背景**：Kubernetesクラスター内の各ノードには有限のリソース（CPU、メモリ、ストレージ等）がある。Podをスケジュールする際に、ノードのリソース容量と既存Podの使用量を考慮し、要求リソースを満たせるノードにのみ配置する必要がある。本プラグインはこのリソースベースのフィルタリングとスコアリングを実現し、リソースの過剰割り当てを防止する。

**機能の利用シーン**：全てのPodスケジューリングにおいて本プラグインが自動的に動作する。CPU/メモリの要求を持つPodが作成された場合、ノードの空き容量に基づいてフィルタリングされ、スコアリング戦略に基づいて最適なノードが選択される。

**主要な処理内容**：
1. PreFilter: Podのリソース要求量（CPU、メモリ、エフェメラルストレージ、スカラーリソース）を事前計算し、CycleStateに保存
2. Filter: 各ノードのAllocatable（割当可能量）とRequested（使用済み量）を比較し、Podの要求量を満たせないノードを除外
3. PreScore: スコアリングに必要なPodリソース要求リストを計算し、CycleStateに保存
4. Score: 設定されたスコアリング戦略（LeastAllocated / MostAllocated / RequestedToCapacityRatio）に基づいてノードにスコアを付与
5. BalancedAllocation: CPU/メモリの使用率バランスを評価し、リソース使用率が均等なノードを優先

**関連システム・外部連携**：DRA（Dynamic Resource Allocation）との連携により、DRAベースの拡張リソースのフィルタリング・スコアリングもサポート。DeviceClassリソースの監視イベントにも対応。

**権限による制御**：フィーチャーゲート（EnableInPlacePodVerticalScaling、EnableSidecarContainers、EnablePodLevelResources、EnableDRAExtendedResource等）により動作が制御される。

## 関連画面

本機能はバックエンド処理であり、直接的な画面関連はない。

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

## 機能種別

計算処理 / フィルタリング / スコアリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| NodeResourcesFitArgs | config.NodeResourcesFitArgs | Yes | フィルタリング設定（IgnoredResources、IgnoredResourceGroups） | ValidateNodeResourcesFitArgs |
| ScoringStrategy | config.ScoringStrategy | Yes | スコアリング戦略（LeastAllocated/MostAllocated/RequestedToCapacityRatio） | Type、Resources、Weightが必要 |
| Pod | v1.Pod | Yes | スケジュール対象のPod | - |
| NodeInfo | fwk.NodeInfo | Yes | ノード情報（Allocatable、Requested含む） | - |

### 入力データソース

- Pod仕様（v1.Pod.Spec.Containers、InitContainers、Overhead）
- ノード情報（NodeInfo.Allocatable、NodeInfo.Requested）
- DRAリソーススライスおよびDeviceClass情報（DRA拡張リソース有効時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FilterStatus | fwk.Status | フィルタリング結果（nil=通過、Unschedulable=リソース不足） |
| Score | int64 | ノードスコア（0-100） |
| InsufficientResources | []InsufficientResource | リソース不足の詳細（ResourceName、Reason、Requested、Used、Capacity） |

### 出力先

スケジューラーフレームワークのCycleStateおよびスケジューリング結果

## 処理フロー

### 処理シーケンス

```
1. PreFilter: Podリソース要求の事前計算
   └─ computePodResourceRequest でPodの全リソース要求を集計
   └─ InitContainersの最大値とContainersの合計値のmax
   └─ Overheadを加算
   └─ preFilterStateKeyでCycleStateに保存

2. Filter: ノードリソース適合チェック
   └─ getPreFilterState でCycleStateから事前計算結果を取得
   └─ fitsRequest で各リソースの充足性を検証
      ├─ Pod数上限チェック
      ├─ CPU空き容量チェック
      ├─ メモリ空き容量チェック
      ├─ エフェメラルストレージ空き容量チェック
      └─ スカラーリソース空き容量チェック（DRA委譲含む）

3. PreScore: スコアリング用データの事前計算
   └─ calculatePodResourceRequestList でリソース別要求量リストを作成
   └─ DRA拡張リソース有効時: getDRAPreScoredParams で割当状態取得
   └─ preScoreStateKeyでCycleStateに保存

4. Score: ノードスコアの算出
   └─ 戦略に応じたscorerを実行
      ├─ LeastAllocated: 空きリソースが多いほど高スコア
      ├─ MostAllocated: 使用リソースが多いほど高スコア
      └─ RequestedToCapacityRatio: カスタム関数形状に基づくスコア
```

### フローチャート

```mermaid
flowchart TD
    A[PreFilter: Pod リソース要求計算] --> B[CycleState に保存]
    B --> C[Filter: ノード毎にリソース判定]
    C --> D{リソース充足?}
    D -->|Yes| E[フィルタ通過]
    D -->|No| F[Unschedulable]
    E --> G[PreScore: スコア用データ計算]
    G --> H[Score: 戦略に基づくスコア算出]
    H --> I{LeastAllocated?}
    H --> J{MostAllocated?}
    H --> K{RequestedToCapacityRatio?}
    I --> L["score = (capacity - requested) * MaxNodeScore / capacity"]
    J --> M["score = requested * MaxNodeScore / capacity"]
    K --> N["score = brokenLinearFunction(utilization)"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | Pod数上限 | ノード上のPod数がAllowedPodNumberを超える場合はフィルタ失敗 | 常時 |
| BR-02 | CPU充足 | 要求CPU > (Allocatable CPU - Requested CPU)の場合はフィルタ失敗 | CPU要求 > 0 |
| BR-03 | メモリ充足 | 要求Memory > (Allocatable Memory - Requested Memory)の場合はフィルタ失敗 | Memory要求 > 0 |
| BR-04 | 解決不能判定 | 要求量がAllocatable自体を超える場合はUnschedulableAndUnresolvable | 常時 |
| BR-05 | IgnoredResources | 指定された拡張リソースはフィルタリング対象外 | 設定時 |
| BR-06 | DRA委譲 | DeviceClassマッピングが存在しNodeのAllocatableに0のリソースはDRAに委譲 | DRAExtendedResource有効時 |
| BR-07 | BestEffortスキップ | BalancedAllocationではBestEffort Podのスコアリングをスキップ | 全リソース要求が0 |

### 計算ロジック

**LeastAllocated**: `score = ((capacity - requested) * MaxNodeScore) / capacity`（リソース毎に重み付き平均）

**MostAllocated**: `score = (requested * MaxNodeScore) / capacity`（リソース毎に重み付き平均）

**BalancedAllocation**: `score = (1 - std) * MaxNodeScore`（stdはリソース使用率の標準偏差）。Pod追加前後のバランス改善度も考慮。

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

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

本機能はデータベースへの直接操作は行わない。全てインメモリのCycleState上で計算が行われる。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Unschedulable | スケジュール不可 | リソース不足だがプリエンプションで解消可能 | スケジューラーがプリエンプションを試行 |
| UnschedulableAndUnresolvable | スケジュール不可（解決不能） | 要求量がノード容量自体を超過 | 別ノードを検索、該当ノードはスキップ |
| Error | 内部エラー | CycleStateからの読み取り失敗 | スケジューリングサイクルの再試行 |

### リトライ仕様

プラグイン自体にリトライ機構はない。スケジューラーフレームワークが再スケジューリングを管理する。

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

トランザクションは使用しない。CycleState内のデータはスケジューリングサイクル単位で管理される。

## パフォーマンス要件

- PreFilter/Filter処理は各ノードに対して並列実行される
- DRA拡張リソースのCEL式評価にはキャッシュ（celCache、deviceMatchCache、nodeMatchCache）を使用
- EventsToRegisterでQueueingHintを使用し、不要な再スケジューリングを回避

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

- フィーチャーゲートによる機能制御（EnableDRAExtendedResource等）
- ノードリソース情報はInformerキャッシュ経由で取得（直接API呼び出しなし）

## 備考

- SidecarContainers（v1.28以降）: restartable init containerのリソース計算に対応
- InPlacePodVerticalScaling（KEP 1287）: Pod Scale Down イベントの検知に対応
- PodLevelResources: Pod全体レベルのリソース指定に対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fit.go | `pkg/scheduler/framework/plugins/noderesources/fit.go` | Fit構造体、preFilterState、preScoreState、InsufficientResource の定義 |
| 1-2 | resource_allocation.go | `pkg/scheduler/framework/plugins/noderesources/resource_allocation.go` | resourceAllocationScorer、DRACaches の定義 |

**読解のコツ**: `preFilterState`はフィルタリング用、`preScoreState`はスコアリング用のCycleState格納データ。それぞれ異なるキーで保存される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fit.go | `pkg/scheduler/framework/plugins/noderesources/fit.go` | NewFit関数（188-229行目）がプラグイン初期化のエントリーポイント |

**主要処理フロー**:
1. **188-229行目**: NewFit - プラグインの初期化、スコアリング戦略の選択、DRA連携の設定
2. **298-311行目**: PreFilter - Podリソース要求の事前計算
3. **579-612行目**: Filter - ノードリソース適合チェック
4. **136-153行目**: PreScore - スコアリング用データの事前計算
5. **732-750行目**: Score - スコアの算出

#### Step 3: フィルタリングロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fit.go | `pkg/scheduler/framework/plugins/noderesources/fit.go` | fitsRequest関数（642-729行目）がフィルタリングのコアロジック |

**主要処理フロー**:
- **642-654行目**: Pod数上限チェック
- **663-693行目**: CPU、メモリ、エフェメラルストレージの充足チェック
- **695-726行目**: スカラーリソースの充足チェック（DRA委譲判定含む）

#### Step 4: スコアリングロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | resource_allocation.go | `pkg/scheduler/framework/plugins/noderesources/resource_allocation.go` | score関数（138-183行目）がスコアリングのコアロジック |
| 4-2 | least_allocated.go | `pkg/scheduler/framework/plugins/noderesources/least_allocated.go` | leastResourceScorer（30-47行目）、leastRequestedScore（52-61行目） |
| 4-3 | most_allocated.go | `pkg/scheduler/framework/plugins/noderesources/most_allocated.go` | mostResourceScorer（30-47行目）、mostRequestedScore（54-65行目） |
| 4-4 | balanced_allocation.go | `pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go` | balancedResourceScorer（194-208行目）、balancedResourceScore（210-244行目） |
| 4-5 | requested_to_capacity_ratio.go | `pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go` | buildRequestedToCapacityRatioScorerFunction（31-58行目） |

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

```
NewFit (初期化)
    │
    ├─ PreFilter
    │      └─ computePodResourceRequest
    │             └─ resource.PodRequests
    │
    ├─ Filter
    │      └─ fitsRequest
    │             ├─ Pod数チェック
    │             ├─ CPU/Memory/EphemeralStorage チェック
    │             └─ ScalarResources チェック
    │                    └─ shouldDelegateResourceToDRA
    │
    ├─ PreScore
    │      └─ calculatePodResourceRequestList
    │      └─ getDRAPreScoredParams (DRA有効時)
    │
    └─ Score
           └─ resourceAllocationScorer.score
                  ├─ calculateResourceAllocatableRequest
                  │      └─ calculateDRAExtendedResourceAllocatableRequest (DRA有効時)
                  │             └─ calculateDRAResourceTotals
                  └─ scorer (LeastAllocated / MostAllocated / RequestedToCapacityRatio)
```

### データフロー図

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

Pod.Spec.Containers     ───▶  computePodResourceRequest   ───▶  preFilterState (CycleState)
Pod.Spec.InitContainers        (リソース要求集計)
Pod.Spec.Overhead

preFilterState          ───▶  fitsRequest                 ───▶  FilterStatus (通過/不通過)
NodeInfo.Allocatable           (リソース充足チェック)               InsufficientResources[]
NodeInfo.Requested

preScoreState           ───▶  scorer(策略)                ───▶  Score (0-100)
NodeInfo                       (スコア算出)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fit.go | `pkg/scheduler/framework/plugins/noderesources/fit.go` | ソース | メインプラグイン（Filter、Score）の実装 |
| resource_allocation.go | `pkg/scheduler/framework/plugins/noderesources/resource_allocation.go` | ソース | スコアリング共通基盤、DRAキャッシュ |
| balanced_allocation.go | `pkg/scheduler/framework/plugins/noderesources/balanced_allocation.go` | ソース | BalancedAllocationスコアリング |
| least_allocated.go | `pkg/scheduler/framework/plugins/noderesources/least_allocated.go` | ソース | LeastAllocatedスコアリング |
| most_allocated.go | `pkg/scheduler/framework/plugins/noderesources/most_allocated.go` | ソース | MostAllocatedスコアリング |
| requested_to_capacity_ratio.go | `pkg/scheduler/framework/plugins/noderesources/requested_to_capacity_ratio.go` | ソース | RequestedToCapacityRatioスコアリング |
| test_util.go | `pkg/scheduler/framework/plugins/noderesources/test_util.go` | テスト | テストユーティリティ |
