# 通知設計書 134-HealthCheckNodePort

## 概要

本ドキュメントは、KubernetesのHealthCheckNodePortにおけるServiceヘルスチェック機能に関連するWarningイベントの通知設計について記載する。具体的には、kube-proxyがHealthCheckNodePort上でヘルスチェックのリスン開始に失敗した際に発行される「FailedToStartServiceHealthcheck」イベントを扱う。

### 本通知の処理概要

本通知は、kube-proxyのServiceHealthServerが、Service（externalTrafficPolicy=Local設定）のHealthCheckNodePort上でHTTPヘルスチェックサーバを起動する際に失敗した場合に発行されるWarningイベントである。

**業務上の目的・背景**：LoadBalancerタイプのServiceでexternalTrafficPolicy=Localが設定されている場合、各ノードのHealthCheckNodePortで外部ロードバランサがノードのエンドポイント有無を確認できる。このポートでのヘルスチェック起動に失敗すると、ロードバランサはノードの状態を判定できず、トラフィックの適切な分散に支障をきたす。本通知はこの障害を早期に検知するために発行される。

**通知の送信タイミング**：kube-proxyのSyncServicesメソッドが呼ばれた際に、新しいHealthCheckNodePort上でHTTPリスナーの起動を試み、失敗した場合にイベントが発行される。SyncServicesはProxyサーバの同期サイクルごとに呼ばれる。

**通知の受信者**：対象ServiceのObjectReferenceに紐付くKubernetesイベントとして記録されるため、kubectl describe service等でServiceを参照するクラスタ管理者が受信者となる。

**通知内容の概要**：ノード名、Service名、HealthCheckNodePortのポート番号、および失敗の詳細エラーメッセージを含む警告。

**期待されるアクション**：受信者はポート競合の確認（他プロセスが同じポートを使用していないか）、ファイアウォールルールの確認、kube-proxyの再起動を行う。ServiceのHealthCheckNodePortの変更を検討する場合もある。

## 通知種別

Kubernetesイベント（Event API）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（SyncServices処理内で直接発行） |
| 優先度 | 高 |
| リトライ | なし（次回のSyncServicesサイクルで再試行） |

### 送信先決定ロジック

イベントは対象ServiceのObjectReference（APIVersion: v1, Kind: Service, Namespace, Name）に紐付けて記録される。

## 通知テンプレート

### Kubernetesイベント

| 項目 | 内容 |
|-----|------|
| EventType | Warning |
| Reason | FailedToStartServiceHealthcheck |
| Action | Listen |
| Component | proxy healthcheck |

### 本文テンプレート

```
node %s failed to start healthcheck %q on port %d: %v
```

パラメータ:
- `%s`: ノード名
- `%q`: Service名（namespace/name形式）
- `%d`: HealthCheckNodePortのポート番号
- `%v`: 詳細エラーメッセージ

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | Kubernetesイベントのため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| nodeName | ノード名 | server構造体のnodeNameフィールド | Yes |
| nsn | Service名（namespace/name） | hcInstance.nsn | Yes |
| port | HealthCheckNodePortのポート番号 | hcInstance.port | Yes |
| err | 詳細エラーメッセージ | listenAndServeAllの戻り値 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| Service同期 | SyncServicesメソッド呼び出し | 新規HealthCheckNodePortのリスン開始失敗 | ポートバインド失敗など |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 既存Service | 既にリスンが成功しているServiceについては再度リスン試行しない |
| Recorderなし | recorder（events.EventRecorder）がnilの場合、イベントは発行されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[kube-proxy同期サイクル] --> B[SyncServices呼び出し]
    B --> C[不要なServiceを閉じる]
    C --> D[新しいServiceのHealthCheckを開始]
    D --> E[listenAndServeAll]
    E --> F{全ノードIPでリスン成功?}
    F -->|Yes| G[servicesマップに追加]
    F -->|No| H[既開始のリスナーを閉じる]
    H --> I{recorder != nil?}
    I -->|Yes| J[FailedToStartServiceHealthcheckイベント発行]
    I -->|No| K[エラーログのみ]
    J --> L[Service追加スキップ]
    K --> L
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| Service | HealthCheckNodePortの取得 | ServicePort情報経由 |

### テーブル別参照項目詳細

#### Service

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| Spec.HealthCheckNodePort | HealthCheckポート番号の取得 | externalTrafficPolicy=Localの場合 |
| Spec.ExternalTrafficPolicy | HealthCheckの必要性判定 | ServiceType=LoadBalancer |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Event | INSERT | 警告イベントの記録 |

#### 送信ログテーブル

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Type | Warning | イベントタイプ |
| INSERT | Reason | FailedToStartServiceHealthcheck | イベント理由 |
| INSERT | Action | Listen | アクション種別 |
| INSERT | Message | ノード・Service・ポート・エラー詳細 | 動的生成 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ポートバインド失敗 | 他プロセスが同ポートを使用中 | イベント発行、ログ記録。次回SyncServicesで再試行 |
| ネットワークエラー | ノードIPでのリスン失敗 | 部分失敗時は既開始分をロールバック（closeAll） |
| NodePortAddresses取得失敗 | ノードIP取得エラー | 全アドレス（0.0.0.0）でリスンにフォールバック |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 直接的なリトライなし |
| リトライ間隔 | 次回SyncServicesサイクル（kube-proxy同期間隔依存） |
| リトライ対象エラー | リスン開始に失敗した全てのケース |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Event APIのデフォルトレート制限に従う |
| 1日あたり上限 | 制限なし |

### 配信時間帯

時間帯制限なし。kube-proxyの同期サイクルに従って発行される。

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

- HealthCheckNodePortはクラスタ外部からアクセスされるため、ポート上での情報漏洩に注意が必要
- ヘルスチェックレスポンスにはService名、Namespace、ローカルエンドポイント数、プロキシの健全性状態が含まれる
- HealthCheckNodePortが起動できない場合、外部ロードバランサはノードの状態を判定できなくなる

## 備考

- ServiceHealthServerはHealthCheck対象のServiceポート変更時に、古いリスナーを閉じて新しいリスナーを開始する
- SyncEndpointsメソッドでローカルエンドポイント数が更新され、HTTP応答の内容に反映される
- エンドポイント数が0の場合またはkube-proxyが不健全な場合、HTTP 503が返される
- ヘルスチェックレスポンスは JSON形式でservice情報、localEndpoints数、serviceProxyHealthy状態を含む

---

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

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

### 推奨読解順序

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

ServiceHealthServerの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | service_health.go | `pkg/proxy/healthcheck/service_health.go` | ServiceHealthServerインターフェース（43-53行目）、server構造体（90-102行目）、hcInstance構造体（153-160行目） |

**読解のコツ**: server構造体のservicesマップがNamespacedName→hcInstanceのマッピングを保持。hcInstanceが個々のService用HTTPサーバを管理する。

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

SyncServicesメソッドとイベント発行を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | service_health.go | `pkg/proxy/healthcheck/service_health.go` | SyncServicesメソッド（104-151行目） |

**主要処理フロー**:
1. **109-118行目**: 不要なServiceのヘルスチェックを閉じる
2. **122-149行目**: 新しいServiceのヘルスチェックを開始
3. **131行目**: listenAndServeAllでHTTPサーバを起動
4. **133-146行目**: 失敗時にイベント発行とログ記録

#### Step 3: HTTPサーバの起動とレスポンスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | service_health.go | `pkg/proxy/healthcheck/service_health.go` | listenAndServeAll関数（163-198行目）、hcHandler.ServeHTTP（223-254行目） |

**主要処理フロー**:
- **170-195行目**: 各ノードIPアドレスでHTTPリスナーを起動
- **176-181行目**: リスン失敗時に既開始分をロールバック
- **239-243行目**: エンドポイント数とプロキシ健全性に基づきHTTPステータスコードを返す

#### Step 4: HealthCheckNodePortの設定取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | serviceport.go | `pkg/proxy/serviceport.go` | BaseServicePortInfoのhealthCheckNodePortフィールド（85行目）、HealthCheckNodePort()メソッド（128-130行目） |
| 4-2 | serviceport.go | `pkg/proxy/serviceport.go` | newBaseServicePortInfo関数内のHealthCheckNodePort設定（231-237行目） |

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

```
kube-proxy同期サイクル
    |
    +-- SyncServices (104行目)
           |
           +-- closeAll (200行目) [不要Service閉鎖]
           |
           +-- listenAndServeAll (163行目) [新Service起動]
           |      |
           |      +-- listener.Listen (175行目) [各ノードIP]
           |      |
           |      +-- httpSrv.Serve (187行目) [goroutine]
           |      |
           |      +-- closeAll (179行目) [失敗時ロールバック]
           |
           +-- recorder.Eventf "FailedToStartServiceHealthcheck" (137-143行目) [失敗時]
    |
    +-- SyncEndpoints (256行目)
           |
           +-- hcInstance.endpoints更新 (265行目)
    |
    +-- hcHandler.ServeHTTP (223行目) [HTTP応答]
           |
           +-- 200 OK or 503 Service Unavailable (239-243行目)
```

### データフロー図

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

Service変更 ---------> SyncServices ---------> listenAndServeAll --+
(HealthCheckNodePort)                                              |
                                                                   +---> Kubernetes Event
Endpoint変更 --------> SyncEndpoints -------> hcInstance.endpoints |     (FailedToStartServiceHealthcheck)
                                                      |            |
                                                      v            +---> HTTP Response
外部LBリクエスト ----> hcHandler.ServeHTTP ------------>            (200 OK / 503)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| service_health.go | `pkg/proxy/healthcheck/service_health.go` | ソース | ServiceHealthServer本体。リスン管理、HTTP応答、イベント発行 |
| serviceport.go | `pkg/proxy/serviceport.go` | ソース | ServicePort抽象化。HealthCheckNodePortフィールド管理 |
| servicechangetracker.go | `pkg/proxy/servicechangetracker.go` | ソース | Service変更追跡。HealthCheckNodePorts()メソッド |
| proxier.go (iptables) | `pkg/proxy/iptables/proxier.go` | ソース | iptablesプロキシ。SyncServicesの呼び出し元 |
| proxier.go (ipvs) | `pkg/proxy/ipvs/proxier.go` | ソース | IPVSプロキシ。SyncServicesの呼び出し元 |
| proxier.go (nftables) | `pkg/proxy/nftables/proxier.go` | ソース | nftablesプロキシ。SyncServicesの呼び出し元 |
