# 画面設計書 23-kubectl port-forward

## 概要

本ドキュメントは、Kubernetes CLIツール kubectl の `port-forward` コマンドに関する画面設計書である。kubectl port-forward はローカルポートをPodのポートに転送し、ローカルからPod内のサービスにアクセス可能にする。

### 本画面の処理概要

kubectl port-forward コマンドは、ローカルマシンの指定ポートとKubernetesクラスター上のPodのポートを接続するトンネルを作成する。これにより、クラスター外からPod内のサービスに直接アクセスできるようになる。

**業務上の目的・背景**：クラスター内部のサービスに外部から直接アクセスする必要がある場合に使用する。デバッグ、開発中のサービスへのアクセス、データベースへの一時的な接続、管理用Webインターフェースへのアクセスなど、Service/Ingress を経由せずにPodと通信するケースで活用される。

**画面へのアクセス方法**：ターミナルから `kubectl port-forward <TYPE/NAME> [LOCAL_PORT:]REMOTE_PORT` を実行する。

**主要な操作・処理内容**：
1. 対象Pod/リソースの検索とフォワード可能なPodの特定
2. Service指定時のポートマッピング解決（targetPort への変換）
3. UDPポートの検出と拒否
4. SPDY/WebSocket トンネルの確立
5. ローカルポートでの待ち受けとデータ転送

**画面遷移**：単独で使用される。他のコマンドからの遷移はない。Ctrl+C またはPod終了でセッション終了。

**権限による表示制御**：対象Podの `pods/portforward` サブリソースに対する権限が必要。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 89 | ポートフォワード（port-forward） | 主機能 | ローカルポートをPodのポートに転送する主処理 |
| 66 | Kubelet API Server | API連携 | Kubeletのポートフォワードエンドポイントを通じて転送を確立する |

## 画面種別

CLI常駐型コマンド（フォアグラウンドプロセス）

## URL/ルーティング

```
kubectl port-forward TYPE/NAME [options] [LOCAL_PORT:]REMOTE_PORT [...[LOCAL_PORT_N:]REMOTE_PORT_N]
```

内部的には以下の REST API エンドポイントを使用：
```
POST /api/v1/namespaces/{namespace}/pods/{name}/portforward
```

## 入出力項目

| 項目名 | 種別 | 必須 | 型 | 説明 |
|--------|------|------|-----|------|
| TYPE/NAME | 引数 | Yes | string | フォワード対象のPod/Deployment/Service |
| [LOCAL_PORT:]REMOTE_PORT | 引数 | Yes | string[] | ポートマッピング（1つ以上） |
| --address | フラグ | No | string[] | 待ち受けアドレス（デフォルト: localhost） |
| --pod-running-timeout | フラグ | No | duration | PodがRunningになるまでの待機時間（デフォルト: 60s） |

## 表示項目

| 項目名 | 説明 |
|--------|------|
| フォワード開始メッセージ | "Forwarding from [address]:port -> port" |
| 接続メッセージ | 接続/切断に関するメッセージ |
| エラーメッセージ | ポートフォワード中のエラー |

## イベント仕様

### 1-ポートフォワード開始

1. Complete: リソース検索、Pod特定、Service時のtargetPort解決、UDPチェック
2. Validate: PodName、ポート数、クライアント設定の確認
3. RunPortForward: Pod状態確認 -> シグナルハンドラ設定 -> PortForwarder起動

### 2-ポートフォワード終了

Ctrl+C（SIGINT）受信、Pod終了、またはコンテキストキャンセルで停止。StopChannelがクローズされる。

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| port-forward実行 | - | SELECT | Pod情報の取得のみ |

kubectl port-forward はリソースの状態を変更しない。

### テーブル別更新項目詳細

該当なし

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 表示条件 |
|------------|------|--------------|----------|
| M-01 | エラー | "TYPE/NAME and list of ports are required for port-forward" | 引数不足（2未満） |
| M-02 | エラー | "pod name or resource type/name must be specified" | PodName空 |
| M-03 | エラー | "at least 1 PORT is required for port-forward" | ポート未指定 |
| M-04 | エラー | "unable to forward port because pod is not running. Current status=%v" | PodがRunning以外 |
| M-05 | エラー | "UDP protocol is not supported for %s" | UDPポートの指定 |
| M-06 | エラー | "remote port cannot be empty" | リモートポート空 |

## 例外処理

| 例外 | 状態 | 対処 |
|------|------|------|
| Pod が Running 以外 | エラー終了 | Running状態でない旨を表示 |
| UDPポート指定 | エラー終了 | UDP非サポートのエラーを表示 |
| Service ポートが見つからない | エラー終了 | ポートが見つからないエラーを表示 |
| 名前付きポートが解決不能 | エラー終了 | ポート名解決失敗のエラーを表示 |
| SPDY/WebSocket 接続失敗 | フォールバック | WebSocket失敗時はSPDYにフォールバック |

## 備考

- ランダムポート割り当ては `LOCAL_PORT` を空にすることで可能（例: `:5000`）。
- Service 指定時は targetPort への自動変換が行われる（`translateServicePortToTargetPort` 関数、行185-218）。
- 名前付きポート（`https` など）もサポートされる。
- WebSocket トンネリングが有効な場合、最初に WebSocket を試みSPDYにフォールバックする（行145-156）。
- `--address 0.0.0.0` で全インターフェースからアクセス可能にできる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | PortForwardOptions（行51-62）: Namespace, PodName, Ports, Address, StopChannel, ReadyChannel |

**読解のコツ**: StopChannel と ReadyChannel がゴルーチン間の同期に使用される。ReadyChannel はポートフォワードが準備完了した際にクローズされる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | NewCmdPortForward（行102-121）: コマンド定義 |

**主要処理フロー**:
1. **行112-114**: Complete -> Validate -> RunPortForward の3段階実行

#### Step 3: ポート解決ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | Complete（行318-395）: Service/Pod毎の分岐処理 |
| 3-2 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | translateServicePortToTargetPort（行185-218）: Serviceポートの変換 |
| 3-3 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | convertPodNamedPortToNumber（行222-248）: 名前付きポートの数値変換 |

#### Step 4: フォワード実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | RunPortForwardContext（行422-456）: Pod状態確認、シグナルハンドラ、ForwardPorts呼び出し |
| 4-2 | portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | createDialer（行139-156）: SPDY/WebSocketダイアラーの作成 |

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

```
NewCmdPortForward (行102)
    |
    +-- Complete (行318)
    |       +-- f.NewBuilder() -> Pod特定
    |       +-- AttachablePodForObjectFn
    |       +-- translateServicePortToTargetPort / convertPodNamedPortToNumber
    |       +-- checkUDPPortInService / checkUDPPortInPod
    |
    +-- Validate (行398)
    |
    +-- RunPortForward -> RunPortForwardContext (行422)
            |
            +-- PodClient.Pods().Get() (行423)
            +-- signal.Notify(signals, os.Interrupt) (行433)
            +-- RESTClient.Post().SubResource("portforward") (行449-453)
            +-- PortForwarder.ForwardPorts (行455)
                    |
                    +-- createDialer (行139)
                    |       +-- spdy.RoundTripperFor
                    |       +-- NewSPDYOverWebsocketDialer
                    |       +-- NewFallbackDialer
                    +-- portforward.NewOnAddresses (行163)
                    +-- fw.ForwardPorts (行167)
```

### データフロー図

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

ユーザー引数             Complete
(TYPE/NAME, PORTS) ---> (Pod特定, ポート解決)
                              |
                         Validate
                         (必須チェック)
                              |
                         RunPortForwardContext
                         (Pod Running確認)
                              |
ローカルクライアント     SPDY/WebSocket Tunnel          Podのポート
(localhost:LOCAL) ----> (ポートフォワード) ------------> (REMOTE_PORT)
       ^                      |                              |
       |                      |                              |
       +-------- レスポンスデータ <---------------------------+
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| portforward.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go` | ソース | port-forward コマンドの主実装 |
| portforward/ | `staging/src/k8s.io/client-go/tools/portforward/` | ソース | ポートフォワード実装（SPDY/WebSocket） |
| spdy/ | `staging/src/k8s.io/client-go/transport/spdy/` | ソース | SPDYトランスポート |
| util/ | `staging/src/k8s.io/kubectl/pkg/util/` | ソース | LookupServicePortNumberByName等のユーティリティ |
| portforward_test.go | `staging/src/k8s.io/kubectl/pkg/cmd/portforward/portforward_test.go` | テスト | ユニットテスト |
