kubeadmでkubernetesクラスタ構築

# はじめに

自分でkubernetesクラスタを構築する際の備忘録。VirtualBox+vagrantで構築した場合。
基本的にkubernetesマニュアルの[kubeadmを使ってクラスターを構築する](https://kubernetes.io/ja/docs/setup/production-environment/tools/kubeadm/)をベースにvagrant固有の差分や他の方が記載された記事を反映。

# kubernetesクラスタ構成

MasterノードとWorkerノードをそれぞれ1台構成とする。
ちなみにMasterノードは`コントロールプレーン`とか`Adminノード`など色々書かれているが、ここでは`Masterノード`で統一して書く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218194/0e536af3-ea3b-46ad-872b-eac038ea1d2a.png)

# kubernetesクラスタ構築の流れ
以下の流れでkubernetesクラスタを構築する。
Workerノードで実施する`kubernetesクラスタに参加`は、Masterノードで実施する`Podネットワークアドオンのインストール`終了後に実施すること。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218194/e43d25cb-2469-44d7-b411-c620d3e433a1.png" width=90%>

# インストールするソフトウェアとバージョン

- ゲストVM： ubuntu22.04
    - Masterノード：192.168.56.53
    - Workerノード：192.168.56.54
- コンテナランタイム: containerd2.1.1
    - runc: 1.2.6
    - CNI Plugin: 1.7.1
- cgroupドライバ： systemd cgroupドライバ
- kubernetes: 1.33
- Podネットワークアドオン： Calico v3.30.0

# いざ、インストール
MasterノードとWorkerノードで共通の手順、MasterノードやWorkerノードどちらで実施するかは、<font color="red">[Masterノードで実施]</font>、<font color="blue">[Workerノードで実施]</font>の識別子をつけた。

### インストールするVMがない場合
手元にインストールするVMがないとき、`VirtualBox＋vagrant`が利用可能ならkubernetesクラスタ構成に示したVM用のVagrantfileを[GitHubのレポジトリ](https://github.com/nkoseki/vagrant.git)から持ってきてゲストVMを構築する。
```shell
# 任意のディレクトリで実行
git clone https://github.com/nkoseki/vagrant.git
cd vagrant

# Masterノード構築用
cd 10.master
vagrant up

# Workerノード構築用
cd ../11.worker1/
vagrant up
```
VMのプロビジョニングはタイムゾーンや日本語化、vimの設定を実施している。起動したら`vagrant ssh`でログイン。

## コンテナランタイムのインストール

何はともあれMasterノード、Workerノード上でコンテナが動いていないと話にならない。コンテナ単体で動作させる場合はDockerをコンテナランタイムとして使うケースもあるが、kubernetesが利用するコンテナランタイムとしてはメジャーなcontainerdを使う。
containerdの場合、Dockerのよう直接的なコマンドラインツールはないため、crictlやnerdctlなどの補助ツールを使用してコンテナ操作をする必要があるとのことだが、今回補助ツールはインストールしない。


### IPv4フォワーディングを有効化
<font color="red">[Masterノードで実施]</font><font color="blue">[Workerノードで実施]</font>

VMのIPv4フォワーディングを有効化し、iptablesからブリッジされたトラフィックを見えるようにする。

```shell
# カーネルモジュールの設定
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

# カーネルモジュールを挿入
sudo modprobe overlay
sudo modprobe br_netfilter

# この構成に必要なカーネルパラメーター、再起動しても永続する
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

# 再起動せずにカーネルパラメーターを適用
sudo sysctl --system
```

カーネルモジュール、カーネルパラメータの確認
```shell
# カーネルモジュールがロードされたか確認
lsmod | grep -e br_netfilter -e overlay

# カーネルパラメータが正しく設定されたか確認
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
```

### cgroupドライバーの選択
cgroupドライバとして、昔は`cgroupfs`が利用されていたが、現在のLinuxの起動方式がsystemdになっているので`systemd cgroupドライバ`にするのが普通なのか。kubernetesマニュアルにもsystemdが推奨とあるので素直に従う。
コンテナランタイムとkubeletで同じcgroupドライバを使う必要がある。ここではどのドライバにするか決めるだけで設定は後ほど実施する。

### コンテナランタイムのインストール

<font color="red">[Masterノードで実施]</font><font color="blue">[Workerノードで実施]</font>

コンテナランタイムとしてcontainerdをインストールする場合、下記をインストールする。

`コンテナランタイム本体`
高レベルのCNIインターフェースとも言う。containerd本体。プロセスとして動作しruncに指示をしたり、使用するcgroupドライバの種別を決める。

`コンテナランタイムのサービス起動スクリプト`
オプションとあるが、サービスとしてcontainerdを動かすので入れといた方がいい

`runc`
低レベルのCNIインタフェースとも言う。containerdから呼ばれて実際にコンテナを動かすプログラム

`CNI Plugin`
Podの通信用。VMをまたがったPod同士の通信は`Podネットワークアドオン`としてCalicoで実現する。
`Podネットワークアドオン`も`CNI Plugin`と表現されている場合があるが、両者は別物。

#### コンテナランタイム本体のインストール
```shell
VER=2.1.1
curl -OL https://github.com/containerd/containerd/releases/download/v${VER}/containerd-${VER}-linux-amd64.tar.gz
sudo tar Cxzvf /usr/local containerd-${VER}-linux-amd64.tar.gz

# インストール確認
ls -l /usr/local/bin
```

#### コンテナランタイムのサービス起動スクリプトのインストール
```shell
curl -OL https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
sudo cp ./containerd.service /lib/systemd/system/containerd.service
sudo systemctl daemon-reload
sudo systemctl enable --now containerd

# サービス起動確認
systemctl status containerd
```

低レベルCNIインタフェースのruncがインストールされていなくてもcontainerdが正常に起動される。

#### runcのインストール
```shell
VER=1.2.6 
curl -OL https://github.com/opencontainers/runc/releases/download/v${VER}/runc.amd64
sudo install -m 755 runc.amd64 /usr/local/sbin/runc

# インストール確認
ls -l /usr/local/sbin
```
runcはサービスとして起動しているわけじゃなく、あくまでもcontainerdから呼ばれるプログラム。
Dockerコンテナでも低レベルCNIインタフェースとしてruncを利用している。

#### CNI Pluginのインストール

```shell
VER=1.7.1
curl -OL https://github.com/containernetworking/plugins/releases/download/v${VER}/cni-plugins-linux-amd64-v${VER}.tgz
sudo mkdir -p /opt/cni/bin
sudo tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v${VER}.tgz

# インストール確認
ls -l /opt/cni/bin/
```

### コンテナランタイムとcgroupドライバの紐付け

<font color="red">[Masterノードで実施]</font><font color="blue">[Workerノードで実施]</font>

containerdとsystemd cgrupドライバが紐付けていないので紐づける。
containerdをインストールしても設定変更用の`config.toml`ファイルが出力されないので手動で出力する。containerdはデフォルトで`/etc/containerd`配下を読み込むとのこと。

```shell
sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# 設定情報確認
cat /etc/containerd/config.toml
```
systemd cgroupドライバを利用するように書き換える。

```shell
sudo vi /etc/containerd/config.toml

# config.tomlファイル
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  ...
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    # 下記を追加
    SystemdCgroup = true  
```

修正後、containerdを再起動
```shell
sudo systemctl restart containerd
```

### コンテナランタイムのプロセス起動確認
正常にcontainerdが起動していることが確認できる。
補助ツールを入れると、この段階でコンテナのインストールや起動ができるはず（試したことない）
```shell
systemctl status containerd
```

## kubeadm,kubelet,kubectlのインストール
一部Masterノード、Workerノードだけの手順があるので注意。



### 事前準備

<font color="red">[Masterノードで実施]</font><font color="blue">[Workerノードで実施]</font>

#### SwapをOFFにする
`/etc/fstab`を書き換える
```shell
sudo vi /etc/fstab

# コメントアウトしてswap を永続的にOFFにする
# /swap.img  none  swap  sw  0 0
```
再起動してSwapがOFFを有効にする
```shell
# 再起動
sudo shutdown -r now
```
再起動後、再度ログインしSwapのサイズが0になっていることを確認
```shell
free -m
              total        used        free      shared  buff/cache   available
Mem:           1983         124        1630           0         228        1711
Swap:             0           0           0
```

#### レポジトリ登録

aptのパッケージ更新と必要なパッケージインストール
```shell
# お約束
sudo apt-get update

# 必要なパッケージのインストール
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
```
Kubernetesパッケージリポジトリーの公開署名キーをダウンロード
```shell
# `/etc/apt/keyrings`フォルダーが存在しない場合は、curlコマンドの前に作成する必要があります。
# sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
```
aptレポジトリを追加
```shell
# これで/etc/apt/sources.list.d/kubernetes.listにある既存の設定が上書きされます
VER=v1.33
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${VER}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
```

### kubeadm,kubelet,kubectlのインストール
事前準備が終わったら、kubeadm等のツールインストール

#### <font color="red">[Masterノードで実施]</font>
Masterノードでは以下をインストールする。
```shell
sudo apt-get update
# kubelet, kubeadm, kubectlのインストール
sudo apt-get install -y kubelet kubeadm kubectl
# バージョンを固定する
sudo apt-mark hold kubelet kubeadm kubectl
```

#### <font color="blue">[Workerノードで実施]</font>
Masterノードの実行コマンドからkubectlを取り除く。
```shell
sudo apt-get update
# kubelet, kubeadmのインストール。Workerノードなのでkubectlは不要
sudo apt-get install -y kubelet kubeadm
# バージョンを固定する
sudo apt-mark hold kubelet kubeadm
```

### kubeletが使用するcgroupドライバの設定
containerdで使うのと同じsystemdを指定する。後述の`kubeadm init`および`kubeadm join`実行時に参照される。
vagrantでゲストVMを作成した場合、VMに割り当てられるIPはHostOnlyネットワーク用のIPとNAT用IPの２つのIPが存在するため、`--node-ip`でどちらのIPを利用するか明示する必要がある。
#### <font color="red">[Masterノードで実施]</font>
```shell
cat << EOF | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --node-ip=192.168.56.53
EOF
```

#### <font color="blue">[Workerノードで実施]</font>
```shell
cat << EOF | sudo tee /etc/default/kubelet
KUBELET_EXTRA_ARGS=--cgroup-driver=systemd --node-ip=192.168.56.54
EOF
```

### kubeletのプロセス再起動
<font color="red">[Masterノードで実施]</font><font color="blue">[Workerノードで実施]</font>
kubeletの起動オプションを変更したので、kubelet再起動
```shell
# kubeletの再起動
sudo systemctl daemon-reload
sudo systemctl restart kubelet
```

Masterノード、Workerノードとも、kubernetesの初期化が完了していないためkubeletは正常起動せず再起動を繰り返しているが問題ない.

<details>
  <summary>kubeletの状態確認</summary>

```shell
vagrant@master:~$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: activating (auto-restart) (Result: exit-code) since Sun 2025-06-01 10:53:34 JST; 9s ago
       Docs: https://kubernetes.io/docs/
    Process: 3083 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=1/FAILURE)
   Main PID: 3083 (code=exited, status=1/FAILURE)
        CPU: 94ms
```
</details>


## kubernetesの初期化
<font color="red">[Masterノードで実施]</font>

`--pod-network-cidr`のアドレスはPodネットワークとして利用するアドレス帯、後述のPodネットワークアドオンのインストールで指定するCalicoのPodネットワークアドレスと同じにする。

またkubernetesマニュアルには`明示的に指定しない限り、kubeadmはデフォルトゲートウェイに関連付けられたネットワークインターフェースを使用して、この特定のコントロールプレーンノードのAPIサーバーのadvertise addressを設定する`とあるので、今回構築する構成だとNATのIP`10.0.2.15`が割当てられ、通信ができない。
このためマニュアルの`異なるネットワークインターフェースを使用するには、kubeadm initに--apiserver-advertise-address=<ip-address>引数を指定`に従って設定。
`--node-name`は'kubectl get node`で表示されるノード名、デフォルトではhostnameが割り当てられるためノード名を変更したい場合に利用。

```shell
sudo kubeadm init --pod-network-cidr=172.16.0.0/16 \
    --apiserver-advertise-address=192.168.56.53 \
    --node-name=master
```

ログインユーザにkubectlコマンドの利用を許可する。
これがない場合、root権限をもつユーザしかkubectlコマンドを実行できない。

```shell
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

kubeletは正常に起動、PodはcorednsがPendig状態のため、NodeがNotReadyとなる。
Podネットワークアドオンをインストールするとcorednsが正常になり、Node、Podともに正常起動する。

<details>
  <summary>kubeletの状態確認（kubeadm init後）</summary>

```shell
vagrant@master:~$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: active (running) since Sun 2025-06-08 15:25:25 JST; 2min 17s ago
       Docs: https://kubernetes.io/docs/
   Main PID: 6215 (kubelet)
      Tasks: 11 (limit: 2223)
     Memory: 33.3M
        CPU: 10.324s
     CGroup: /system.slice/kubelet.service
             └─6215 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/l>

 6月 08 15:26:25 master kubelet[6215]: I0608 15:26:25.617572    6215 kuberuntime_gc.go:361] "Error getting ContainerStatus for containerID" containerID="a4c>
 6月 08 15:26:25 master kubelet[6215]: E0608 15:26:25.619963    6215 log.go:32] "ContainerStatus from runtime service failed" err="rpc error: code = NotFoun>
 6月 08 15:26:25 master kubelet[6215]: I0608 15:26:25.620050    6215 kuberuntime_gc.go:361] "Error getting ContainerStatus for containerID" containerID="c46>
 6月 08 15:26:25 master kubelet[6215]: E0608 15:26:25.623226    6215 log.go:32] "ContainerStatus from runtime service failed" err="rpc error: code = NotFoun>
 6月 08 15:26:25 master kubelet[6215]: I0608 15:26:25.623537    6215 kuberuntime_gc.go:361] "Error getting ContainerStatus for containerID" containerID="00b>
 6月 08 15:27:25 master kubelet[6215]: E0608 15:27:25.598317    6215 kubelet_node_status.go:460] "Node not becoming ready in time after startup"
```
</details>

<details>
  <summary>ノード、Podの状態確認（kubeadm init後）</summary>

```shell
### PodのcorednsがPending状態なのが原因で、ノードがNotReadyで正常起動していない。
vagrant@master:~$ kubectl get node -owide
NAME     STATUS     ROLES           AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
master   NotReady   control-plane   7m36s   v1.33.1   192.168.56.53   <none>        Ubuntu 22.04.5 LTS   5.15.0-133-generic   containerd://2.1.1
vagrant@master:~$ 
vagrant@master:~$ kubectl get pod -A -owide
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-674b8bbfcf-c8jv4         0/1     Pending   0          7m35s   <none>          <none>   <none>           <none>
kube-system   coredns-674b8bbfcf-f2s7x         0/1     Pending   0          7m35s   <none>          <none>   <none>           <none>
kube-system   etcd-master                      1/1     Running   0          7m41s   192.168.56.53   master   <none>           <none>
kube-system   kube-apiserver-master            1/1     Running   0          7m39s   192.168.56.53   master   <none>           <none>
kube-system   kube-controller-manager-master   1/1     Running   1          7m39s   192.168.56.53   master   <none>           <none>
kube-system   kube-proxy-67ndr                 1/1     Running   0          7m35s   192.168.56.53   master   <none>           <none>
kube-system   kube-scheduler-master            1/1     Running   1          7m40s   192.168.56.53   master   <none>           <none>

```
</details>

## Podネットワークアドオンのインストール
<font color="red">[Masterノードで実施]</font>
ノード間で通信を可能にするため、Podネットワークアドオンをインストールする。`CNI Pluginのインストール`と書いているサイトもあるが、containerdのインストールで実施した`CNI Plugin`と混乱しないよう`Podネットワークアドオン`の名称にする。

PodネットワークアドオンインストールするまでCluster DNS(CoreDNS)は起動しない。

[Calicoのインストールページ](https://docs.tigera.io/calico/latest/getting-started/kubernetes/self-managed-onprem/onpremises)から資材をダウンロードしてインストール。

### Calicoのインストール
```shell
curl -OL https://raw.githubusercontent.com/projectcalico/calico/v3.30.0/manifests/operator-crds.yaml
kubectl create -f operator-crds.yaml
curl -OL https://raw.githubusercontent.com/projectcalico/calico/v3.30.0/manifests/tigera-operator.yaml
kubectl create -f tigera-operator.yaml
```
### Customリソースのダウンロード、修正
CalicoのPodネットワークのデフォルト設定が`192.168.0.0/16`だがこれはVirtualBoxのHostOnlyネットワークのデフォルト`192.168.56.0/24`と重なるため、CalicoのPodネットワークを`172.16.0.0/16`に修正した上でCustomリソースを適用する。

#### Customリソースのダウンロード
```shell
curl -OL https://raw.githubusercontent.com/projectcalico/calico/v3.30.0/manifests/custom-resources.yaml
```
#### Customリソースの修正
```shell
$ vi custom-resources.yaml

### custom-resources.yamlファイル
apiVersion: operator.tigera.io/v1
kind: Installation
metadata:
  name: default
spec:
  # Configures Calico networking.
  calicoNetwork:
    ipPools:
    - name: default-ipv4-ippool
      blockSize: 26
      #### このアドレスは使用しない
#      cidr: 192.168.0.0/16
      ### 新たにPodネットワークを割り当てる
	  cidr: 172.16.0.0/16
      encapsulation: VXLANCrossSubnet
      natOutgoing: Enabled
      nodeSelector: all()
```
#### 修正したCustomリソースを適用
`kubectl apply`でも良さそうだが、本家に従って`create`

```shell
kubectl create -f custom-resources.yaml
```
全てのPodが正常に起動するまで少し時間がかかる。
<details>
  <summary>Podの起動確認</summary>

```shell
vagrant@master:~/calico$ kubectl get pod -A
NAMESPACE          NAME                                       READY   STATUS    RESTARTS   AGE
calico-apiserver   calico-apiserver-559c99b8d5-cqnc2          1/1     Running   0          3m28s
calico-apiserver   calico-apiserver-559c99b8d5-gw72x          1/1     Running   0          3m28s
calico-system      calico-kube-controllers-5d5749f6d8-zcsl4   1/1     Running   0          3m24s
calico-system      calico-node-kbnnl                          1/1     Running   0          3m24s
calico-system      calico-typha-7bdf95c55d-vm56k              1/1     Running   0          3m25s
calico-system      csi-node-driver-w9744                      2/2     Running   0          3m24s
calico-system      goldmane-7b5b4cd5d9-4kmgp                  1/1     Running   0          3m25s
calico-system      whisker-f7894bbc-jc7xh                     2/2     Running   0          2m37s
kube-system        coredns-674b8bbfcf-bxz5m                   1/1     Running   0          150m
kube-system        coredns-674b8bbfcf-dvnpj                   1/1     Running   0          150m
kube-system        etcd-master                                1/1     Running   1          150m
kube-system        kube-apiserver-master                      1/1     Running   1          150m
kube-system        kube-controller-manager-master             1/1     Running   1          150m
kube-system        kube-proxy-l8gmk                           1/1     Running   0          150m
kube-system        kube-scheduler-master                      1/1     Running   1          150m
tigera-operator    tigera-operator-844669ff44-9q55l           1/1     Running   0          7m50s
```
</details>

Calico管理用のコマンドラインツール`calicoctl`の導入手順もこの後書かれているがスキップ、そのうちやる。

## Workerノードをkubernetesクラスタへ参加させる
<font color="blue">[Workerノードで実施]</font>
MasterノードでPodネットワークアドオンのインストールまで終わり、Masterノードのkubernetesクラスタの正常起動が確認できたら、WorkerノードをKubernetesクラスタに参加させることができる。
WorkerノードがKubernetesクラスタへの参加前に、Workerノードの下記プロセスの正常起動やSwapくらいは確認しておきたい。（どこまでWorkerノードの設定をしたか忘れるので・・）
```shell
# コンテナランタイムのプロセスが正常に起動していること
systemctl status containerd

# kubeletのプロセスも正常に起動していること
systemctl status kubelet

# SwapがOFF（０）になっていること
free -m
```

確認が済んだら、Workerノードをクラスタに参加させる。その際Tokenが必要となるので、Tokenの取得をする。

### kubernetesクラスタ参加用のToken取得

Workerノードをkubernetesクラスタに参加させる場合、Masterノードが発行するTokenを取得する必要がある。TokenはMasterノードで出力され、以下２通りの方法で取得が可能。
- クラスタ初期化のときのログからToken情報を取得する
- コマンドラインからTokenを再発行して取得する

#### クラスタ初期化のときのログからToken情報を取得する場合
クラスタ初期化した際、ログ出力内容にToken情報も出力されている。

<font color="red">[Masterノードで実施]</font>された結果
```shell
....(色々なログ出力された後、最後に出力）

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.56.53:6443 --token xxxxxx.yyyyyyyyyyy \
	--discovery-token-ca-cert-hash sha256:xxxxxxxxxxxxxx 
```

#### コマンドラインからTokenを再発行して取得する場合
クラスタ初期化時のログがない場合、コマンドラインでToken情報の出力ができる。
Masterノードで実施する必要がある。

<font color="red">[Masterノードで実施]</font>
```shell
# Tokenの再発行（Masterノードで実施）
sudo kubeadm token create --print-join-command
```

出力結果
```shell
kubeadm join 192.168.56.53:6443 --token xxxxxx --discovery-token-ca-cert-hash sha256:xxxx
```
ちなみにTokenの有効期限は24時間、有効期限を確認したい場合は以下で確認が可能。

<font color="red">[Masterノードで実施]</font>
```shell
kubeadm token list
```

### Workerノードがkubernetesクラスタに参加する
Masterノードに対しkubernetesクラスタへの参加を依頼する。成功するとkubernetesクラスタにWorkerノードが追加される。`--apiserver-advertise-address`と`--node-name`の説明はMasterノードの初期化の項に記載しているので、そちらを参照。

<font color="blue">[Workerノードで実施]</font>
```shell
sudo kubeadm join 192.168.56.53:6443 --token xxxxxxx \
	--discovery-token-ca-cert-hash sha256:xxxxxxx \
	--apiserver-advertise-address=192.168.56.54 \
	--node-name=worker01
```
`--node-name`としてhostnameと異なる`worker01`を指定するとWarningがでるものの`kubectl get node`ではnode nameとして`worker01`が表示される。

#### kubernetesクラスタにWorkerノードが参加できたか確認する
kubeletコマンドが利用できるMasterノードで確認する。

<font color="red">[Masterノードで実施]</font>
```shell
vagrant@master:~$ kube get node  -o wide
NAME       STATUS   ROLES           AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
master     Ready    control-plane   3h10m   v1.33.1   192.168.56.53   <none>        Ubuntu 22.04.5 LTS   5.15.0-133-generic   containerd://2.1.1
worker01   Ready    <none>          11m     v1.33.1   192.168.56.54   <none>        Ubuntu 22.04.5 LTS   5.15.0-133-generic   containerd://2.1.1
```

ここまでくれば、あとはIPアドレス変えたWorkerノードを作成してkubernetesクラスタに追加していけば良い。

# おわりに
kubernetesのマニュアル、初見だと何やっているか迷子になったので。。
~~構築失敗したときのリセット手順も整理したい。~~
[構築失敗した時のリセット方法](https://qiita.com/nkoseki/items/471dc5a978d119268fe5)を整理しました。