# 機能設計書 93-ドレイン（drain）

## 概要

本ドキュメントは、kubectl drainコマンドによるノードからのPod退去機能の設計を記述する。

### 本機能の処理概要

kubectl drainコマンドは、指定されたノードからPodを安全に退去（evict）させるCLI機能である。ノードのメンテナンスや廃棄前の準備として使用される。

**業務上の目的・背景**：ノードのOS更新、カーネルアップグレード、ハードウェアメンテナンス、クラスタバージョンアップ等の運用作業において、ワークロードに影響を与えずにノードを安全にサービスから外すために利用される。

**機能の利用シーン**：ノードのローリングアップデート、ノード縮退、ハードウェア障害時の計画的移行、クラスタスケールダウン。

**主要な処理内容**：
1. 対象ノードをcordon（スケジューリング不可に設定）
2. ノード上のPod一覧を取得しフィルタリング
3. Eviction APIを使用してPodを退去
4. 全Podの退去完了を待機

**関連システム・外部連携**：Eviction APIを通じてPodDisruptionBudget（PDB）の制約を尊重する。cordon操作によりSchedulerからの新規Pod配置を防止する。

**権限による制御**：ノードのupdate権限（cordon用）、pods/evictionのcreate権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | kubectl drain | 主機能 | ノードからPodを退去させる |
| - | kubectl cordon | 関連機能 | drain内部でcordonを自動実行 |

## 機能種別

ノード運用操作 / Pod退去

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| NODE | string | Yes | ドレイン対象のノード名 | 存在するノード |
| --force | bool | No | DaemonSet管理外のPodを強制削除 | - |
| --grace-period | int | No | Pod終了の猶予期間（秒） | -1以上 |
| --ignore-daemonsets | bool | No | DaemonSet管理のPodを無視 | - |
| --delete-emptydir-data | bool | No | emptyDir使用Podの削除を許可 | - |
| --selector / -l | string | No | ラベルセレクタ | 有効なラベルセレクタ形式 |
| --timeout | duration | No | 操作全体のタイムアウト | 正の値 |
| --dry-run | string | No | dry-run戦略 | none/client/server |
| --pod-selector | string | No | Podフィルタリング用セレクタ | 有効なラベルセレクタ形式 |
| --disable-eviction | bool | No | Eviction APIを使わず直接削除 | - |
| --skip-wait-for-delete-timeout | int | No | DeletionTimestamp設定済みPodの待機スキップ秒数 | 0以上 |
| --chunk-size | int64 | No | ページネーションのチャンクサイズ | 正の整数 |

### 入力データソース

CLI引数、kubeconfig（クラスター接続情報）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| cordon結果 | string | "node/xxx cordoned" メッセージ |
| eviction結果 | string | "evicting pod xxx" / "pod/xxx evicted" メッセージ |
| エラー警告 | string | Pod退去時の警告メッセージ |

### 出力先

標準出力（stdout）、標準エラー出力（stderr）

## 処理フロー

### 処理シーケンス

```
1. Complete: 引数と環境の初期化
2. RunDrain: ドレイン実行
   ├─ RunCordonOrUncordon: ノードをcordon（Unschedulable=true）
   ├─ GetPodsForDeletion: 退去対象のPod一覧を取得
   │   ├─ DaemonSet管理Podのフィルタリング
   │   ├─ Mirror Podのフィルタリング
   │   ├─ ローカルストレージ使用Podのフィルタリング
   │   └─ 未管理Podのフィルタリング
   ├─ Eviction APIでPodを退去（またはDelete API）
   └─ 全Pod退去完了を待機（ポーリング）
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[Complete: 引数解析・初期化]
    B --> C[RunCordonOrUncordon: ノードcordon]
    C --> D[GetPodsForDeletion: Pod一覧取得]
    D --> E{退去対象Podあり?}
    E -->|No| F[完了メッセージ出力]
    E -->|Yes| G{disable-eviction?}
    G -->|Yes| H[Delete APIでPod削除]
    G -->|No| I[Eviction APIでPod退去]
    H --> J[Pod退去完了待機]
    I --> J
    J --> K{全Pod退去完了?}
    K -->|No| L{タイムアウト?}
    L -->|Yes| M[エラー終了]
    L -->|No| J
    K -->|Yes| F
    F --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-93-01 | cordon先行 | drainの前にノードをcordon（Unschedulable=true）に設定 | 常時 |
| BR-93-02 | PDB尊重 | Eviction APIはPodDisruptionBudgetの制約を尊重 | disable-eviction=false時 |
| BR-93-03 | DaemonSet除外 | DaemonSet管理のPodはデフォルトで退去対象外 | ignore-daemonsets=true時は警告のみ |
| BR-93-04 | ローカルストレージ警告 | emptyDir使用Podはデフォルトで退去不可 | delete-emptydir-data=true時は許可 |
| BR-93-05 | 未管理Pod警告 | Controller管理外のPodはデフォルトで退去不可 | force=true時は強制削除 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Cordon | Node | PATCH | spec.unschedulable=trueに設定 |
| Eviction | pods/eviction | CREATE | EvictionサブリソースをPOST |
| Delete | Pod | DELETE | force時にPodを直接削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | DaemonSetエラー | DaemonSet管理Podあり（ignore-daemonsets未指定） | --ignore-daemonsetsを指定 |
| - | ローカルストレージエラー | emptyDir使用Podあり（delete-emptydir-data未指定） | --delete-emptydir-dataを指定 |
| - | 未管理Podエラー | Controller管理外Podあり（force未指定） | --forceを指定 |
| - | PDBエラー | PDB制約によりEvictionが拒否 | PDB設定を確認、またはタイムアウトで待機 |
| - | タイムアウトエラー | 指定時間内にPod退去が完了しない | タイムアウト値を増やす、PDB設定を確認 |

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

cordon操作はMerge Patchで実行。Eviction操作は個別のPodに対して逐次実行される（全体のトランザクション保証なし）。

## パフォーマンス要件

ノード上のPod数に応じて処理時間が変動。Eviction APIの呼び出しは逐次実行されるため、PDB制約がある場合は待機時間が発生する。

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

- ノードのupdate権限（cordon用）が必要
- pods/evictionのcreate権限が必要
- --forceオプションの使用は運用ポリシーで制限すべき
- PDB制約を無視する--disable-evictionの使用は慎重に判断

## 備考

- drain後にノードを再びスケジューリング可能にするにはkubectl uncordonを実行する
- drain操作は冪等ではない（既に退去済みのPodは再退去されない）
- chunk-sizeはPod一覧取得時のページネーションに使用

---

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | drain.go | `staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go` | DrainCmdOptions構造体とHelper構造体でコマンドの全オプションを確認 |

**読解のコツ**: drain.goにはcordon/uncordon/drain の3コマンドが定義されている。DrainCmdOptionsがdrain固有、Helper（kubectl/pkg/drain/パッケージ）が共通ロジック。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | drain.go | `staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go` | NewCmdDrain関数でcobraコマンドの定義を確認 |

#### Step 3: ドレイン実行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | drain.go | `staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go` | RunDrain関数でcordon→getPods→evictの流れを確認 |
| 3-2 | drain.go | `staging/src/k8s.io/kubectl/pkg/drain/drain.go` | Helper.GetPodsForDeletionとHelper.EvictOrDeletePodのロジック |

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

```
NewCmdDrain
    │
    ├─ Complete
    │      └─ namespace, builder, client設定
    │
    └─ RunDrain
           ├─ RunCordonOrUncordon
           │      └─ helper.PatchNodeUnschedulable(true)
           ├─ GetPodsForDeletion
           │      ├─ DaemonSetフィルタ
           │      ├─ MirrorPodフィルタ
           │      ├─ LocalStorageフィルタ
           │      └─ UnmanagedPodフィルタ
           ├─ EvictOrDeletePod (各Podに対して)
           │      ├─ EvictPod → Eviction API (POST)
           │      └─ DeletePod → Delete API (DELETE)
           └─ waitForDeletion
```

### データフロー図

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

CLI引数(NODE)        ───▶ Complete（初期化）
                           │
                           ▼
kubeconfig           ───▶ RunDrain
                      ├─ RunCordonOrUncordon  ───▶ API Server (PATCH Node)
                      │                             └─ "node cordoned"
                      ├─ GetPodsForDeletion   ───▶ API Server (LIST Pods)
                      ├─ EvictOrDeletePod     ───▶ API Server (POST eviction)
                      │                             └─ "pod evicted"
                      └─ waitForDeletion      ───▶ API Server (GET Pod)
                                                    └─ "drained"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| drain.go | `staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go` | ソース | drain/cordon/uncordonコマンドのCLI定義 |
| drain.go | `staging/src/k8s.io/kubectl/pkg/drain/drain.go` | ソース | ドレインロジックの共通実装 |
| filters.go | `staging/src/k8s.io/kubectl/pkg/drain/filters.go` | ソース | Podフィルタリングロジック |
