# 機能設計書 59-ノードシャットダウン管理

## 概要

本ドキュメントは、Kubeletのノード正常シャットダウン時にPodのグレースフル終了を管理するNode Shutdown Manager機能の設計を記載する。

### 本機能の処理概要

KubeletのNode Shutdown Manager機能は、ノードのシステムシャットダウン通知を検知し、Podを優先度に基づいてグレースフルに終了させる。LinuxではsystemdのInhibitLock機構を利用してシャットダウンを一時的に抑制し、その間にPodの安全な終了処理を実行する。Windowsではシステムシャットダウンイベントに応答する。

**業務上の目的・背景**：ノードのメンテナンスや予期せぬシャットダウン時に、Pod内のアプリケーションがデータを保存し、クリーンアップ処理を完了する時間を確保する必要がある。Node Shutdown Managerにより、Podの優先度に基づく段階的な終了と、ボリュームの安全なアンマウントを実現する。

**機能の利用シーン**：ノードの計画的シャットダウン/再起動時、クラウド環境でのノードプリエンプション時、OSアップデートに伴う再起動時。

**主要な処理内容**：
1. systemd InhibitLockの取得によるシャットダウン遅延
2. systemdシャットダウン通知のD-Bus監視
3. Pod優先度に基づくグループ分けと段階的終了
4. 各優先度グループのgracePeriod管理
5. ボリュームのアンマウント待機
6. シャットダウン中のPod Admission拒否
7. シャットダウン状態の永続化（localStorageStateFile）

**関連システム・外部連携**：systemd（D-Bus経由のInhibitLock、シャットダウン通知）、Volume Manager（ボリュームアンマウント待機）。

**権限による制御**：シャットダウン時のPod終了はKubeletの権限で実行。Critical Podも含め全Podが対象となるが、優先度によって猶予期間が異なる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Kubelet内部機能のため画面関連なし |

## 機能種別

ライフサイクル管理 / 状態管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ShutdownGracePeriodRequested | time.Duration | No | 全体のシャットダウン猶予期間 | 0以上 |
| ShutdownGracePeriodCriticalPods | time.Duration | No | Critical Pod用猶予期間 | ShutdownGracePeriodRequested以下 |
| ShutdownGracePeriodByPodPriority | []config | No | 優先度別猶予期間 | 優先度順 |

### 入力データソース

- systemd D-Bus: シャットダウン通知、InhibitDelay
- Kubelet設定: シャットダウン猶予期間設定
- Pod一覧: 活性Podとその優先度

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PodStatus.Phase | v1.PodPhase | Failed（シャットダウンによる終了） |
| PodStatus.Reason | string | "Terminated" |
| PodStatus.Message | string | "Pod was terminated in response to imminent node shutdown." |
| PodCondition | v1.PodCondition | DisruptionTarget条件の追加 |

### 出力先

- API Server（PodStatus更新）
- Kubernetesイベント
- ローカルストレージ（シャットダウン状態永続化）

## 処理フロー

### 処理シーケンス

```
1. Manager初期化
   └─ 設定の読み込み、podManager初期化、InhibitLock取得
2. シャットダウン通知監視
   └─ D-Bus MonitorShutdown()でシャットダウン通知待機
3. シャットダウン通知受信
   └─ nodeShuttingDownNow = true、新規Pod Admission拒否開始
4. 優先度別Pod終了
   └─ 低優先度グループから順にkillPodFunc実行
5. ボリュームアンマウント待機
   └─ 各グループのPod終了後にボリュームアンマウント完了を待機
6. InhibitLock解放
   └─ 全Pod終了後にInhibitLockを解放してシャットダウン続行許可
```

### フローチャート

```mermaid
flowchart TD
    A[Manager.Start] --> B[InhibitLock取得]
    B --> C[D-Bus MonitorShutdown開始]
    C --> D{シャットダウン通知?}
    D -->|No| D
    D -->|Yes| E[nodeShuttingDownNow = true]
    E --> F[syncNodeStatus呼び出し]
    F --> G[優先度グループ分け]
    G --> H[グループ1: 低優先度Pod終了]
    H --> I[ボリュームアンマウント待機]
    I --> J[グループ2: 中優先度Pod終了]
    J --> K[ボリュームアンマウント待機]
    K --> L[グループN: Critical Pod終了]
    L --> M[ボリュームアンマウント待機]
    M --> N[InhibitLock解放]
    N --> O[シャットダウン続行]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | 優先度順終了 | 低優先度Podから先に終了し、高優先度Podには最大限の猶予を与える | シャットダウン時 |
| BR-59-02 | Pod猶予期間上限 | PodのterminationGracePeriodSecondsとグループの猶予期間の小さい方を適用 | Pod終了時 |
| BR-59-03 | Admission拒否 | シャットダウン中は新規PodのAdmissionを拒否 | シャットダウン開始後 |
| BR-59-04 | フィーチャーゲート | GracefulNodeShutdown無効時はstub（no-op）を返す | 機能無効時 |
| BR-59-05 | 設定移行 | ShutdownGracePeriodByPodPriorityが未設定の場合、旧設定から自動移行 | 設定なし時 |
| BR-59-06 | ボリューム待機 | Pod終了後にVolumeManager.WaitForAllPodsUnmount()でアンマウント完了を待機 | シャットダウン時 |

### 計算ロジック

- 旧設定からの移行: デフォルト優先度猶予 = ShutdownGracePeriodRequested - ShutdownGracePeriodCriticalPods
- グループ全体の待機時間 = ShutdownGracePeriodSeconds * time.Second

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 状態永続化 | graceful_node_shutdown_state（ファイル） | UPDATE | シャットダウン状態の保存 |
| PodStatus | API Server（etcd） | UPDATE | Pod終了ステータスの更新 |

### テーブル別操作詳細

#### graceful_node_shutdown_state（ローカルファイル）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | shutdownState | シャットダウン進行状態 | シャットダウン開始/完了時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| DBusConnectionError | 外部エラー | systemd D-Bus接続失敗 | 1秒間隔で再接続試行 |
| InhibitLockError | 外部エラー | InhibitLock取得失敗 | ログ記録、シャットダウン保護なしで動作 |
| KillPodError | 一時エラー | Pod終了失敗 | ログ記録、次のグループに進行 |
| VolumeUnmountTimeout | タイムアウト | ボリュームアンマウント待機超過 | ログ記録、次のグループに進行 |

### リトライ仕様

- D-Bus再接続: 1秒間隔（dbusReconnectPeriod）
- Pod終了: グループの猶予期間内で完了を待機

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

nodeShuttingDownMutexによるシャットダウン状態の排他制御。Pod終了は各グループ内で並行実行、グループ間は順次実行。

## パフォーマンス要件

- D-Bus監視は低オーバーヘッド
- シャットダウン遅延: InhibitDelayの範囲内で全Pod終了を完了する必要がある
- 各グループ内のPod終了は並行実行（goroutine + WaitGroup）

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

- systemd InhibitLockの操作にはD-Busアクセス権限が必要
- シャットダウン状態ファイルはKubeletの状態ディレクトリに保存

## 備考

- Linux以外のプラットフォーム（Windows等）ではstub実装となる（Start()はno-op）
- GracefulNodeShutdownBasedOnPodPriorityフィーチャーゲートにより優先度別猶予期間をサポート
- DisruptionTarget Pod Conditionが設定され、Pod Disruption Budgetの対象外であることを示す
- nodeShutdownReason = "Terminated"、nodeShutdownMessage = "Pod was terminated in response to imminent node shutdown."

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nodeshutdown_manager.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager.go` | Managerインターフェース、Config、podManager |

**読解のコツ**: Managerインターフェースはlifecycle.PodAdmitHandlerを埋め込んでいる。Config構造体がシャットダウン設定の全体像を把握する鍵。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nodeshutdown_manager_linux.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager_linux.go` | managerImpl構造体、NewManager、Start |

**主要処理フロー**:
- **59-76行目**: managerImpl構造体 - D-Bus接続、InhibitLock、podManager
- **79-111行目**: NewManager - フィーチャーゲート確認、podManager初期化

#### Step 3: Pod終了処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nodeshutdown_manager.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager.go` | podManager.killPods、groupByPriority |

**主要処理フロー**:
- **101-126行目**: newPodManager - 優先度別猶予期間の初期化とソート
- **129-219行目**: killPods - 優先度グループごとの段階的Pod終了
- **258-294行目**: groupByPriority - Podを優先度グループに分類

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

```
Kubelet
    |
    +-- NodeShutdownManager.Start() [Linux]
    |       +-- systemd.NewDBusCon()
    |       +-- dbusCon.InhibitShutdown()
    |       +-- dbusCon.MonitorShutdown()
    |       |
    |       +-- [シャットダウン通知受信]
    |               +-- syncNodeStatus()
    |               +-- podManager.killPods()
    |               |       +-- groupByPriority()
    |               |       +-- [グループごと]
    |               |               +-- killPodFunc() [並行]
    |               |               +-- volumeManager.WaitForAllPodsUnmount()
    |               |               +-- timer/doneCh待機
    |               +-- dbusCon.ReleaseInhibitLock()
    |
    +-- NodeShutdownManager.Admit()
            +-- ShutdownStatus()チェック
```

### データフロー図

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

systemd D-Bus            ──▶  MonitorShutdown()      ──▶  シャットダウン通知
(シャットダウン通知)

活性Pod一覧             ──▶  groupByPriority()      ──▶  優先度グループ

各グループ              ──▶  killPods()             ──▶  Pod終了
                               |                          PodStatus更新
                               v                          (Phase=Failed)
                         WaitForAllPodsUnmount()
                               |
                               v
                         InhibitLock解放           ──▶  システムシャットダウン続行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nodeshutdown_manager.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager.go` | ソース | 共通インターフェース、podManager、ユーティリティ |
| nodeshutdown_manager_linux.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager_linux.go` | ソース | Linux(systemd)実装 |
| nodeshutdown_manager_windows.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager_windows.go` | ソース | Windows実装 |
| nodeshutdown_manager_others.go | `pkg/kubelet/nodeshutdown/nodeshutdown_manager_others.go` | ソース | その他プラットフォーム（stub） |
| storage.go | `pkg/kubelet/nodeshutdown/storage.go` | ソース | シャットダウン状態の永続化 |
| systemd/ | `pkg/kubelet/nodeshutdown/systemd/` | ソース | systemd D-Bus連携 |
