# 通知設計書 35-NodeAllocatableEnforced

## 概要

本ドキュメントは、KubernetesクラスタにおいてノードのAllocatable制限が正常に適用された際に発行されるNodeAllocatableEnforcedイベント通知の設計を記述する。kubeletのContainer ManagerがcgroupにNode Allocatable制限を設定し、成功した際にこの通知が発行される。

### 本通知の処理概要

NodeAllocatableEnforced通知は、kubeletのContainer Manager（containerManagerImpl）がNode Allocatable制限をcgroupに正常に適用した際に発行されるNormalイベントである。この通知は複数の場面で発行される可能性がある：Pod用cgroupルートへの制限適用、System Reserved cgroupへの制限適用、Kube Reserved cgroupへの制限適用、およびそれぞれのCompressible版。

**業務上の目的・背景**：Node Allocatableは、ノードのリソース（CPU、メモリ等）からシステムやKubernetesコンポーネントの予約分を差し引いた、Pod に割り当て可能なリソース量を管理する仕組みである。cgroup制限の適用成功を通知することで、ノードのリソース管理が正しく機能していることを確認できる。

**通知の送信タイミング**：kubeletのContainer ManagerがEnforce Node Allocatable処理を実行し、cgroupの制限更新が成功した時点で発行される。cgroupルートへの制限はリトライループ内で成功するまで繰り返される。

**通知の受信者**：Kubernetes APIサーバを通じてイベントが記録され、ノードオブジェクトに紐づけられる。

**通知内容の概要**：適用対象に応じたメッセージが記録される。例：「Updated Node Allocatable limit across pods」「Updated limits on system reserved cgroup {name}」「Updated limits on kube reserved cgroup {name}」。

**期待されるアクション**：通常は正常動作の確認として参照される。特別なアクションは不要であるが、この通知が長時間発行されない場合はAllocatable制限の適用に問題がある可能性がある。

## 通知種別

Kubernetes Event（Normal）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（cgroupルート: ゴルーチン内、その他: 同期） |
| 優先度 | 低（Normal EventType） |
| リトライ | cgroupルート: 成功するまで1分間隔でリトライ |

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

イベントはContainer Managerが管理するノードオブジェクト参照（nodeRef）に対して記録される。

## 通知テンプレート

### メール通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元アドレス | N/A（Kubernetes Event） |
| 送信元名称 | kubelet |
| 件名 | N/A |
| 形式 | Kubernetes Event Object |

### 本文テンプレート

```
# cgroupルート制限適用時
Updated Node Allocatable limit across pods

# System Reserved cgroup制限適用時
Updated limits on system reserved cgroup %v

# Kube Reserved cgroup制限適用時
Updated limits on kube reserved cgroup %v
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| N/A | N/A | N/A | 添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| cgroupName | cgroup名（System/Kube Reserved用） | nc.SystemReservedCgroupName / nc.KubeReservedCgroupName | No（cgroupルート時は不要） |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| cgroup更新成功 | cgroupルートの制限更新成功 | cgroupRoot が空でない場合 | リトライループ内で成功時に発行 |
| cgroup更新成功 | System Reserved cgroup制限更新成功 | EnforceNodeAllocatable に SystemReserved が含まれる場合 | 同期処理で発行 |
| cgroup更新成功 | Kube Reserved cgroup制限更新成功 | EnforceNodeAllocatable に KubeReserved が含まれる場合 | 同期処理で発行 |
| cgroup更新成功 | System Reserved Compressible cgroup制限更新成功 | EnforceNodeAllocatable に SystemReservedCompressible が含まれる場合 | 同期処理で発行 |
| cgroup更新成功 | Kube Reserved Compressible cgroup制限更新成功 | EnforceNodeAllocatable に KubeReservedCompressible が含まれる場合 | 同期処理で発行 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| cgroupRootが空 | cgroupRootが空の場合（ルートコンテナの場合）、cgroupルート制限の適用はスキップ |
| EnforceNodeAllocatable未設定 | 各制限タイプがEnforceNodeAllocatableに含まれていない場合はスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Enforce Node Allocatable開始] --> B{cgroupRoot非空?}
    B -->|Yes| C[go func: cgroupルート制限更新ループ]
    C --> D[cgroupManager.Update実行]
    D --> E{成功?}
    E -->|Yes| F[Normal Event: Updated Node Allocatable limit across pods]
    E -->|No| G[Warning Event: Failed to update]
    G --> H[1分スリープ]
    H --> D
    B -->|No| I[System Reserved チェック]
    F --> I
    I --> J{SystemReserved有効?}
    J -->|Yes| K[enforceExistingCgroup実行]
    K --> L{成功?}
    L -->|Yes| M[Normal Event: Updated limits on system reserved cgroup]
    L -->|No| N[Warning Event + return error]
    J -->|No| O[Kube Reserved チェック]
    M --> O
```

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

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| NodeConfig | Allocatable制限の設定値取得 | kubelet設定 |
| cgroupManager | 現在のcgroup状態 | Linux cgroup |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| cgroup | UPDATE | リソース制限の適用 |
| Events | INSERT | NodeAllocatableEnforcedイベントの記録 |

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

| 操作 | 項目（カラム名） | 更新値 | 備考 |
|-----|-----------------|-------|------|
| INSERT | Event.Reason | "NodeAllocatableEnforced" | Kubernetes Eventオブジェクト |
| INSERT | Event.Type | "Normal" | EventTypeNormal |
| INSERT | Event.Message | 対象に応じたメッセージ | 上記テンプレート参照 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| cgroup更新失敗 | メモリ使用量超過等 | cgroupルート: 1分間隔でリトライ、その他: エラーreturn |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | cgroupルート: 無制限、その他: なし |
| リトライ間隔 | 1分（time.Sleep(time.Minute)） |
| リトライ対象エラー | cgroupManager.Update()のエラー |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 5件程度（各cgroup種別ごとに最大1件） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

時間帯の制限なし。kubelet起動時にContainer Managerの初期化処理で実行される。

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

- cgroup名が含まれるが機密情報ではない
- イベントはKubernetes RBACにより閲覧権限が制御される

## 備考

- Linux環境専用の機能であり、node_container_manager_linux.goに実装されている
- cgroupルートへの制限適用は別ゴルーチンで非同期に実行される（Pod Evictionによるメモリ使用量低下を待つため）
- CgroupsPerQOSが有効かつNodeAllocatableEnforcementKeyが設定されている場合、Node Allocatable値が使用される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | event.go | `pkg/kubelet/events/event.go` | 79行目: `SuccessfulNodeAllocatableEnforcement = "NodeAllocatableEnforced"` 定数定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | node_container_manager_linux.go | `pkg/kubelet/cm/node_container_manager_linux.go` | 70-148行目: Enforce Node Allocatable処理全体 |

**主要処理フロー**:
1. **74行目**: EnforceNodeAllocatable設定チェック
2. **94行目**: cgroupRootが非空であることの確認
3. **96-106行目**: リトライループ（cgroupルート制限）
4. **99行目**: 成功時 `cm.recorder.Event(nodeRef, v1.EventTypeNormal, events.SuccessfulNodeAllocatableEnforcement, ...)`
5. **109-146行目**: System Reserved / Kube Reserved / Compressible版の順次適用

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

```
containerManagerImpl.Enforce Node Allocatable
    |
    +-- [cgroupRoot非空の場合]
    |      +-- go func() リトライループ
    |             +-- cgroupManager.Update()
    |             +-- [成功] recorder.Event(Normal, "NodeAllocatableEnforced")
    |
    +-- [SystemReserved有効の場合]
    |      +-- enforceExistingCgroup()
    |      +-- [成功] recorder.Eventf(Normal, "NodeAllocatableEnforced", ...)
    |
    +-- [KubeReserved有効の場合]
    |      +-- enforceExistingCgroup()
    |      +-- [成功] recorder.Eventf(Normal, "NodeAllocatableEnforced", ...)
    |
    +-- [SystemReservedCompressible有効の場合]
    |      +-- enforceExistingCgroup()
    |      +-- [成功] recorder.Eventf(Normal, "NodeAllocatableEnforced", ...)
    |
    +-- [KubeReservedCompressible有効の場合]
           +-- enforceExistingCgroup()
           +-- [成功] recorder.Eventf(Normal, "NodeAllocatableEnforced", ...)
```

### データフロー図

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

NodeConfig                   containerManagerImpl                 Kubernetes Event
(Allocatable設定)  ----->    Enforce Node Allocatable        ----> (Reason: "NodeAllocatableEnforced",
                              (node_container_manager_             Type: Normal)
cgroup状態         ----->     linux.go:70-148)               |
                              cgroupManager.Update()         +--> cgroup制限更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| event.go | `pkg/kubelet/events/event.go` | ソース | イベント定数定義 |
| node_container_manager_linux.go | `pkg/kubelet/cm/node_container_manager_linux.go` | ソース | Enforce Node Allocatable処理 |
| container_manager.go | `pkg/kubelet/cm/container_manager.go` | ソース | ContainerManager インターフェース定義 |
