# 機能設計書 10-DaemonSetコントローラー

## 概要

本ドキュメントは、Kubernetes DaemonSetコントローラーの機能設計書である。全ノード（または指定ノード）で1つずつPodを実行するよう管理する。

### 本機能の処理概要

DaemonSetコントローラーは、DaemonSetリソースで定義されたPodが、クラスター内の全てのノード（またはnodeSelectorで指定されたノード）で1つずつ実行されることを保証する。ノードの追加・削除に応じてPodを自動的に作成・削除する。

**業務上の目的・背景**：クラスター内の全ノードで共通のシステムサービスを実行する必要がある場合に使用される。ログ収集エージェント（Fluentd, Filebeat）、モニタリングエージェント（Prometheus Node Exporter, Datadog Agent）、ネットワークプラグイン（Calico, Cilium）、ストレージプラグイン（CSI Node Driver）など、ノードごとに1つのインスタンスが必要なデーモンプロセスの管理に不可欠である。

**機能の利用シーン**：ログ収集エージェントの全ノードデプロイ、ネットワークプラグインの全ノードデプロイ、モニタリングエージェントの展開、セキュリティスキャナーの展開、GPUノード専用のデバイスプラグインの展開など。

**主要な処理内容**：
1. DaemonSetリソースの監視（Informer経由）
2. ノード一覧の監視と適格ノードの判定
3. 各ノードへのPod作成（shouldRunOnNode判定）
4. 不要ノードからのPod削除
5. ローリングアップデート（maxSurge/maxUnavailable制御）
6. ControllerRevisionによるリビジョン管理
7. FailedPodのバックオフ管理

**関連システム・外部連携**：スケジューラー（Podのノード割り当て）、API Server、Node情報

**権限による制御**：DaemonSetの操作にはapps/daemonsetsリソースへのRBACアクセス権が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングに直接の関連なし（kubectl経由でDaemonSetリソースを操作） |

## 機能種別

コントローラー / リコンシリエーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| DaemonSet.Spec.Selector | LabelSelector | Yes | Pod選択ラベルセレクター | 不変 |
| DaemonSet.Spec.Template | PodTemplateSpec | Yes | Podテンプレート | 有効なPod仕様 |
| DaemonSet.Spec.UpdateStrategy.Type | string | No | RollingUpdate/OnDelete | 有効な戦略 |
| DaemonSet.Spec.UpdateStrategy.RollingUpdate.MaxSurge | IntOrString | No | 更新中の最大超過Pod数（デフォルト0） | 0以上 |
| DaemonSet.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable | IntOrString | No | 更新中の最大利用不可Pod数（デフォルト1） | 0以上（maxSurge=0時は1以上） |
| DaemonSet.Spec.RevisionHistoryLimit | *int32 | No | 保持するリビジョン履歴数（デフォルト10） | 0以上 |
| DaemonSet.Spec.Template.Spec.NodeSelector | map[string]string | No | 対象ノードの選択条件 | 有効なラベル |
| DaemonSet.Spec.Template.Spec.Affinity.NodeAffinity | NodeAffinity | No | ノードアフィニティ | 有効なアフィニティ設定 |
| DaemonSet.Spec.Template.Spec.Tolerations | []Toleration | No | ノードTaintへの許容 | 有効なToleration |

### 入力データソース

API Server経由のInformer（DaemonSet, ControllerRevision, Pod, Node）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Pod | v1.Pod | 各ノードに作成されるDaemon Pod |
| ControllerRevision | apps/v1.ControllerRevision | リビジョン管理 |
| DaemonSet.Status | DaemonSetStatus | ステータス更新 |
| Event | v1.Event | DaemonSet関連イベント |

### 出力先

API Server経由でetcdに永続化

## 処理フロー

### 処理シーケンス

```
1. Informerからのイベント検知
   └─ DaemonSet/Pod/Nodeの変更をWorkQueueにエンキュー
2. syncDaemonSet（メインリコンシリエーションループ）
   └─ WorkQueueからDaemonSetキーを取得して同期処理開始
3. ノード適格性判定
   └─ 各ノードでDaemon Podを実行すべきかを判定（nodeSelector, affinity, toleration）
4. manage Pods
   └─ 不足ノードへのPod作成、不要ノードからのPod削除
5. ローリングアップデート
   └─ maxSurge/maxUnavailableに従い新旧Podを入れ替え
6. ステータス更新
   └─ DaemonSet.Statusのレプリカ数等を更新
7. クリーンアップ
   └─ RevisionHistoryLimitを超過した古いControllerRevisionを削除
```

### フローチャート

```mermaid
flowchart TD
    A[Informerイベント] --> B[WorkQueueエンキュー]
    B --> C[syncDaemonSet]
    C --> D[ノード適格性判定]
    D --> E[各ノードのPod状態確認]
    E --> F{アクション判定}
    F -->|Podなし・実行すべき| G[Pod作成]
    F -->|Pod存在・不要| H[Pod削除]
    F -->|更新必要| I[ローリングアップデート]
    G --> J[ステータス更新]
    H --> J
    I --> I1{maxSurge > 0?}
    I1 -->|Yes| I2[新Pod作成→旧Pod削除]
    I1 -->|No| I3[旧Pod削除→新Pod作成]
    I2 --> J
    I3 --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-1 | BurstReplicas | 1回のsyncで最大250個のPodを作成/削除 | Pod作成/削除時 |
| BR-2 | StatusUpdateRetries | ステータス更新は最大1回リトライ | ステータス更新失敗時 |
| BR-3 | BackoffGCInterval | 失敗Podのバックオフ情報を1分間隔でGC | 定期的に実行 |
| BR-4 | shouldRunOnNode | nodeSelector, nodeAffinity, tolerationsを総合判定 | ノード適格性判定 |
| BR-5 | maxSurge/maxUnavailable | maxSurge=0時はmaxUnavailable=1以上必須 | ローリングアップデート |
| BR-6 | SelectingAllReason | セレクターが全Podに一致する場合はイベント発行 | セレクター検証時 |
| BR-7 | ノード変更の専用キュー | ノード更新イベントは専用のnodeUpdateQueueで処理 | ノード変更時 |

### 計算ロジック

ローリングアップデート時:
- maxSurge=0: 既存Podを削除してからノード上に新Podを作成（ダウンタイムあり）
- maxSurge>0: 新Podを先に作成してから旧Podを削除（ゼロダウンタイム）
- maxUnavailable: 同時にUnavailableになれるPodの上限
- desiredNumberScheduled: shouldRunOnNode=trueのノード数

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Pod作成 | etcd | INSERT | 適格ノードへのDaemon Pod作成 |
| Pod削除 | etcd | DELETE | 不要ノードからのPod削除 |
| ControllerRevision作成 | etcd | INSERT | リビジョン管理 |
| DaemonSet Status更新 | etcd | UPDATE | ステータス更新 |

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

#### etcd

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | /registry/pods/{namespace}/{name} | nodeNameフィールドを設定したPod | スケジューラーバイパス |
| DELETE | /registry/pods/{namespace}/{name} | 不要ノード上のPod | gracePeriodSeconds考慮 |
| UPDATE | /registry/daemonsets/{namespace}/{name} | status フィールド | desiredNumberScheduled, numberReady等 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Pod作成失敗 | ノードリソース不足 | ノードのリソースキャパシティを確認 |
| - | FailedDaemonPod | PodがFailed状態 | Pod定義を修正（イメージ、コマンド等） |
| - | FailedPlacement | ノードに配置できない | nodeSelector, tolerationを確認 |

### リトライ仕様

ワークキューのrate limiterにより自動リトライ。Failed Podはfailure backoffにより再作成間隔が指数的に増加（BackoffGCInterval=1分でGC）。

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

各Pod操作はAPI Server経由でアトミックに実行。ノード単位でPodの存在を管理するため、各ノードの処理は独立。

## パフォーマンス要件

- BurstReplicas=250により、大規模クラスターでのAPI Server負荷を制限
- ノード追加後のPod作成: 即座（Informerイベント検知後）
- ノード更新は専用キュー（nodeUpdateQueue）で処理し、メインキューと分離

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

- DaemonSetの操作にはapps/daemonsetsリソースへの適切なRBAC権限が必要
- DaemonSet PodはhostNetworkやprivilegedモードを使用することが多く、Pod Security Admissionの設定に注意

## 備考

DaemonSetコントローラーはPod作成時にnodeNameフィールドを設定するため、スケジューラーを経由せずにPodをノードに直接配置する。ただし、nodeAffinity/tolerationの評価はコントローラー内で行われる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | daemon_controller.go | `pkg/controller/daemon/daemon_controller.go` | DaemonSetsController構造体（**87-137行目**）。kubeClient, podControl, crControl, burstReplicas, expectations, dsLister, historyLister, podLister, nodeLister, queue, nodeUpdateQueue, failedPodsBackoff |

**読解のコツ**: DaemonSetコントローラーは2つのワークキュー（queue, nodeUpdateQueue）を持つ。メインキューはDaemonSetの変更を処理し、nodeUpdateQueueはノードの変更を処理する。これにより、ノード変更の大量イベントがDaemonSetの処理をブロックしない。BurstReplicas=250（**61行目**）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | daemon_controller.go | `pkg/controller/daemon/daemon_controller.go` | NewDaemonSetsController関数（**139-148行目**）でコントローラー初期化 |

**主要処理フロー**:
1. **139行目**: NewDaemonSetsControllerでコントローラー初期化
2. **151-176行目**: DaemonSetsController構造体の初期化（podControl, crControl, burstReplicas, expectations, 2つのworkqueue）
3. **178-188行目**: DaemonSet Informerにイベントハンドラ登録
4. **192-204行目**: ControllerRevision Informerにイベントハンドラ登録
5. **208-218行目**: Pod Informerにイベントハンドラ登録

#### Step 3: ローリングアップデートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | update.go | `pkg/controller/daemon/update.go` | rollingUpdate関数（**44行目**）でローリングアップデートロジック |

**主要処理フロー**（update.go）:
- **44行目**: rollingUpdate関数 - ローリングアップデートのメインロジック
- **46行目**: getNodesToDaemonPodsでノード→Pod マッピングを取得
- **50行目**: updatedDesiredNodeCountsでmaxSurge, maxUnavailable, desiredNumberScheduledを計算
- **69行目**: maxSurge=0の場合の処理分岐

#### Step 4: ユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | util/ | `pkg/controller/daemon/util/` | DaemonSet用ユーティリティ関数 |

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

```
DaemonSetsController.Run()
    │
    ├─ worker() [メインキュー]
    │      └─ syncDaemonSet()
    │             ├─ getNodesToDaemonPods()
    │             ├─ manage() → Pod作成/削除
    │             │      ├─ [Pod不足] podControl.CreatePods()
    │             │      └─ [Pod超過] podControl.DeletePod()
    │             ├─ rollingUpdate()
    │             │      ├─ [maxSurge=0] 旧Pod削除→新Pod作成
    │             │      └─ [maxSurge>0] 新Pod作成→旧Pod削除
    │             ├─ cleanupHistory()
    │             └─ updateDaemonSetStatus()
    │
    ├─ nodeWorker() [ノード更新キュー]
    │      └─ ノード変更に関連するDaemonSetをメインキューにエンキュー
    │
    └─ Informer Event Handlers
           ├─ addDaemonset() / updateDaemonset() / deleteDaemonset()
           ├─ addPod() / updatePod() / deletePod()
           ├─ addNode() / updateNode() / deleteNode()
           └─ addHistory() / updateHistory() / deleteHistory()
```

### データフロー図

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

DaemonSet Spec ──────▶ DaemonSetsController ──────▶ Pod (各ノードに1つ)
├─ selector               ├─ syncDaemonSet()              ├─ nodeName設定
├─ template               ├─ manage()                     └─ OwnerReference
└─ updateStrategy         └─ rollingUpdate()

Node一覧 ────────────▶ shouldRunOnNode() ──────▶ 適格ノード判定
├─ labels                  ├─ nodeSelector照合          DaemonSet Status
├─ taints                  ├─ nodeAffinity照合          ├─ desiredNumberScheduled
└─ conditions              └─ toleration照合            ├─ currentNumberScheduled
                                                         ├─ numberReady
                                                         └─ updatedNumberScheduled
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| daemon_controller.go | `pkg/controller/daemon/daemon_controller.go` | ソース | コントローラー本体（構造体、初期化、sync） |
| update.go | `pkg/controller/daemon/update.go` | ソース | ローリングアップデートロジック |
| doc.go | `pkg/controller/daemon/doc.go` | ソース | パッケージドキュメント |
| util/ | `pkg/controller/daemon/util/` | ソース | ユーティリティ関数 |
| config/ | `pkg/controller/daemon/config/` | ソース | コントローラー設定 |
