# 機能設計書 15-Endpointコントローラー

## 概要

本ドキュメントは、Kubernetes Endpointコントローラーの機能設計を記述する。ServiceとPodの紐付けを管理し、Endpointsリソースを更新する。

### 本機能の処理概要

**業務上の目的・背景**：KubernetesのServiceはラベルセレクタでPodを選択し、ネットワークトラフィックをルーティングする。EndpointコントローラーはServiceのセレクタに一致するPodのIPアドレスとポート情報を収集し、Endpointsリソースとして管理する。これによりkube-proxyやCoreDNSが正しいバックエンドPodにトラフィックを転送できる。

**機能の利用シーン**：Service作成時、Pod追加/削除/更新時、Podの状態変化（Ready/NotReady）時のEndpoints自動更新。

**主要な処理内容**：
1. Service Informerからのイベント検出とEndpoints同期
2. Pod InformerからのPod変更検出とマッチするServiceの特定
3. Serviceセレクタに一致するPodの収集
4. PodのIPアドレスとポートからEndpointSubsetの構築
5. Ready/NotReadyアドレスの分類
6. Endpointsリソースの作成・更新
7. 容量超過時のEndpointsトランケーション（最大1000エンドポイント）
8. 孤立Endpointsの検出と削除

**関連システム・外部連携**：API Server、kube-proxy（Endpointsを監視してiptables/IPVS/nftablesルールを更新）、CoreDNS（サービスディスカバリー）

**権限による制御**：コントローラーはEndpoints/Services/Podsの読み取りとEndpointsの作成・更新・削除権限を持つ。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Endpointコントローラーは直接の画面を持たない |

## 機能種別

コントローラー（Reconciliation Loop） / データ同期

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Service.spec.selector | map[string]string | - | Podセレクタ（nilの場合処理しない） | - |
| Service.spec.type | ServiceType | - | ExternalNameの場合処理しない | - |
| Service.spec.ports | []ServicePort | - | サービスポート定義 | - |
| Service.spec.publishNotReadyAddresses | bool | - | NotReadyアドレスを含めるか | - |
| Service.spec.ipFamilies | []IPFamily | - | IPファミリー | IPv4/IPv6 |
| endpointUpdatesBatchPeriod | time.Duration | No | Pod変更からEndpoints更新までの遅延 | - |

### 入力データソース

- Kubernetes API Server: Service Informer
- Kubernetes API Server: Pod Informer
- Kubernetes API Server: Endpoints Informer

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Endpoints.subsets | []EndpointSubset | IPアドレス・ポートのサブセット |
| Endpoints.labels | map[string]string | Serviceから継承したラベル |
| Endpoints.annotations | map[string]string | over-capacity、lastChangeTriggerTime |

### 出力先

- Kubernetes API Server: Endpointsリソースの作成・更新・削除

## 処理フロー

### 処理シーケンス

```
1. イベント受信
   a. Service Add/Update/Delete → serviceキューにエンキュー
   b. Pod Add/Update/Delete → podキューにエンキュー
   c. Endpoints Delete → serviceキューにエンキュー
2. podWorker: Pod変更からマッチするServiceを特定し、serviceキューにエンキュー
3. worker: serviceキューからデキューしsyncServiceを実行
   a. Serviceが存在しない場合: Endpoints削除
   b. ExternalName/セレクタなし: 処理スキップ
   c. セレクタに一致するPod一覧を取得
   d. Pod情報からEndpointSubsetを構築
   e. 現在のEndpointsと比較し変更がある場合のみ更新
   f. 容量超過時はトランケーション
4. checkLeftoverEndpoints: 起動時にServiceなしの孤立Endpointsを検出・キュー追加
```

### フローチャート

```mermaid
flowchart TD
    A[Service/Pod/Endpoints イベント] --> B{イベント種別}
    B -->|Service| C[serviceキュー]
    B -->|Pod| D[podキュー → syncPod → serviceキュー]
    B -->|Endpoints Delete| C
    C --> E[syncService]
    E --> F{Service存在?}
    F -->|No| G[Endpoints削除]
    F -->|Yes| H{ExternalName or セレクタなし?}
    H -->|Yes| I[スキップ]
    H -->|No| J[セレクタでPod取得]
    J --> K[EndpointSubset構築]
    K --> L{変更あり?}
    L -->|No| M[スキップ]
    L -->|Yes| N{容量超過?}
    N -->|Yes| O[トランケーション + アノテーション]
    N -->|No| P[Endpoints作成/更新]
    O --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | セレクタなしService除外 | spec.selectorがnilの場合はEndpointsを管理しない | 常時 |
| BR-02 | ExternalName除外 | type=ExternalNameの場合はEndpointsを管理しない | 常時 |
| BR-03 | Ready/NotReady分類 | PodがReadyならAddresses、そうでなければNotReadyAddresses | publishNotReadyAddresses=false |
| BR-04 | 容量制限 | maxCapacity=1000を超える場合はトランケーション | エンドポイント数 > 1000 |
| BR-05 | IPファミリーマッチ | ServiceのIPFamiliesに一致するPod IPのみ使用 | 常時 |
| BR-06 | Headless Service | ClusterIP=NoneのServiceはポートなしでもEndpointsを作成 | ClusterIP=None |

### 計算ロジック

- maxCapacity = 1000（トランケーション閾値）
- maxRetries = 15（最大リトライ回数）
- トランケーション: サブセット間でエンドポイント数の割合に基づいて比例配分

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Endpoints作成 | Endpoints (etcd) | INSERT | 新規Service用 |
| Endpoints更新 | Endpoints (etcd) | UPDATE | Pod変更時 |
| Endpoints削除 | Endpoints (etcd) | DELETE | Service削除時 |

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

#### Endpoints (etcd)

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | subsets | Pod IP/Port情報 | セレクタに一致するPodから構築 |
| INSERT/UPDATE | labels | Serviceラベル + managed-by | endpoint-controller |
| INSERT/UPDATE | annotations | over-capacity, lastChangeTriggerTime | 条件に応じて設定 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| FailedToCreateEndpoint | Warning Event | Endpoints作成失敗 | RateLimited requeue（最大15回） |
| FailedToUpdateEndpoint | Warning Event | Endpoints更新失敗 | RateLimited requeue（最大15回） |
| - | Forbidden | Namespace Terminating | 処理ドロップ |

### リトライ仕様

- 最大15回リトライ後にキューからドロップ
- exponential backoff: 5ms * 2^(retry-1)

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

Endpoints更新は単一のAPI呼び出しで行われる。staleEndpointsTrackerにより、古いキャッシュからの不要な更新を防止する。

## パフォーマンス要件

- maxCapacity: 1000（Endpointsリソースの最大エンドポイント数）
- endpointUpdatesBatchPeriod: Pod変更のバッチ化遅延
- staleEndpointsTracker: キャッシュの古さを追跡して不要な更新を回避

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

- Endpointsリソースにはバックエンド PodのIPアドレスが含まれる
- リーダーエレクション用Endpointsは孤立チェックから除外される

## 備考

- EndpointSliceコントローラー（No.16）がより効率的な代替として推奨される
- LabelManagedBy = "endpoints.kubernetes.io/managed-by" で管理者を識別
- 起動時にcheckLeftoverEndpointsで孤立Endpointsを検出

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | Controller構造体（132-180行目） |

**読解のコツ**: queueとpodQueueの2つのキューがある点に注意。podQueueはPod→Service変換を行い、最終的にqueueに投入する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | NewEndpointController（80-129行目） |
| 2-2 | endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | Run（184-219行目） |

**主要処理フロー**:
1. **80-129行目**: Service/Pod/Endpoints Informerのハンドラ登録
2. **184-219行目**: worker、podWorker、checkLeftoverEndpointsの起動
3. **334-542行目**: syncService: メイン同期ロジック

#### Step 3: 同期処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | syncService（334-542行目）: セレクタPodの収集とEndpoints更新 |
| 3-2 | endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | truncateEndpoints（684-738行目）: 容量超過時のトランケーション |

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

```
NewEndpointController (初期化)
    |
    +-- Run
        |
        +-- worker -> processNextWorkItem -> syncService
        |       +-- serviceLister.Services().Get
        |       +-- podLister.Pods().List (セレクタでPod取得)
        |       +-- addEndpointSubset (Subset構築)
        |       +-- endpoints.RepackSubsets
        |       +-- truncateEndpoints
        |       +-- client.CoreV1().Endpoints().Create/Update
        |
        +-- podWorker -> syncPod -> serviceキューに追加
        |
        +-- checkLeftoverEndpoints (起動時孤立検出)
```

### データフロー図

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

Service Informer ---+
                    |
Pod Informer -------+---> syncService ---> Endpoints作成/更新 (API Server)
                    |
Endpoints Informer -+
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| endpoints_controller.go | `pkg/controller/endpoint/endpoints_controller.go` | ソース | メインコントローラーロジック |
| endpoints_tracker.go | `pkg/controller/endpoint/endpoints_tracker.go` | ソース | staleEndpointsTracker |
| config/ | `pkg/controller/endpoint/config/` | 設定 | コントローラー設定構造体 |
