# 機能設計書 88-コンテナ実行（exec）

## 概要

本ドキュメントは、kubectlの`exec`コマンドによるコンテナ内コマンド実行機能の設計を記述する。稼働中のPodのコンテナ内で任意のコマンドを実行し、標準入出力を介して対話的なシェルアクセスも可能にする。

### 本機能の処理概要

**業務上の目的・背景**：稼働中のコンテナ内でデバッグコマンドを実行するための機能を提供する。コンテナ内でのファイル確認、環境変数チェック、ネットワーク接続確認など、トラブルシューティングに不可欠な操作を可能にする。

**機能の利用シーン**：コンテナ内でのデバッグ（bash/shセッション）、ファイル内容の確認、ネットワーク診断（ping/curl）、データベースクライアントの実行、ログファイルの直接確認など。

**主要な処理内容**：
1. コマンドライン引数の解析（Complete）
2. Pod/コンテナの特定
3. TTY設定とストリーム管理
4. SPDY/WebSocket経由でのリモートコマンド実行
5. 標準入出力の転送

**関連システム・外部連携**：API Serverのexecサブリソースを経由してkubeletに接続し、コンテナランタイムのexec機能を使用する。SPDY/WebSocketプロトコルを使用する。

**権限による制御**：対象Podに対するpods/exec権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 3 | kubectl exec | 主機能 | コンテナ内でコマンドを実行する主処理 |

## 機能種別

操作実行 / リモートコマンド実行

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| POD / TYPE/NAME | string | Yes | Pod名またはリソースタイプ/名前 | Pod、ファイル名のいずれか必須 |
| COMMAND | string[] | Yes | 実行するコマンドと引数 | --以降に指定必須 |
| -c / --container | string | No | コンテナ名 | 省略時はPod内の最初のコンテナ |
| -i / --stdin | bool | No | stdinをコンテナに転送 | - |
| -t / --tty | bool | No | TTYを割り当て | -iがなければTTY不使用 |
| -q / --quiet | bool | No | 不要な出力を抑制 | - |
| -f / --filename | string[] | No | リソース定義ファイル | JSON形式のみ |
| --pod-running-timeout | duration | No | Pod起動待機タイムアウト | デフォルト60秒 |

### 入力データソース

- コマンドライン引数
- 標準入力（-i指定時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| コマンド出力 | stream | 実行されたコマンドの標準出力 |
| エラー出力 | stream | 実行されたコマンドの標準エラー出力 |

### 出力先

- 標準出力（stdout）：コマンドのstdout
- 標準エラー出力（stderr）：コマンドのstderr（TTY時はstdoutに統合）

## 処理フロー

### 処理シーケンス

```
1. NewCmdExec: コマンド定義
2. Complete: オプション補完
   ├─ ArgsLenAtDash解析（--以降のコマンド抽出）
   ├─ Namespace解決
   ├─ RESTConfig取得
   └─ PodClient初期化
3. Validate: バリデーション
   ├─ Pod名/リソース名/ファイル名の必須チェック
   ├─ コマンドの必須チェック
   └─ 出力ストリームの必須チェック
4. Run: コマンド実行
   ├─ Pod取得（直接指定 or Builder経由）
   ├─ Pod状態チェック（Succeeded/Failedは不可）
   ├─ コンテナ名解決
   ├─ SetupTTY（TTY設定）
   ├─ RESTClient.Post().SubResource("exec")
   └─ Executor.Execute（SPDY/WebSocket経由）
```

### フローチャート

```mermaid
flowchart TD
    A[開始: Run] --> B{PodName直接指定?}
    B -->|Yes| C[PodClient.Pods.Get]
    B -->|No| D[Builder.Do.Object]
    D --> E[ExecutablePodFn]
    C --> F{Pod状態チェック}
    E --> F
    F -->|Succeeded/Failed| G[エラー: completed pod]
    F -->|Running| H[コンテナ名解決]
    H --> I[SetupTTY]
    I --> J{TTY && Terminal?}
    J -->|Yes| K[Raw TTY設定]
    J -->|No| L[通常ストリーム]
    K --> M[RESTClient.Post exec]
    L --> M
    M --> N[Executor.Execute]
    N --> O{SPDY or WebSocket?}
    O --> P[SPDYExecutor]
    O --> Q[WebSocketExecutor + Fallback]
    P --> R[StreamWithContext]
    Q --> R
    R --> S[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | コマンド必須 | --以降にコマンド指定が必須 | 常時 |
| BR-02 | 完了Pod不可 | Succeeded/Failedフェーズのコンテナにはexec不可 | 常時 |
| BR-03 | コンテナ自動選択 | コンテナ未指定時はFindOrDefaultContainerByNameでデフォルトコンテナを選択 | -c未指定時 |
| BR-04 | TTY自動無効化 | stdinが端末でない場合、TTYを自動的に無効化 | -t指定時 |
| BR-05 | TTY時stderr統合 | TTY有効時はstderrをnilに設定（stdoutに統合） | TTY時 |
| BR-06 | WebSocket優先 | RemoteCommandWebsocketsが無効でない限りWebSocketを優先使用（SPDYフォールバック） | 常時 |
| BR-07 | POD/COMMAND形式廃止 | `exec POD COMMAND`形式は非推奨、`exec POD -- COMMAND`形式を使用 | 常時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Pod取得 | etcd（API Server経由） | SELECT | 対象Podの情報取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | バリデーションエラー | Pod名未指定かつファイル名未指定 | Pod名またはファイルを指定 |
| - | バリデーションエラー | コマンド未指定 | --以降にコマンドを指定 |
| - | 実行エラー | Pod状態がSucceeded/Failed | 稼働中のPodを指定 |
| - | 接続エラー | WebSocket/SPDY接続失敗 | ネットワーク設定を確認 |

### リトライ仕様

WebSocket接続失敗時にSPDYへのフォールバックを行う（httpstream.IsUpgradeFailure/IsHTTPSProxyErrorの場合）。

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

コマンド実行は単一操作であり、トランザクション管理は不要。

## パフォーマンス要件

- defaultPodExecTimeout = 60秒（Pod起動待機タイムアウト）
- ストリーム転送はリアルタイムで行われる

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

- pods/exec権限が必要（RBAC）
- コンテナ内で任意のコマンドを実行できるため、高い権限が必要
- TTYモードでは入出力が暗号化されたストリーム経由で転送される
- PodSecurityPolicyやSecurityContextによるコンテナ内の権限制御はexecにも適用される

## 備考

- createExecutor関数（146-166行目）でSPDYExecutorとWebSocketExecutorのフォールバック構成を作成
- terminalSizeQueueAdapterでターミナルサイズの動的変更を転送
- `kubectl cp`コマンドもExecOptionsを使用してファイル転送を実現

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | StreamOptions構造体（168-184行目）でストリームオプションを把握 |
| 1-2 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | ExecOptions構造体（187-204行目）でexec固有オプションを把握 |
| 1-3 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | RemoteExecutorインターフェース（116-122行目）で実行抽象を把握 |

#### Step 2: TTYセットアップを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | SetupTTY関数（261-311行目）でTTY設定処理を理解 |

**主要処理フロー**:
- **267-271行目**: stdin無しの場合、In=nilとしてTTY無効化
- **279-284行目**: isTerminalIn()による端末判定
- **296行目**: t.Raw = trueで生モードに設定
- **302-308行目**: dockerterm.StdStreamsでWindowsストリーム対応

#### Step 3: コマンド実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | Run関数（314-407行目）で実行処理を理解 |
| 3-2 | exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | createExecutor関数（146-166行目）でエグゼキューター作成を理解 |

**主要処理フロー**:
- **319-346行目**: Pod取得（直接指定 or Builder経由 → ExecutablePodFn）
- **350-351行目**: Succeeded/Failedフェーズのチェック
- **354-361行目**: コンテナ名解決（FindOrDefaultContainerByName）
- **378-399行目**: RESTClient.Post().SubResource("exec")でAPIリクエスト構築
- **402行目**: t.Safe(fn)でTTY安全実行

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

```
NewCmdExec (exec.go:81)
    │
    ├─ Complete (exec.go:207)
    │      ├─ f.ToRawKubeConfigLoader().Namespace()
    │      ├─ f.ToRESTConfig()
    │      └─ f.KubernetesClientSet()
    │
    ├─ Validate (exec.go:248)
    │
    └─ Run (exec.go:314)
           ├─ PodClient.Pods.Get / Builder.Do().Object()
           ├─ ExecutablePodFn
           ├─ FindOrDefaultContainerByName
           ├─ SetupTTY (exec.go:261)
           │      └─ dockerterm.StdStreams
           └─ Executor.Execute (exec.go:399)
                  └─ createExecutor (exec.go:146)
                         ├─ remotecommand.NewSPDYExecutor
                         ├─ remotecommand.NewWebSocketExecutor
                         └─ remotecommand.NewFallbackExecutor
```

### データフロー図

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

stdin ──────────────▶ SetupTTY ──▶ RESTClient.Post
(--stdin指定時)                      /exec サブリソース
                                        │
                                  SPDY/WebSocket
                                        │
                                  kubelet → コンテナランタイム
                                        │
                                  stdout ◀──────────────── コマンド出力
                                  stderr ◀──────────────── コマンドエラー
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| exec.go | `staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go` | ソース | コマンド定義・実行処理 |
| podcmd/podcmd.go | `staging/src/k8s.io/kubectl/pkg/cmd/util/podcmd/podcmd.go` | ソース | デフォルトコンテナ選択 |
| term/term.go | `staging/src/k8s.io/kubectl/pkg/util/term/term.go` | ソース | TTYユーティリティ |
