# 機能設計書 21-Garbage Collectorコントローラー

## 概要

本ドキュメントは、KubernetesのGarbage Collector（GC）コントローラーの機能設計を記述する。GCコントローラーはOwnerReferenceに基づくオブジェクト間の依存関係グラフを構築・維持し、不要となったリソースのカスケード削除およびオーファン処理を自動的に実行する。

### 本機能の処理概要

**業務上の目的・背景**：Kubernetesではリソース間の親子関係がOwnerReferenceによって表現される。親リソースが削除された際に、子リソース（依存リソース）が孤立して残り続けることを防ぐため、自動的なガベージコレクションが必要である。GCコントローラーは、Deployment削除時のReplicaSet・Pod連鎖削除や、カスタムリソースの依存関係管理など、クラスター全体のリソースライフサイクル管理の中核を担う。

**機能の利用シーン**：ユーザーがkubectl deleteでDeploymentを削除した際に、配下のReplicaSetやPodが自動削除されるシーン。また、CRD（CustomResourceDefinition）が削除された際に関連リソースがカスケード削除されるシーン。さらに、--cascade=orphanオプション指定時に子リソースを孤立させるシーンでも利用される。

**主要な処理内容**：
1. 全APIリソースのInformerを動的に起動し、オブジェクトの変更イベントを監視する
2. GraphBuilderが依存関係グラフ（uidToNode）を構築・更新する
3. 親オブジェクトが存在しない（dangling）依存オブジェクトをattemptToDeleteキューに投入する
4. オーファン処理が必要なオブジェクトをattemptToOrphanキューに投入する
5. ワーカーがキューからアイテムを取り出し、API Serverに削除/更新リクエストを送信する

**関連システム・外部連携**：API Server（リソースの取得・削除・パッチ操作）、Discovery API（利用可能なリソースタイプの検出）、メタデータクライアント（PartialObjectMetadataによる軽量アクセス）

**権限による制御**：GCコントローラーはsystem:controller:generic-garbage-collectorサービスアカウントで動作し、全リソースに対するget、list、watch、patch、delete権限を持つ。個々のオブジェクト削除時にはOwnerReferenceのUID一致によるアクセス制御が行われる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | kubectl delete | API連携 | 削除時にOwnerReferenceに基づくカスケード削除が発動する |

## 機能種別

データ連携 / ガベージコレクション（バックグラウンド自動処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| workers | int | Yes | attemptToDelete/attemptToOrphanの並行ワーカー数 | 正の整数 |
| initialSyncTimeout | time.Duration | Yes | 初期同期のタイムアウト時間 | 正の値 |
| terminatedPodThreshold | int | No | 完了Podの保持閾値（PodGC側） | 0以上の整数 |

### 入力データソース

- API Server Discovery API: 全リソースタイプの一覧取得
- 各リソースのInformer: list/watchによるリソース変更イベント（add/update/delete）
- メタデータクライアント: PartialObjectMetadataによるOwnerReference情報の取得

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 削除リクエスト | DELETE API呼び出し | 不要と判定されたオブジェクトの削除 |
| パッチリクエスト | PATCH API呼び出し | OwnerReferenceの除去（dangling参照のクリーンアップ） |
| ステータスパッチ | PATCH API呼び出し | FinalizerDeletingDependentsの除去 |
| イベント | Event API呼び出し | GC関連のイベント記録 |

### 出力先

- API Server: リソースの削除・更新操作
- Kubernetes Events: GC処理のイベントログ
- メトリクス: Prometheusメトリクス（gc_controller_*）

## 処理フロー

### 処理シーケンス

```
1. Run()が呼び出され、GCコントローラーが起動する
   └─ EventBroadcasterの開始、GraphBuilderの起動
2. GraphBuilder.Run()が依存関係グラフの構築を開始する
   └─ graphChangesキューからイベントを処理し、uidToNodeマップを更新
3. 初期同期が完了するまで待機する（initialSyncTimeout）
   └─ 全リソースモニターのキャッシュ同期を確認
4. attemptToDeleteワーカーとattemptToOrphanワーカーを起動する
   └─ 各workers個のgoroutineでキュー処理を開始
5. Sync()が定期的にDiscovery APIをポーリングする
   └─ 新規リソースタイプの検出とモニターの再同期
6. attemptToDeleteWorker: キューからノードを取り出し削除判定を行う
   └─ classifyReferencesでsolid/dangling/waitingForDependentsDeletionに分類
7. attemptToOrphanWorker: キューからノードを取り出しオーファン処理を行う
   └─ 依存オブジェクトのOwnerReferenceを除去し、オーナーのFinalizerを除去
```

### フローチャート

```mermaid
flowchart TD
    A[Run開始] --> B[EventBroadcaster開始]
    B --> C[GraphBuilder起動]
    C --> D{初期同期完了?}
    D -->|Yes| E[ワーカー起動]
    D -->|Timeout| E
    E --> F[attemptToDeleteWorker]
    E --> G[attemptToOrphanWorker]

    F --> H{キューからノード取得}
    H --> I[attemptToDeleteItem]
    I --> J{オブジェクト存在確認}
    J -->|NotFound| K[仮想削除イベント発行]
    J -->|存在| L{OwnerReference分類}
    L -->|solid有り| M[dangling参照をパッチで除去]
    L -->|全てdangling| N{Finalizer確認}
    N -->|OrphanFinalizer| O[DeletePropagationOrphan]
    N -->|DeleteDependentsFinalizer| P[DeletePropagationForeground]
    N -->|なし| Q[DeletePropagationBackground]

    G --> R{キューからノード取得}
    R --> S[依存オブジェクトのOwnerRef除去]
    S --> T[オーナーのOrphanFinalizer除去]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | カスケード削除 | 親オブジェクト削除時に全ての依存オブジェクトも削除される | DeletePropagationBackground/Foreground時 |
| BR-21-02 | オーファン処理 | 親オブジェクト削除時に依存オブジェクトのOwnerReferenceのみ除去される | DeletePropagationOrphan時またはOrphanFinalizer存在時 |
| BR-21-03 | Foreground削除 | 依存オブジェクトの削除完了後に親オブジェクトが削除される | FinalizerDeletingDependents存在時 |
| BR-21-04 | UID一致検証 | オブジェクト削除時にUIDが一致することを確認し、同名の新規オブジェクト誤削除を防止する | 全削除操作時 |
| BR-21-05 | 仮想ノード処理 | Informer未観測のオーナーに対して仮想ノードを作成し、後続で実体確認する | GraphBuilderでの参照先オーナー未検出時 |
| BR-21-06 | absentOwnerキャッシュ | NotFoundとなったオーナーをキャッシュし、API Server負荷を軽減する | isDangling判定時 |
| BR-21-07 | 名前空間スコープ検証 | クラスタースコープオブジェクトが名前空間スコープオーナーを参照する場合はエラーとする | isDangling判定時 |

### 計算ロジック

- **dangling判定**: `isDangling()`でAPI Serverに問い合わせ、オーナーが存在しないかUID不一致の場合にdanglingと判定
- **削除ポリシー決定**: solid参照が1つでもある場合は削除しない。全参照がdanglingの場合、Finalizerに基づいてOrphan/Foreground/Backgroundを決定
- **循環検出**: waitingForDependentsDeletionの依存がdeletingDependentsを持つ場合、循環を防ぐためにblockingOwnerReferenceを解除

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| オブジェクト取得 | 全APIリソース（etcd） | SELECT（GET） | OwnerReferenceの最新状態確認 |
| オブジェクト削除 | 全APIリソース（etcd） | DELETE | 不要オブジェクトの削除 |
| OwnerReference除去 | 全APIリソース（etcd） | UPDATE（PATCH） | dangling OwnerReferenceのクリーンアップ |
| Finalizer除去 | 全APIリソース（etcd） | UPDATE（PATCH） | DeleteDependents/Orphan Finalizerの除去 |

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

#### 全APIリソース（etcd経由）

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | UID一致、ResourceVersion指定 | GracePeriodSeconds=0でForeground削除時 |
| PATCH | metadata.ownerReferences | dangling参照の除去 | Strategic Merge Patch使用 |
| PATCH | metadata.finalizers | FinalizerDeleteDependents/FinalizerOrphanDependentsの除去 | Strategic Merge Patch使用 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NotFound | API応答 | 削除対象オブジェクトが既に存在しない | 仮想削除イベントを発行しグラフから除去 |
| Conflict | API応答 | ResourceVersionが変更されている | JSON Merge Patchにフォールバック |
| restMappingError | 内部 | リソースタイプがREST Mapperに未登録 | ログ出力しリトライ（Discovery再同期で解決を期待） |
| namespacedOwnerOfClusterScopedObjectErr | 内部 | クラスタースコープオブジェクトが名前空間スコープオーナーを参照 | リトライせず破棄 |
| enqueuedVirtualDeleteEventErr | 内部 | 仮想削除イベントを投入済み | リトライせず破棄（GraphBuilder側で処理） |

### リトライ仕様

- attemptToDeleteキュー: RateLimitingキューによるエクスポネンシャルバックオフでリトライ
- attemptToOrphanキュー: RateLimitingキューによるエクスポネンシャルバックオフでリトライ
- restMappingError: 次回のDiscovery同期でリソースが認識されるまでリトライ継続
- パッチ失敗時: Strategic Merge PatchからJSON Merge Patchへのフォールバック

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

Kubernetesはetcdを使用しており、従来のRDBMSトランザクションは存在しない。各API操作はResourceVersionによる楽観的並行性制御（Optimistic Concurrency Control）を用いる。削除操作ではUID preconditionを指定し、同名の新規オブジェクトの誤削除を防止する。

## パフォーマンス要件

- ワーカー数はデフォルトで20（attemptToDelete: 20ワーカー、attemptToOrphan: 20ワーカー）
- Discovery APIのポーリング間隔は30秒
- ResourceResyncTimeは0（再同期なし、イベント駆動のみ）
- absentOwnerCacheにより不存在オーナーへのAPI呼び出しを削減
- メタデータクライアントによりPartialObjectMetadataのみ取得し、ネットワーク帯域を節約

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

- GCコントローラーはsystem:controller:generic-garbage-collectorサービスアカウントで実行される
- 全リソースに対する広範な権限を持つため、サービスアカウントの認証情報は厳重に管理する必要がある
- OwnerReference.UID一致による検証で、権限のないオブジェクトの誤削除を防止
- BlockOwnerDeletion=trueの場合、依存オブジェクトの作成者にオーナー削除をブロックする権限があることがAdmission Controlで検証される

## 備考

- GCコントローラーはkube-controller-managerの一部として起動される
- カスタムリソース（CRD）もOwnerReferenceを持つ場合はGCの対象となる
- GCの動作はメトリクス（gc_controller_*）で監視可能
- Discovery APIの障害時は既存のモニターを維持し、新規リソースの追加のみスキップする

---

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

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

### 推奨読解順序

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

依存関係グラフのノード構造とイベントの表現を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | graph.go | `pkg/controller/garbagecollector/graph.go` | objectReference構造体（29-33行目）とnode構造体（63-80行目）。ノードはidentity、dependents、deletingDependents、beingDeleted、virtualフラグを持つ |
| 1-2 | graph_builder.go | `pkg/controller/garbagecollector/graph_builder.go` | event構造体（68-76行目）。virtual/eventType/obj/gvkフィールド。eventTypeはadd/update/deleteの3種 |

**読解のコツ**: node構造体は各フィールドに個別のsync.RWMutexを持つ。setterとgetterは異なるロックを使用するため、異なるフィールドの読み取り値が時間的に一貫しない可能性がある点に注意。

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

GCコントローラーの初期化と起動フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | GarbageCollector構造体（64-77行目）。attemptToDelete/attemptToOrphanキュー、dependencyGraphBuilder、absentOwnerCacheを保持 |
| 2-2 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | NewGarbageCollector（83-94行目）とNewComposedGarbageCollector（96-119行目）。GraphBuilderからキューとキャッシュを取得 |

**主要処理フロー**:
1. **132行目**: Run()でEventBroadcaster開始、GraphBuilder起動
2. **153-155行目**: GraphBuilder.Run()をgoroutineで起動
3. **161-167行目**: 初期同期の待機（タイムアウト付き）
4. **172-179行目**: attemptToDeleteワーカーとattemptToOrphanワーカーをworkers個ずつ起動

#### Step 3: GraphBuilderの動作を理解する

依存関係グラフの構築と更新メカニズムを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | graph_builder.go | `pkg/controller/garbagecollector/graph_builder.go` | GraphBuilder構造体（81-100行目）。monitors、uidToNode、graphChanges、attemptToDelete/attemptToOrphanキューを保持 |

**主要処理フロー**:
- **81-100行目**: GraphBuilder構造体定義。monitorLock、running状態を管理
- graphChangesキューからイベントを取得し、processGraphChanges()でuidToNodeマップを更新
- 親なしノードをattemptToDeleteに、オーファン対象をattemptToOrphanにエンキュー

#### Step 4: 削除判定ロジックを理解する

attemptToDeleteWorkerの削除判定フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | attemptToDeleteWorker（322-378行目）。仮想ノード判定、attemptToDeleteItem呼び出し、エラーハンドリング |
| 4-2 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | attemptToDeleteItem（503-651行目）。API Server確認、classifyReferences、削除ポリシー決定 |
| 4-3 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | classifyReferences（464-487行目）。solid/dangling/waitingForDependentsDeletionの3分類 |
| 4-4 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | isDangling（383-456行目）。absentOwnerCache確認、API Serverへの問い合わせ、UID一致検証 |

#### Step 5: オーファン処理を理解する

attemptToOrphanWorkerのオーファン処理フローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | attemptToOrphanWorker（739-765行目）。依存オブジェクトのOwnerReference除去、Finalizer除去 |
| 5-2 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | orphanDependents（673-709行目）。並行goroutineで全依存のOwnerReferenceをパッチ除去 |

#### Step 6: Discovery同期を理解する

新規リソースタイプの検出とモニター再同期の仕組みを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | Sync（190-264行目）。GetDeletableResourcesでリソース一覧を取得し、差分があればresyncMonitorsを呼び出す |
| 6-2 | garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | GetDeletableResources（786-817行目）。delete/list/watchをサポートするリソースのみを対象とする |

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

```
GarbageCollector.Run()
    │
    ├─ GraphBuilder.Run()
    │      ├─ startMonitors() ── 各リソースのInformerを起動
    │      └─ processGraphChanges() ── graphChangesキューを処理
    │             ├─ addNode() / updateNode() / deleteNode()
    │             ├─ attemptToDelete.Add() ── 削除候補をエンキュー
    │             └─ attemptToOrphan.Add() ── オーファン候補をエンキュー
    │
    ├─ runAttemptToDeleteWorker()
    │      └─ attemptToDeleteItem()
    │             ├─ getObject() ── API Serverからオブジェクト取得
    │             ├─ classifyReferences()
    │             │      └─ isDangling() ── 各OwnerReferenceの存在確認
    │             ├─ patch() ── dangling OwnerReferenceの除去
    │             ├─ deleteObject() ── オブジェクト削除
    │             └─ processDeletingDependentsItem()
    │                    └─ removeFinalizer()
    │
    └─ runAttemptToOrphanWorker()
           └─ orphanDependents() ── 依存のOwnerReference除去
                  └─ removeFinalizer() ── OrphanFinalizerの除去
```

### データフロー図

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

Informerイベント ───────▶ GraphBuilder
(add/update/delete)        │ processGraphChanges()
                           │ uidToNode更新
                           ▼
                     attemptToDeleteキュー ───▶ attemptToDeleteWorker
                           │                        │
                           │                        ├─▶ API Server GET (存在確認)
                           │                        ├─▶ API Server PATCH (OwnerRef除去)
                           │                        └─▶ API Server DELETE (オブジェクト削除)
                           │
                     attemptToOrphanキュー ───▶ attemptToOrphanWorker
                                                    │
                                                    ├─▶ API Server PATCH (依存のOwnerRef除去)
                                                    └─▶ API Server PATCH (Finalizer除去)

Discovery API ──────▶ Sync()
(定期ポーリング)         │ resyncMonitors()
                        └─▶ 新規リソースのInformer追加
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| garbagecollector.go | `pkg/controller/garbagecollector/garbagecollector.go` | ソース | GCコントローラーのメインロジック。削除判定、オーファン処理、Discovery同期 |
| graph_builder.go | `pkg/controller/garbagecollector/graph_builder.go` | ソース | GraphBuilderによる依存関係グラフの構築・更新。Informerイベントの処理 |
| graph.go | `pkg/controller/garbagecollector/graph.go` | ソース | グラフノード（node）とオブジェクト参照（objectReference）のデータ構造定義 |
| metrics/metrics.go | `pkg/controller/garbagecollector/metrics/metrics.go` | ソース | Prometheusメトリクスの定義と登録 |
| metaonly/ | `pkg/controller/garbagecollector/metaonly/` | ソース | メタデータのみのオブジェクト変換用ユーティリティ |
| garbagecollector_test.go | `pkg/controller/garbagecollector/garbagecollector_test.go` | テスト | GCコントローラーの単体テスト |
