# 画面設計書 20-kubectl logs

## 概要

本ドキュメントは、Kubernetes CLIツール `kubectl logs` コマンドの画面設計書である。Pod内のコンテナのログを取得・表示するコマンドの仕様を記載する。

### 本画面の処理概要

`kubectl logs` コマンドは、指定されたPod（またはDeployment/ReplicaSet等のリソース）内のコンテナのログをAPI Server/Kubelet経由で取得し、標準出力に表示する。リアルタイムストリーミング（follow）、過去ログ取得、ラベルセレクタによる複数Pod同時取得など、多彩なログ参照機能を提供する。

**業務上の目的・背景**：アプリケーションのデバッグ、障害調査、動作確認のためにコンテナのログを参照することは、Kubernetes運用における最も基本的な操作の一つである。本コマンドにより、Pod内のコンテナが出力した標準出力/標準エラー出力の内容を確認できる。

**画面へのアクセス方法**：ターミナル上で `kubectl logs <Pod名>` を実行する。Pod内にコンテナが1つの場合はコンテナ名の指定は不要。

**主要な操作・処理内容**：
1. Pod名またはリソース種別/名前でログ取得対象を指定する
2. コンテナログをAPI Server/Kubelet経由で取得する
3. ストリーミングモード（-f）で継続的にログを表示する
4. 時間範囲やバイト制限でログをフィルタリングする
5. 複数Podのログを並行して取得・表示する

**画面遷移**：本コマンドは情報表示のみのCLIコマンドであり、リソース変更は行わない。トラブルシューティングフローで `kubectl describe` と共に頻繁に使用される。

**権限による表示制御**：podリソースのget権限とpods/logのget権限が必要。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 87 | ログ表示（logs） | 主機能 | Pod/コンテナのログを取得・表示する主処理 |
| 62 | ログ管理 | API連携 | Kubelet経由でコンテナログを取得する |
| 66 | Kubelet API Server | API連携 | Kubeletのログ取得エンドポイントにリクエストを送信する |

## 画面種別

CLI コマンド（情報表示 - ログ）

## URL/ルーティング

```
kubectl logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]
```

## 入出力項目

### 入力項目

| 項目名 | フラグ | 型 | 必須 | デフォルト | 説明 |
|--------|--------|------|------|-----------|------|
| Pod名/リソース | 位置引数 | string | Yes(*) | - | Pod名またはTYPE/NAME形式 |
| コンテナ名 | -c, --container | string | No | "" | 対象コンテナ名。単一コンテナPodでは不要 |
| コンテナ名（位置） | 位置引数（2番目） | string | No | - | コンテナ名を位置引数でも指定可能 |
| フォロー | -f, --follow | bool | No | false | ログのリアルタイムストリーミング |
| 前回コンテナ | -p, --previous | bool | No | false | 前回終了したコンテナのログを表示 |
| タイムスタンプ | --timestamps | bool | No | false | 各行にタイムスタンプを付加 |
| 末尾行数 | --tail | int64 | No | -1 | 表示する末尾行数。-1は全行。セレクタ使用時はデフォルト10行 |
| バイト制限 | --limit-bytes | int64 | No | 0 | 最大取得バイト数。0は無制限 |
| 時間指定（相対） | --since | duration | No | 0 | 指定時間以降のログのみ表示（例: 1h） |
| 時間指定（絶対） | --since-time | string | No | "" | RFC3339形式の時刻以降のログのみ表示 |
| 全コンテナ | --all-containers | bool | No | false | Pod内の全コンテナのログを表示 |
| 全Pod | --all-pods | bool | No | false | リソース配下の全Podのログを表示（prefixを自動有効化） |
| ラベルセレクタ | -l, --selector | string | No | "" | ラベルによるPod選択 |
| プレフィックス | --prefix | bool | No | false | 各行にPod名/コンテナ名をプレフィックス |
| 最大並行数 | --max-log-requests | int | No | 5 | follow時の最大並行ログ数 |
| エラー無視 | --ignore-errors | bool | No | false | ストリーミング中のエラーを非致命的に |
| TLS検証スキップ | --insecure-skip-tls-verify-backend | bool | No | false | Kubelet証明書の検証をスキップ |
| Pod起動タイムアウト | --pod-running-timeout | duration | No | 20s | Pod起動待機のタイムアウト |

(*) Pod名/リソースまたは--selectorのいずれかが必須

### 出力項目

| 項目名 | 説明 |
|--------|------|
| コンテナログ | コンテナの標準出力/標準エラー出力の内容 |

## 表示項目

| 項目 | 形式 | 説明 |
|------|------|------|
| ログ行 | テキスト | コンテナの出力テキスト |
| タイムスタンプ | RFC3339 | --timestamps指定時の各行先頭 |
| プレフィックス | `[pod/<pod>/<container>]` | --prefix指定時の各行先頭 |

## イベント仕様

### 1-logs実行（単一Pod）

1. コマンドライン引数を解析しLogsOptionsを初期化する（`Complete`、logs.go L249-325）
2. Pod名とセレクタの排他チェック（L261-263）
3. PodLogOptionsを構築する（`ToLogOptions`、L212-247）
4. Builderでリソースを取得する（L298-322）
5. LogsForObjectでログストリームを取得する（`RunLogsContext`、L373-398）
6. DefaultConsumeRequestでログを読み取り出力する（L475-496）

### 2-logs実行（複数Pod/follow）

1. 上記1-3と同様の初期化
2. AllPodLogsForObject（--all-pods時）またはLogsForObjectでリクエストマップを構築（L376-383）
3. follow時かつ複数Pod時は並行消費（`parallelConsumeRequest`、L400-429）
   - 各Podのログを個別のgoroutineで取得
   - io.Pipeで出力を統合
   - --max-log-requestsで並行数を制限（L386-391）
4. 非follow時またはPod単一時は順次消費（`sequentialConsumeRequest`、L431-444）

## データベース更新仕様

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

| 操作（イベント） | 対象リソース | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| logs実行 | Pod/PodList | SELECT | ログ取得対象のPodを特定 |
| logs実行 | pods/log | SELECT | コンテナログをKubelet経由で取得 |

読み取り専用コマンドのため、データ書き込みは発生しない。

## メッセージ仕様

| 種別 | メッセージ | 条件 |
|------|-----------|------|
| エラー | `expected 'logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER]'` | 引数不正 |
| エラー | `only a selector (-l) or a POD name is allowed` | Pod名とセレクタの同時指定 |
| エラー | `--all-containers=true should not be specified with container name %s` | --all-containersとコンテナ名の同時指定 |
| エラー | `only one of -c or an inline [CONTAINER] arg is allowed` | -cフラグと位置引数コンテナの同時指定 |
| エラー | `--limit-bytes must be greater than 0` | 負のlimit-bytes |
| エラー | `--since must be greater than 0` | 負のsince |
| エラー | `--tail must be greater than or equal to -1` | -1未満のtail |
| エラー | `at most one of sinceTime or sinceSeconds may be specified` | --sinceと--since-timeの同時指定 |
| エラー | `you are attempting to follow %d log streams, but maximum allowed concurrency is %d` | 並行数超過 |
| 情報 | `No resources found in %s namespace.` | 対象Podなし |

## 例外処理

| 例外条件 | 動作 |
|---------|------|
| Pod名未指定かつセレクタ未指定 | 使用法エラーを表示して終了 |
| Podが見つからない | NotFoundエラーを表示して終了 |
| コンテナが見つからない | エラーメッセージを表示して終了 |
| follow中のストリームエラー | --ignore-errors=trueなら継続、falseなら停止 |
| 最大並行数超過 | エラーメッセージを表示して終了 |
| --sinceと--since-timeの同時指定 | バリデーションエラーを表示して終了 |
| シグナル受信（Ctrl+C） | ストリーミングを停止してos.Exit(1) |

## 備考

- --all-pods=trueを指定するとprefixが自動的に有効化される（L271-273）
- セレクタ使用時のデフォルトtailは10行（`selectorTail`、L112）。--tailの明示指定で上書き可能
- DefaultConsumeRequestはバッファリング読み取りを行い、改行単位で出力する（L475-496）。これによりサブラインレベルのインターリーブを防止する
- prefixingWriterは`[pod/<pod>/<container>]`形式のプレフィックスを各行に付加する（L460-465）
- containerNameFromRefSpecRegexpでFieldPathからコンテナ名を抽出する（L158、L455-458）
- RunLogsはシグナルハンドリング付きのRunLogsContextラッパー（L361-368）
- follow時の並行消費ではio.Pipeで出力を統合し、prefixとデータのアトミック書き込みを行う（L508-517）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | LogsOptions構造体（L120-159）：全オプションを保持 |
| 1-2 | types.go (core/v1) | `staging/src/k8s.io/api/core/v1/types.go` | PodLogOptions：API Serverへのログリクエストオプション |

**読解のコツ**: LogsOptions.Options（runtime.Object型）は実際にはPodLogOptions。ToLogOptionsメソッドでLogsOptionsからPodLogOptionsに変換される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | NewCmdLogs関数（L172-190）：コマンド定義 |
| 2-2 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | AddFlags（L192-210）：全フラグの登録 |

**主要処理フロー**:
1. **L173**: NewLogsOptionsでオプション初期化（デフォルトtail=-1, MaxFollowConcurrency=5）
2. **L182-186**: Complete -> Validate -> RunLogsの実行チェーン
3. **L188**: AddFlagsで大量のフラグを登録

#### Step 3: 初期化とバリデーション

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | Complete（L249-325）：リソース解決とオプション構築 |
| 3-2 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | ToLogOptions（L212-247）：PodLogOptionsへの変換 |
| 3-3 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | Validate（L327-357）：入力値検証 |

**主要処理フロー**:
- **L254-269**: 引数の数に応じたPod名/コンテナ名の解析
- **L294-295**: LogsForObject/AllPodLogsForObject関数の設定（polymorphichelpers）
- **L298-322**: Builderでリソースを取得

#### Step 4: ログ取得と出力

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | RunLogsContext（L373-398）：ログストリーム取得のメイン |
| 4-2 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | parallelConsumeRequest（L400-429）：並行ログ消費 |
| 4-3 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | sequentialConsumeRequest（L431-444）：順次ログ消費 |
| 4-4 | logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | DefaultConsumeRequest（L475-496）：ストリーム読み取り |

**主要処理フロー**:
- **L376-383**: AllPodLogsForObject/LogsForObjectでリクエストマップ取得
- **L385-391**: follow時の最大並行数チェック
- **L394-397**: follow+複数Podなら並行消費、それ以外は順次消費
- **L476-496**: バッファリング読み取りで改行単位出力

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

```
NewCmdLogs (L172)
    |
    +-- Complete (L249)
    |       +-- ToLogOptions (L212) --> PodLogOptions
    |       +-- f.NewBuilder().Do().Infos()
    |       +-- LogsForObject/AllPodLogsForObject設定
    |
    +-- Validate (L327)
    |
    +-- RunLogs (L361)
            +-- interrupt.New(cancel)
            +-- RunLogsContext (L373)
                    +-- AllPodLogsForObject() / LogsForObject()
                    |       --> map[ObjectRef]ResponseWrapper
                    |
                    +-- [follow + 複数Pod]
                    |   parallelConsumeRequest (L400)
                    |       +-- io.Pipe()
                    |       +-- [各Pod goroutine]
                    |       |       +-- addPrefixIfNeeded (L446)
                    |       |       +-- ConsumeRequestFn (L475)
                    |       +-- io.Copy(Out, reader)
                    |
                    +-- [それ以外]
                        sequentialConsumeRequest (L431)
                                +-- [各Pod]
                                        +-- addPrefixIfNeeded (L446)
                                        +-- ConsumeRequestFn (L475)
```

### データフロー図

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

POD名 / TYPE/NAME       Complete()
  -c CONTAINER         --> リソース解決 ------------>+---> API Server
  -f (follow)          --> PodLogOptions構築 ------->|     (Pod取得)
  --tail N                                           |
  --since DURATION     RunLogsContext()              |
                       --> LogsForObject() --------->+---> API Server/Kubelet
                       --> リクエストマップ取得 ----->|     (ログストリーム)
                                                     |
                       [follow+複数Pod]              |
                       --> parallelConsumeRequest() ->+---> io.Pipe
                       --> goroutine x N ------------>|     並行読み取り
                                                     |
                       [それ以外]                    |
                       --> sequentialConsumeRequest()->+---> stdout
                       --> DefaultConsumeRequest() -->|     ログテキスト
                       --> [prefix付与] ------------->|     [pod/name/container]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| logs.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs.go` | ソース | logsコマンドのメイン実装 |
| logs_test.go | `staging/src/k8s.io/kubectl/pkg/cmd/logs/logs_test.go` | テスト | logsコマンドのユニットテスト |
| logsforobject.go | `staging/src/k8s.io/kubectl/pkg/polymorphichelpers/logsforobject.go` | ソース | LogsForObject：リソース種別に応じたログ取得 |
| interrupt.go | `staging/src/k8s.io/kubectl/pkg/util/interrupt/interrupt.go` | ソース | シグナルハンドリングユーティリティ |
