# 機能設計書 11-Jobコントローラー

## 概要

本ドキュメントは、Kubernetes Jobコントローラーの機能設計を記述する。Jobコントローラーはバッチ処理の実行を管理し、指定回数の正常完了を保証するコントローラーである。

### 本機能の処理概要

**業務上の目的・背景**：Kubernetesクラスタにおいて、一度きりの処理やバッチジョブを確実に実行・完了させる必要がある。Jobコントローラーは、Podが失敗した場合の再作成や、指定された完了数に達するまでのPod管理を自動化し、バッチワークロードの信頼性を保証する。

**機能の利用シーン**：データベースマイグレーション、一括データ処理、ETLパイプライン、テスト実行など、完了条件のある一回性の処理を実行する場面で使用される。Indexed Jobによる並列分散処理や、PodFailurePolicyによるきめ細かな失敗ハンドリングも提供する。

**主要な処理内容**：
1. Jobリソースの監視とPodの作成・削除による所望状態の維持
2. Pod完了数・失敗数のカウントとステータス更新
3. Indexed JobにおけるインデックスベースのPod管理
4. PodFailurePolicyに基づく失敗条件の評価
5. SuccessPolicyに基づく早期完了判定
6. バックオフ付きPod再作成による障害時の段階的リトライ
7. アクティブ期限（activeDeadlineSeconds）による実行時間制限
8. 孤立Podのファイナライザ管理

**関連システム・外部連携**：API Server（etcd経由のJobおよびPodリソース永続化）、CronJobコントローラー（定期的なJob作成の親コントローラー）、Kubelet（Podの実際の実行）

**権限による制御**：RBACにより、Job作成・削除・更新の権限が制御される。コントローラー自体はsystem:controller:job-controllerサービスアカウントで動作する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Jobコントローラーは直接の画面を持たない。kubectl経由でJobリソースのCRUD操作が行われる |

## 機能種別

コントローラー（Reconciliation Loop） / CRUD操作 / バッチ処理管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| spec.completions | *int32 | No | 完了に必要なPod数。nilの場合はparallelism=1扱い | >= 0 |
| spec.parallelism | *int32 | No | 同時実行可能なPod数 | >= 0 |
| spec.backoffLimit | *int32 | No | 失敗許容回数 | >= 0 |
| spec.activeDeadlineSeconds | *int64 | No | Job全体の最大実行時間（秒） | > 0 |
| spec.ttlSecondsAfterFinished | *int32 | No | 完了後の自動削除待ち時間（秒） | >= 0 |
| spec.completionMode | string | No | "NonIndexed" または "Indexed" | NonIndexed/Indexed |
| spec.podFailurePolicy | *PodFailurePolicy | No | Pod失敗時のアクション定義 | - |
| spec.successPolicy | *SuccessPolicy | No | 早期完了判定ルール | - |
| spec.managedBy | *string | No | 外部コントローラーに委譲する場合のコントローラー名 | - |

### 入力データソース

- Kubernetes API Server: Job Informer（Jobリソースの変更通知）
- Kubernetes API Server: Pod Informer（Podリソースの変更通知）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| status.succeeded | int32 | 正常完了したPod数 |
| status.failed | int32 | 失敗したPod数 |
| status.active | int32 | 実行中のPod数 |
| status.ready | *int32 | Ready状態のPod数 |
| status.terminating | *int32 | 終了処理中のPod数 |
| status.conditions | []JobCondition | Job完了・失敗のCondition |
| status.startTime | *metav1.Time | Job開始時刻 |
| status.completionTime | *metav1.Time | Job完了時刻 |
| status.completedIndexes | string | 完了済みインデックス範囲（Indexed Job） |
| status.failedIndexes | *string | 失敗インデックス範囲（Indexed Job） |
| status.uncountedTerminatedPods | *UncountedTerminatedPods | まだカウントされていない終了Pod |

### 出力先

- Kubernetes API Server: Jobステータスの更新
- Kubernetes API Server: Pod作成・削除

## 処理フロー

### 処理シーケンス

```
1. Informerからイベント受信（Job追加/更新、Pod追加/更新/削除）
   └─ workqueueにJobキーをエンキュー
2. workerがキューからJobキーを取得
   └─ syncJob関数を呼び出し
3. JobとPodの現在状態を取得
   └─ JobLister/PodStoreからキャッシュ取得
4. Podの分類（active/succeeded/failed/uncounted）
   └─ ファイナライザベースのトラッキングで正確にカウント
5. PodFailurePolicy/SuccessPolicyの評価
   └─ 失敗アクション・早期完了の判定
6. Job完了・失敗条件の判定
   └─ activeDeadlineSeconds、backoffLimit、completions等
7. 必要に応じてPodの作成・削除
   └─ parallelism、completions設定に基づく
8. Jobステータスの更新
   └─ API Serverにステータスを書き込み
```

### フローチャート

```mermaid
flowchart TD
    A[Informerイベント受信] --> B[workqueueにエンキュー]
    B --> C[workerがデキュー]
    C --> D[syncJob呼び出し]
    D --> E[JobとPod状態取得]
    E --> F{managedByが外部?}
    F -->|Yes| G[スキップ]
    F -->|No| H[Pod分類と集計]
    H --> I{activeDeadlineSeconds超過?}
    I -->|Yes| J[全Pod削除, Job失敗]
    I -->|No| K{PodFailurePolicy評価}
    K --> L{SuccessPolicy評価}
    L --> M{完了条件判定}
    M -->|完了| N[Jobステータス=Complete]
    M -->|失敗| O[Jobステータス=Failed]
    M -->|継続| P[Pod作成/削除調整]
    P --> Q[ステータス更新]
    N --> Q
    O --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 完了判定 | succeeded >= completionsの場合、Jobを完了とする | completionsが設定されている場合 |
| BR-02 | 失敗判定 | failed > backoffLimitの場合、Jobを失敗とする | backoffLimitが設定されている場合 |
| BR-03 | 並列度制御 | active Podの数がparallelismを超えないようにする | 常時 |
| BR-04 | Indexed Job | 各インデックスに対して1つのPodを割り当て | completionMode=Indexed |
| BR-05 | Pod再作成バックオフ | Pod失敗時にexponential backoffで再作成を遅延 | Pod失敗時 |
| BR-06 | activeDeadline | 設定時間を超えたJobは全Podを削除して失敗 | activeDeadlineSecondsが設定されている場合 |

### 計算ロジック

- Pod作成数の計算: `min(parallelism - active, completions - succeeded - active)`
- バックオフ遅延: `DefaultJobPodFailureBackOff * 2^(failureCount-1)` (最大MaxJobPodFailureBackOff)
- MaxUncountedPods: 500（uncountedTerminatedPodsスライスの上限）
- MaxPodCreateDeletePerSync: 500（1回のsyncでの最大Pod作成/削除数）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Job同期 | Jobs (etcd) | UPDATE | Jobステータスの更新 |
| Pod作成 | Pods (etcd) | INSERT | 新規Podの作成 |
| Pod削除 | Pods (etcd) | DELETE | 不要Podの削除 |
| Pod更新 | Pods (etcd) | UPDATE | ファイナライザの追加・削除 |

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

#### Jobs (etcd)

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | status.succeeded | 完了Pod数 | ファイナライザ除去済みPodから集計 |
| UPDATE | status.failed | 失敗Pod数 | ファイナライザ除去済みPodから集計 |
| UPDATE | status.active | アクティブPod数 | 非終了Podの数 |
| UPDATE | status.conditions | Complete/Failed条件 | 完了・失敗判定時に追加 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | API Server通信エラー | ステータス更新やPod作成失敗時 | exponential backoffでリトライ（最大1分） |
| - | ファイナライザ除去失敗 | Pod更新のconflict | orphanQueueでリトライ |
| - | expectations不一致 | Pod作成/削除が未反映 | 次回sync時に再評価 |

### リトライ仕様

- API呼び出し失敗: DefaultJobApiBackOff（1秒）からMaxJobApiBackOff（1分）のexponential backoff
- Pod失敗時の再作成: DefaultJobPodFailureBackOff（10秒）からMaxJobPodFailureBackOff（10分）のexponential backoff
- sync呼び出し: SyncJobBatchPeriod（1秒）のバッチ遅延

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

etcdベースの楽観的並行制御。Jobステータス更新時はResourceVersionによるconflict検出を行い、conflictの場合は次回syncで再試行する。ファイナライザの追加・削除もPodのResourceVersionに基づく楽観的ロックで管理される。

## パフォーマンス要件

- MaxPodCreateDeletePerSync: 1回のsyncで最大500 Podの作成/削除
- MaxUncountedPods: uncountedTerminatedPodsの上限500（ステータスオブジェクトサイズ約20KB以下を維持）
- SyncJobBatchPeriod: 1秒のバッチ遅延でAPIServer負荷を軽減
- ControllerExpectations: Pod作成・削除の観測遅延を吸収

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

- コントローラーはsystem:controller:job-controllerサービスアカウントで動作
- RBACによりJob/Podの操作権限が制御される
- PodSecurityContextの設定はJobテンプレートで指定されKubeletが適用

## 備考

- managedByフィールドにより外部コントローラーへのJob管理委譲が可能
- JobTrackingWithFinalizersが標準で有効。Podにbatch.kubernetes.io/job-trackingファイナライザを追加し、正確なPod集計を実現

---

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

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

### 推奨読解順序

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

Jobコントローラーが操作する主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `staging/src/k8s.io/api/batch/v1/types.go` | Job, JobSpec, JobStatus, JobConditionの定義 |
| 1-2 | job_controller.go | `pkg/controller/job/job_controller.go` | Controller構造体（84-133行目）とsyncJobCtx構造体（135-151行目） |

**読解のコツ**: Controller構造体のexpectationsとfinalizerExpectationsが、Pod作成/削除の非同期性をどう吸収するかに注目。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | job_controller.go | `pkg/controller/job/job_controller.go` | NewController関数（172-241行目）: Informerのイベントハンドラ登録 |
| 2-2 | job_controller.go | `pkg/controller/job/job_controller.go` | Run関数（245-277行目）: ワーカーgoroutineの起動 |

**主要処理フロー**:
1. **172-174行目**: NewController: PodInformer, JobInformer, KubeClientを受け取り初期化
2. **197-209行目**: JobInformerにAdd/Update/Deleteハンドラ登録
3. **213-225行目**: PodInformerにAdd/Update/Deleteハンドラ登録
4. **245-277行目**: Run: キャッシュ同期後、workerとorphanWorkerを起動

#### Step 3: syncJob処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | job_controller.go | `pkg/controller/job/job_controller.go` | syncJob関数: Jobの状態を評価しPodの作成/削除を実行する中核ロジック |

#### Step 4: Pod失敗ポリシーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pod_failure_policy.go | `pkg/controller/job/pod_failure_policy.go` | PodFailurePolicyの評価ロジック |
| 4-2 | success_policy.go | `pkg/controller/job/success_policy.go` | SuccessPolicyの評価ロジック |

#### Step 5: Indexed Jobユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | indexed_job_utils.go | `pkg/controller/job/indexed_job_utils.go` | インデックス管理、completedIndexesの計算 |
| 5-2 | backoff_utils.go | `pkg/controller/job/backoff_utils.go` | Pod再作成のバックオフ計算 |

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

```
NewController (初期化)
    |
    +-- Run (ワーカー起動)
        |
        +-- worker -> processNextWorkItem -> syncHandler (= syncJob)
        |       |
        |       +-- getPodsForJob
        |       +-- podFailurePolicy evaluation
        |       +-- successPolicy evaluation
        |       +-- manageJob (Pod作成/削除)
        |       |       +-- controller.RealPodControl.CreatePods
        |       |       +-- controller.RealPodControl.DeletePod
        |       +-- updateJobStatus
        |
        +-- orphanWorker -> processNextOrphanPod
                +-- removeTrackingFinalizerFromPod
```

### データフロー図

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

Job Informer ----+
                 |---> workqueue ---> syncJob ---> manageJob ---> Pod作成/削除 (API Server)
Pod Informer ----+                      |
                                        +---> updateJobStatus ---> Jobステータス更新 (API Server)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| job_controller.go | `pkg/controller/job/job_controller.go` | ソース | メインコントローラーロジック |
| pod_failure_policy.go | `pkg/controller/job/pod_failure_policy.go` | ソース | PodFailurePolicy評価 |
| success_policy.go | `pkg/controller/job/success_policy.go` | ソース | SuccessPolicy評価 |
| indexed_job_utils.go | `pkg/controller/job/indexed_job_utils.go` | ソース | Indexed Jobユーティリティ |
| backoff_utils.go | `pkg/controller/job/backoff_utils.go` | ソース | Pod再作成バックオフ計算 |
| tracking_utils.go | `pkg/controller/job/tracking_utils.go` | ソース | ファイナライザトラッキング |
| util/ | `pkg/controller/job/util/` | ソース | Job完了判定等のユーティリティ |
| metrics/ | `pkg/controller/job/metrics/` | ソース | Prometheusメトリクス定義 |
| config/ | `pkg/controller/job/config/` | 設定 | コントローラー設定構造体 |
