# 機能設計書 62-ログ管理

## 概要

本ドキュメントは、Kubeletにおけるコンテナログの取得・ローテーション管理およびジャーナルログ提供機能の設計を記述する。

### 本機能の処理概要

Kubeletのログ管理機能は、コンテナログのライフサイクル管理（ローテーション・圧縮・クリーンアップ）とノードのシステムログ（journald/イベントログ）の提供を行うコンポーネントである。

**業務上の目的・背景**：コンテナログはアプリケーションのデバッグや運用監視に不可欠であるが、無制限に蓄積するとディスクを圧迫する。ログ管理機能は、ログの最大サイズ・最大ファイル数に基づくローテーションポリシーを適用し、ディスク容量の管理を自動化する。また、ノードのシステムログをHTTP経由で提供することで、kubectl logs --node等によるリモートログ取得を可能にする。

**機能の利用シーン**：(1) コンテナログが設定サイズを超過した際の自動ローテーション、(2) コンテナ削除時の関連ログファイルクリーンアップ、(3) kubectl get --raw /api/v1/nodes/{node}/proxy/logs によるノードログ取得。

**主要な処理内容**：
1. CRIを通じてコンテナログのサイズを定期的に監視する
2. MaxSizeを超過したログファイルをタイムスタンプ付きでローテーションする
3. ローテーション済みログをgzip圧縮し、MaxFiles超過分を古い順に削除する
4. journalctl/Get-WinEventを通じてシステムサービスのログを取得・提供する

**関連システム・外部連携**：CRI（Container Runtime Interface）、ファイルシステム、journald（Linux）/EventLog（Windows）。

**権限による制御**：ノードログの取得にはKubelet APIへのアクセス権限（認証・認可）が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 20 | kubectl logs | API連携 | Kubelet経由でコンテナログを取得する |

## 機能種別

データ管理（ログファイルのローテーション・圧縮・クリーンアップ）/ データ連携（ノードログのHTTP提供）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| maxSize | string | Yes | コンテナログの最大サイズ（例："10Mi"） | resource.ParseQuantityで解析可能であること |
| maxFiles | int | Yes | 保持する最大ログファイル数 | 2以上 |
| maxWorkers | int | Yes | ログローテーションワーカー数 | 1以上 |
| monitorInterval | Duration | Yes | ログ監視間隔 | 正の値 |
| query | []string | No (ノードログ) | サービス名またはファイルパス | 最大4サービス、1ファイル |
| sinceTime | string | No | RFC3339形式の開始時刻 | RFC3339形式 |
| untilTime | string | No | RFC3339形式の終了時刻 | sinceTime以降 |
| tailLines | int | No | 末尾から取得する行数 | 0-100000 |

### 入力データソース

- CRI RuntimeService: コンテナ一覧・ステータス・ログパス
- ファイルシステム: ログファイルの実体
- journald / Windows EventLog: システムサービスログ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ローテーション済みログ | ファイル | タイムスタンプ付き(.YYYYMMDD-HHMMSS)のローテーションファイル |
| 圧縮ログ | ファイル | gzip圧縮されたログファイル(.gz) |
| ノードログ応答 | text/plain | HTTP応答としてのログテキスト |

### 出力先

- ファイルシステム: コンテナログディレクトリ（ローテーション・圧縮結果）
- HTTP応答: Kubelet API Server経由でクライアントに返送

## 処理フロー

### 処理シーケンス

```
1. ContainerLogManager.Start()
   └─ maxWorkers数のワーカーgoroutineを起動、定期的にrotateLogs()を実行
2. rotateLogs()
   └─ CRIからRunning状態のコンテナ一覧取得、各コンテナIDをキューに追加
3. processContainer()
   └─ コンテナのログファイルサイズを確認、MaxSize超過時にrotateLog()を呼び出し
4. rotateLog()
   └─ 未使用ログのクリーンアップ → 超過ファイル削除 → 未圧縮ログの圧縮 → 最新ログのローテーション
5. ノードログ取得時: journalServer.ServeHTTP()
   └─ クエリパラメータ解析 → サービス/ファイルの判定 → journalctl実行またはファイル読み取り
```

### フローチャート

```mermaid
flowchart TD
    A[定期監視タイマー] --> B[rotateLogs: コンテナ一覧取得]
    B --> C[各コンテナをキューに追加]
    C --> D[ワーカーがキューから取得]
    D --> E{ログサイズ > MaxSize?}
    E -->|No| F[スキップ]
    E -->|Yes| G[rotateLog]
    G --> H[未使用ログクリーンアップ]
    H --> I[超過ファイル削除]
    I --> J[未圧縮ログをgzip圧縮]
    J --> K[最新ログをリネーム+ReopenContainerLog]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-62-01 | ローテーション対象 | Running状態のコンテナのみローテーション対象 | 定期監視時 |
| BR-62-02 | 最小ファイル数 | MaxFilesは2以上必須（最新ログ+ローテーション先で最低2） | 初期化時 |
| BR-62-03 | 無効化設定 | MaxSizeが負数の場合、ローテーションは無効化される | 初期化時 |
| BR-62-04 | タイムスタンプ形式 | ローテーションファイル名は元ファイル名+".YYYYMMDD-HHMMSS" | ローテーション時 |
| BR-62-05 | ノードログ制限 | サービス指定は最大4個、ファイル指定は最大1個 | ノードログ取得時 |

### 計算ロジック

- 最大ローテーションファイル数: `maxRotatedFiles = MaxFiles - 2`（最新ログと新規作成分を除く）
- タイムスタンプ形式: `"20060102-150405"`（Go time format）
- ノードログタイムアウト: 30秒

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

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

本機能はデータベースを直接操作しない。ファイルシステム上のログファイルが操作対象である。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | CRIエラー | ListContainers/ContainerStatus失敗 | エラーログ出力、次回リトライ |
| - | ファイルI/Oエラー | ログファイルのStat/Rename/Remove失敗 | エラーログ出力、次回リトライ |
| - | ReopenContainerLog失敗 | ランタイムがログファイルを再オープンできない | ローテーション済みファイルを元に戻す |
| 400 | リクエストエラー | 無効なクエリパラメータ | HTTP 400 Bad Request |

### リトライ仕様

- ログローテーション失敗は次回の定期監視サイクルで自動リトライされる
- ReopenContainerLog失敗時はファイル名を元に戻して次回リトライに備える

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

ログローテーションはアトミックなファイル操作（rename）で行われる。圧縮は一時ファイル(.tmp)経由で行い、完了後にリネームすることでデータ損失を防止する。

## パフォーマンス要件

- 複数ワーカーによる並列ログローテーション処理
- rate-limitingキューによるバックプレッシャー制御
- gzip圧縮はBestSpeedレベルを使用（ノードログ応答時）

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

- ノードログ取得はKubelet APIの認証・認可を経由する（root権限相当）
- サービス名の入力にはunsafe文字チェック（`reServiceNameUnsafeCharacters`）が適用される
- ファイルパス指定時は `/var/log/` 配下に限定（`os.OpenInRoot`によるパストラバーサル防止）

## 備考

- ノードログ取得機能はLinux（journalctl）とWindows（Get-WinEvent）で異なる実装を持つ
- ログローテーションポリシーはKubelet設定（`--container-log-max-size`、`--container-log-max-files`）で制御

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | ContainerLogManagerインターフェース（55-60行目）: Start/Cleanの公開API |
| 1-2 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | LogRotatePolicy構造体（64-71行目）: ローテーションポリシー定義 |
| 1-3 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | containerLogManager構造体（100-109行目）: 内部状態 |

**読解のコツ**: `workqueue.TypedRateLimitingInterface`を使用した非同期処理パターンに注目。コンテナIDをキューに投入し、複数ワーカーが並列で処理する。

#### Step 2: コンテナログローテーションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | Start関数（144-157行目）: ワーカー起動と定期監視ループ |
| 2-2 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | rotateLogs関数（193-216行目）: コンテナ一覧取得とキュー投入 |
| 2-3 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | processContainer関数（218-270行目）: 個別コンテナの処理 |
| 2-4 | container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | rotateLog関数（272-305行目）: ローテーション実行 |

**主要処理フロー**:
- **193-216行目**: Running状態のコンテナのみをキューに追加
- **260行目**: ログサイズがMaxSize未満ならスキップ
- **280-298行目**: クリーンアップ→超過削除→圧縮の順で処理
- **300行目**: rotateLatestLogで最新ログのローテーション

#### Step 3: ノードログ取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | kubelet_server_journal.go | `pkg/kubelet/kubelet_server_journal.go` | nodeLogQuery構造体（92-98行目）: クエリパラメータ定義 |
| 3-2 | kubelet_server_journal.go | `pkg/kubelet/kubelet_server_journal.go` | ServeHTTP関数（65-89行目）: HTTPハンドラ |
| 3-3 | kubelet_server_journal.go | `pkg/kubelet/kubelet_server_journal.go` | copyForBoot関数（280-298行目）: サービス/ファイルの振り分け |

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

```
ContainerLogManager
    │
    ├─ Start()
    │      ├─ processQueueItems() [maxWorkers goroutines]
    │      │      └─ processContainer()
    │      │             └─ rotateLog()
    │      │                    ├─ cleanupUnusedLogs()
    │      │                    ├─ removeExcessLogs()
    │      │                    ├─ compressLog()
    │      │                    └─ rotateLatestLog()
    │      └─ rotateLogs() [periodic]
    │             └─ CRI ListContainers() → queue.Add()
    │
    └─ Clean()
           └─ CRI ContainerStatus() → osInterface.Remove()

journalServer
    │
    └─ ServeHTTP()
           └─ nodeLogQuery.Copy()
                  └─ copyForBoot()
                         ├─ splitNativeVsFileLoggers()
                         ├─ copyServiceLogs() → exec.Command(journalctl)
                         └─ copyFileLogs() → heuristicsCopyFileLogs()
```

### データフロー図

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

CRI コンテナ一覧 ──────▶ rotateLogs() ──────────▶ キューに投入
CRI ログパス ──────────▶ processContainer() ────▶ サイズチェック
ログファイル ──────────▶ rotateLog() ───────────▶ ローテーション済みファイル
                                                    圧縮ファイル(.gz)

HTTPリクエスト ────────▶ journalServer ─────────▶ HTTP応答(text/plain)
journalctl出力 ────────▶ copyServiceLogs() ────▶ HTTP応答ストリーム
/var/log/ファイル ──────▶ copyFileLogs() ────────▶ HTTP応答ストリーム
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| container_log_manager.go | `pkg/kubelet/logs/container_log_manager.go` | ソース | コンテナログローテーション管理 |
| container_log_manager_stub.go | `pkg/kubelet/logs/container_log_manager_stub.go` | ソース | ローテーション無効時のスタブ実装 |
| kubelet_server_journal.go | `pkg/kubelet/kubelet_server_journal.go` | ソース | ノードログHTTPハンドラ |
| kubelet_server_journal_linux.go | `pkg/kubelet/kubelet_server_journal_linux.go` | ソース | Linux固有のjournalctl連携 |
| kubelet_server_journal_windows.go | `pkg/kubelet/kubelet_server_journal_windows.go` | ソース | Windows固有のGet-WinEvent連携 |
| container_log_manager_test.go | `pkg/kubelet/logs/container_log_manager_test.go` | テスト | ログ管理のユニットテスト |
