# 画面設計書 46-kubeadm join

## 概要

本ドキュメントは、kubeadmのjoinコマンドの画面設計書である。既存のKubernetesクラスタにワーカーノードまたは追加のコントロールプレーンノードを参加させるためのCLIコマンドの仕様を定義する。

### 本画面の処理概要

**業務上の目的・背景**：Kubernetesクラスタのスケールアウトやコントロールプレーンの高可用性構成のため、新しいノードをクラスタに参加させる必要がある。kubeadm joinコマンドは、ディスカバリ（ノードがコントロールプレーンを信頼する）とTLSブートストラップ（コントロールプレーンがノードを信頼する）の双方向の信頼確立を行い、ノードをクラスタに安全に参加させる。

**画面へのアクセス方法**：ターミナルから `kubeadm join <api-server-endpoint> [flags]` を実行する。root権限が必要。kubeadm init実行後に表示されるjoinコマンドをそのまま使用するのが一般的。

**主要な操作・処理内容**：
1. Preflight フェーズ：参加先クラスタとノードの前提条件を検証
2. ControlPlanePrepare フェーズ：コントロールプレーン参加準備（CP参加時のみ）
3. CheckEtcd フェーズ：etcdの状態確認
4. KubeletStart フェーズ：kubeletの起動と設定
5. EtcdJoin フェーズ：etcdクラスタへの参加（CP参加時のみ）
6. KubeletWaitBootstrap フェーズ：kubeletのブートストラップ完了を待機
7. ControlPlaneJoin フェーズ：コントロールプレーンへの参加処理
8. WaitControlPlane フェーズ：コントロールプレーンの起動待機

**画面遷移**：kubeadm initの完了後に使用される。ワーカーノード参加時は完了メッセージのみ表示。コントロールプレーン参加時はkubeconfigの設定手順が表示される。

**権限による表示制御**：root権限が必要。--dry-runフラグでシミュレーション実行が可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 119 | ノード参加（join） | 主機能 | ワーカーノードまたは追加のコントロールプレーンノードをクラスターに参加させる主処理 |
| 121 | 証明書管理 | 補助機能 | 参加時にノード用証明書の生成・取得を行う |
| 1 | API Serverコア | API連携 | クラスター参加のためAPI Serverにリクエストを送信する |

## 画面種別

ワークフロー実行（CLIフェーズ実行型）

## URL/ルーティング

```
kubeadm join [api-server-endpoint] [flags]
kubeadm join phase <phase-name> [flags]
```

## 入出力項目

### 入力項目（フラグ）

| 項目名 | 型 | 必須 | デフォルト | 説明 |
|--------|------|------|-----------|------|
| [api-server-endpoint] | string | 条件付き | - | API Serverのエンドポイント（位置引数、最大1つ） |
| --node-name | string | 任意 | OS hostname | ノード名 |
| --certificate-key | string | 任意 | "" | 証明書暗号化キー（CP参加時） |
| --apiserver-advertise-address | string | 任意 | 自動検出 | API Serverアドバタイズアドレス（CP参加時） |
| --apiserver-bind-port | int32 | 任意 | 6443 | API Serverバインドポート（CP参加時） |
| --discovery-token | string | 任意 | "" | ディスカバリ用トークン |
| --discovery-token-ca-cert-hash | []string | 任意 | [] | CA証明書のハッシュ値 |
| --discovery-token-unsafe-skip-ca-verification | bool | 任意 | false | CA検証をスキップ |
| --discovery-file | string | 任意 | "" | ディスカバリ用kubeconfigファイル |
| --tls-bootstrap-token | string | 任意 | "" | TLSブートストラップトークン |
| --token | string | 任意 | "" | discovery-tokenとtls-bootstrap-tokenの両方に使用 |
| --control-plane | bool | 任意 | false | コントロールプレーンとして参加 |
| --config | string | 任意 | "" | 設定ファイルパス |
| --ignore-preflight-errors | []string | 任意 | [] | 無視するpreflight検査 |
| --dry-run | bool | 任意 | false | ドライラン実行 |
| --patches | string | 任意 | "" | パッチファイルディレクトリ |
| --cri-socket | string | 任意 | 自動検出 | CRIソケットパス |
| --skip-phases | []string | 任意 | [] | スキップするフェーズ |

### 出力項目

参加完了メッセージが標準出力に表示される。ワーカーノードとコントロールプレーンで異なるメッセージ。

## 表示項目

ワーカーノード参加時：
```
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
```

コントロールプレーン参加時：
```
This node has joined the cluster and a new control plane instance was created:
* Certificate signing request was sent to apiserver and approval was received.
* The Kubelet was informed of the new secure connection details.
* Control plane label and taint were applied to the new node.
* The Kubernetes control plane instances scaled up.
* A new etcd member was added to the local/stacked etcd cluster.

To start administering your cluster from this node, you need to run the following as a regular user:
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    ...
```

## イベント仕様

### 1-joinコマンド実行

1. `newCmdJoin` でworkflow.Runnerを作成し、8つのフェーズを登録
2. `SetDataInitializer` で設定のロードとバリデーションを実行
3. `joinRunner.Run(args)` で全フェーズを順次実行
4. 完了後、ワーカー/コントロールプレーンに応じたメッセージを表示

### 2-データ初期化（newJoinData）

1. `--token` が指定された場合、discovery-tokenとtls-bootstrap-tokenの両方に適用
2. ディスカバリ方式（トークン or ファイル）の判定と不要オブジェクトのクリーンアップ
3. `--control-plane` 未指定時はControlPlaneオブジェクトをnil化
4. admin.confが存在する場合、ディスカバリをスキップしてそのファイルを使用
5. 設定ファイルのロードまたはフラグからの内部設定への変換

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| KubeletStart | ファイルシステム(kubelet設定) | CREATE/UPDATE | kubelet設定ファイルの作成・更新 |
| ControlPlanePrepare | ファイルシステム(証明書/kubeconfig) | CREATE | CP参加時の証明書とkubeconfig生成 |
| EtcdJoin | etcdクラスタ | INSERT | etcdメンバーの追加（CP参加時） |
| ControlPlaneJoin | Node(ラベル/taint) | UPDATE | ノードへのラベルとtaintの付与（CP参加時） |

## メッセージ仕様

| メッセージID | 種別 | メッセージ | 条件 |
|-------------|------|----------|------|
| INFO-01 | 情報 | `This node has joined the cluster:` | ワーカーノード参加成功時 |
| INFO-02 | 情報 | `This node has joined the cluster and a new control plane instance was created:` | CP参加成功時 |
| WARN-01 | 警告 | `More than one API server endpoint supplied on command line` | 複数の引数指定時 |
| WARN-02 | 警告 | `--control-plane is also required when passing control-plane related flags` | CP関連フラグのみ指定時 |
| ERR-01 | エラー | `invalid data struct` | 内部データ構造エラー |

## 例外処理

- ディスカバリ方式が判定できない場合はバリデーションエラー
- `--control-plane` なしでコントロールプレーン関連フラグを指定した場合は警告
- TLSブートストラップ失敗時はエラー終了
- DryRunモードでは一時ディレクトリに出力

## 備考

- ディスカバリには2つの方式がある：トークン+APIサーバエンドポイント、kubeconfigファイル
- `--token` フラグは discovery-token と tls-bootstrap-token の両方のショートカット
- admin.confが既に存在する場合（フェーズ単位実行時）、ディスカバリをスキップする最適化がある
- fetchInitConfigurationFromJoinConfiguration関数でクラスタ設定をConfigMapから取得する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | join.go | `cmd/kubeadm/app/cmd/join.go` | joinOptions構造体（行134-143）とjoinData構造体（行150-160）のフィールドを理解する |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | join.go | `cmd/kubeadm/app/cmd/join.go` | newCmdJoin関数（行165-255）でフェーズ登録（行222-229）と完了メッセージ出力（行192-211）を確認 |

**主要処理フロー**:
1. **行169**: workflow.NewRunner()
2. **行175-214**: RunE内で結果に応じたメッセージ出力
3. **行222-229**: 8フェーズの登録
4. **行233-248**: DataInitializerの設定

#### Step 3: データ初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | join.go | `cmd/kubeadm/app/cmd/join.go` | newJoinData関数（行349-485）のトークン処理（行363-370）、ディスカバリ方式判定（行373-385）、ControlPlane処理（行388-406）に注目 |

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

```
newCmdJoin (join.go:165)
    |
    +-- workflow.Runner.Run()
           |
           +-- NewPreflightPhase
           +-- NewControlPlanePreparePhase
           +-- NewCheckEtcdPhase
           +-- NewKubeletStartPhase
           +-- NewEtcdJoinPhase
           +-- NewKubeletWaitBootstrapPhase
           +-- NewControlPlaneJoinPhase
           +-- NewWaitControlPlanePhase
    |
    +-- 完了メッセージ出力
           +-- joinWorkerNodeDoneMsg (ワーカー時)
           +-- joinControlPlaneDoneTemp (CP時)
```

### データフロー図

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

フラグ/設定ファイル ──> newJoinData()
  api-server-endpoint       |
  token                discovery.For() ──> TLS Bootstrap
                           |
                    workflow.Runner.Run()
                           |
                    各フェーズ実行 ──────> kubelet設定
                                         証明書(CP時)
                                         stdout (完了メッセージ)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| join.go | `cmd/kubeadm/app/cmd/join.go` | ソース | joinコマンド本体の実装 |
| phases/join/ | `cmd/kubeadm/app/cmd/phases/join/` | ソース | 各フェーズの実装 |
| discovery/ | `cmd/kubeadm/app/discovery/` | ソース | ディスカバリ処理 |
| token/ | `cmd/kubeadm/app/discovery/token/` | ソース | トークンベースディスカバリ |
| workflow/ | `cmd/kubeadm/app/cmd/phases/workflow/` | ソース | フェーズワークフローランナー |
