Hyper-V & minikubeでmulti node k8sを構築する

やったことアウトプットしないと、後輩に色々言えないと思ったのでメモ書き程度に…

Kubernetesで色々やってみたいので、手元のWindows 10 ProにHyper-Vをインストールして、その中にk8sを構築する。
ただ、普段の開発マシンはmacOSなので、操作はmacOSからしたい。
※手元のWin10マシンがRyzen 7 3700X 64GBでVM動かすのにちょうどよかったため。

## minikube (Windows 10)

minikube multi nodeで構築する。
https://minikube.sigs.k8s.io/docs/tutorials/multi_node/
コマンドのインストールはめんどくさいので、[Chocolatey](https://chocolatey.org/)でやる。
Kubernetesのバージョンは[EKSと合わせるためにv1.21.5](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)にしています。

Hyper-Vの有効化は割愛

```powershell:Powershell
# 管理者権限のPowershellで作業

# Chocolateyでサクッとminikubeをインストール
> choco install -y minikube

# minikubeでk8s clusterを起動
# --hyperv-virtual-switch='Primary Virtual Switch'
#   -> 事前にHyper-Vのコンパネで仮想スイッチを作成しています
> minikube start `
    --driver=hyperv `
    --hyperv-virtual-switch='Primary Virtual Switch' `
    --nodes=3 `
    --cni=flannel `
    --container-runtime=containerd `
    --cpus=4 `
    --memory=8G `
    --addons=registry,metallb,ingress `
    --embed-certs=true `
    --kubernetes-version=v1.21.5

Microsoft Windows 10 Pro 10.0.19044 Build 19044 上の minikube v1.25.2                                                                            
💿  VM ブートイメージをダウンロードしています...
    > minikube-v1.25.2.iso.sha256: 65 B / 65 B [-------------] 100.00% ? p/s 0s
    > minikube-v1.25.2.iso: 237.06 MiB / 237.06 MiB  100.00% 45.17 MiB p/s 5.5s
👍  minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
💾  Kubernetes v1.21.5 のダウンロードの準備をしています
    > preloaded-images-k8s-v17-v1...: 545.79 MiB / 545.79 MiB  100.00% 48.20 Mi
🔥  hyperv VM (CPUs=4, Memory=8192MB, Disk=20000MB) を作成しています...
📦  containerd 1.4.12 で Kubernetes v1.21.5 を準備しています...
    ▪ kubelet.housekeeping-interval=5m
    ▪ 証明書と鍵を作成しています...
    ▪ コントロールプレーンを起動しています...
    ▪ RBAC のルールを設定中です...
🔗  Flannel (コンテナーネットワークインターフェース) を設定中です...
🔎  Kubernetes コンポーネントを検証しています...
    ▪ registry:2.7.1 イメージを使用しています
    ▪ gcr.io/google_containers/kube-registry-proxy:0.4 イメージを使用しています
    ▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
    ▪ k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1 イメージを使用しています
    ▪ k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1 イメージを使用しています
    ▪ k8s.gcr.io/ingress-nginx/controller:v1.1.1 イメージを使用しています
    ▪ metallb/controller:v0.9.6 イメージを使用しています
    ▪ metallb/speaker:v0.9.6 イメージを使用しています
🔎  registry アドオンを検証しています...
🔎  ingress アドオンを検証しています...
🌟  有効なアドオン: storage-provisioner, metallb, default-storageclass, registry, ingress

👍  minikube クラスター中の minikube-m02 ワーカーノードを起動しています
🔥  hyperv VM (CPUs=4, Memory=8192MB, Disk=20000MB) を作成しています...
🌐  ネットワーク オプションが見つかりました
    ▪ NO_PROXY=172.16.11.179
    ▪ no_proxy=172.16.11.179
📦  containerd 1.4.12 で Kubernetes v1.21.5 を準備しています...
    ▪ env NO_PROXY=172.16.11.179
🔎  Kubernetes コンポーネントを検証しています...

👍  minikube クラスター中の minikube-m03 ワーカーノードを起動しています
🔥  hyperv VM (CPUs=4, Memory=8192MB, Disk=20000MB) を作成しています...
🌐  ネットワーク オプションが見つかりました
    ▪ NO_PROXY=172.16.11.179,172.16.11.180
    ▪ no_proxy=172.16.11.179,172.16.11.180
📦  containerd 1.4.12 で Kubernetes v1.21.5 を準備しています...
    ▪ env NO_PROXY=172.16.11.179
    ▪ env NO_PROXY=172.16.11.179,172.16.11.180
🔎  Kubernetes コンポーネントを検証しています...

❗  C:\ProgramData\chocolatey\bin\kubectl.exe のバージョンは 1.23.5 で、Kubernetes 1.21.5 と互換性がないかもしれません。
    ▪ kubectl v1.21.5 が必要ですか？ 'minikube kubectl -- get pods -A' を試してみてください
🏄  完了しました！ kubectl が「"minikube"」クラスタと「"default"」ネームスペースを使用するよう構成されました
```

## kubectl (macOS)

kubectlをインストール  
バージョンを揃えるために、[asdf](https://github.com/asdf-vm/asdf)を使用しています。  

```bash
$ brew install asdf
```

```bash:~/.bash_profile
# 追記
export BREW_PREFIX=`brew --prefix`
. "${BREW_PREFIX}/opt/asdf/libexec/asdf.sh"
```

```bash
# ~/.bash_profileを再読み込み
$ exec $SHELL -l

# asdfでkubectlを使えるようにする
$ asdf plugin-add kubectl

# kubectl v1.21.5をインストール
$ asdf install kubectl 1.21.5

# システムでkubectl v1.21.5を利用するように設定
$ asdf global kubectl 1.21.5

# バージョン確認
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", GitCommit:"aea7bbadd2fc0cd689de94a54e5b7b758869d691", GitTreeState:"clean", BuildDate:"2021-09-15T21:10:45Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"darwin/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?
```

## KubeConfigをどうにかして持ってくる

Windows 10の `"C:\Users\<ユーザ名>\.kube\config"` をどうにかこうにかして、macOSの `~/.kube/config` に持ってくる。  
私はRDPでコピペしました。  
人によっては、中のIPをいい感じに直す必要性があると思います。

## 疎通確認 (macOS)

```bash
# Server側のバージョンが取れていればOK
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", GitCommit:"aea7bbadd2fc0cd689de94a54e5b7b758869d691", GitTreeState:"clean", BuildDate:"2021-09-15T21:10:45Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"21", GitVersion:"v1.21.5", GitCommit:"aea7bbadd2fc0cd689de94a54e5b7b758869d691", GitTreeState:"clean", BuildDate:"2021-09-15T21:04:16Z", GoVersion:"go1.16.8", Compiler:"gc", Platform:"linux/amd64"}

$ kubectl get all -n kube-system
NAME                                   READY   STATUS    RESTARTS   AGE
pod/coredns-558bd4d5db-527vk           1/1     Running   0          19m
pod/etcd-minikube                      1/1     Running   0          19m
pod/kube-apiserver-minikube            1/1     Running   0          19m
pod/kube-controller-manager-minikube   1/1     Running   0          19m
pod/kube-flannel-ds-amd64-vhm4v        1/1     Running   0          17m
pod/kube-flannel-ds-amd64-vrd7q        1/1     Running   0          16m
pod/kube-flannel-ds-amd64-xdqf5        1/1     Running   0          19m
pod/kube-proxy-2r45z                   1/1     Running   0          19m
pod/kube-proxy-nl4rf                   1/1     Running   0          17m
pod/kube-proxy-zj2ld                   1/1     Running   0          16m
pod/kube-scheduler-minikube            1/1     Running   0          19m
pod/registry-5h7hb                     1/1     Running   0          19m
pod/registry-proxy-4gxpz               1/1     Running   0          19m
pod/registry-proxy-68gms               1/1     Running   0          16m
pod/registry-proxy-6r485               1/1     Running   0          17m
pod/storage-provisioner                1/1     Running   0          19m

NAME                             DESIRED   CURRENT   READY   AGE
replicationcontroller/registry   1         1         1       19m

NAME               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.96.0.10     <none>        53/UDP,53/TCP,9153/TCP   19m
service/registry   ClusterIP   10.98.234.97   <none>        80/TCP,443/TCP           19m

NAME                                     DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/kube-flannel-ds-amd64     3         3         3       3            3           <none>                   19m
daemonset.apps/kube-flannel-ds-arm       0         0         0       0            0           <none>                   19m
daemonset.apps/kube-flannel-ds-arm64     0         0         0       0            0           <none>                   19m
daemonset.apps/kube-flannel-ds-ppc64le   0         0         0       0            0           <none>                   19m
daemonset.apps/kube-flannel-ds-s390x     0         0         0       0            0           <none>                   19m
daemonset.apps/kube-proxy                3         3         3       3            3           kubernetes.io/os=linux   19m
daemonset.apps/registry-proxy            3         3         3       3            3           <none>                   19m

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   1/1     1            1           19m

NAME                                 DESIRED   CURRENT   READY   AGE
replicaset.apps/coredns-558bd4d5db   1         1         1       19m
```

何故か、corednsの調子が悪かったので一度作り直す

```bash
$ kubectl -n kube-system rollout restart deployment coredns
deployment.apps/coredns restarted

# 先ほどと名前が変わっていればOK
$ kubectl -n kube-system get po
NAME                               READY   STATUS    RESTARTS   AGE
coredns-69b98fc48c-rfs5h           1/1     Running   0          29s
....
```

## MetalLB

https://metallb.universe.tf/

今のままだと、MetalLBが動作しないので、LoadBalancerに割り当てるIPアドレスの範囲を設定してあげる。
この際に、企業内のネットワークなどで適当に割り当てると、企業内ネットワークに深刻なダメージを受けることがあるので注意。
基本的には、自宅のLANなどでVPNを切断した上で設定しよう。

我が家は `172.16.10.0/23` のLANを構築しており、DHCPで配布されるアドレスは `172.16.11.100-220` の範囲に限定しているため、MetalLBには `172.16.10.100-200` の範囲を割り当てる。

```powershell:Powershell
> minikube addons configure metallb
-- Enter Load Balancer Start IP: 172.16.10.100
-- Enter Load Balancer End IP: 172.16.10.200
    ▪ metallb/speaker:v0.9.6 イメージを使用しています
    ▪ metallb/controller:v0.9.6 イメージを使用しています
✅  metallb は正常に設定されました
```

## 予定

ストレージ周りが不便なので、[Rook CEPH](https://rook.io/)を入れたい
(まぁ、すでに入れてたけど記事を書くために一度全部吹き飛ばした)