VMware Workstation 16 Proでvctl kindを試してみた

:::note
一応vctl kindが利用できるというので試してみましたが、せっかくVMware Workstation Proを実行しているので複数VMを作成してkubesprayで本物のk8sクラスターを構築する方がテスト環境としては汎用性が高いと思います。

CustomControllerの作成やDeployment, StatefulSetの学習にしてもrook.ioなどでStorageClassが準備できる環境をお勧めします。
:::

# はじめに

VMware Workstation 16 Pro/Playerは、kubernetesクラスターを構築できると宣伝されています。
Fusion 12も同様の機能を持っています。むしろFusion 12の目玉機能としてニュースサイトに掲載されている記事もあるので、Workstaiton版でも動くとはすぐには気がつきませんでした。

VMwareの公式マニュアルは、何をしたら良いか分からない初心者には十分でないと感じたので、メモを残すことにしました。

# 環境

* VMware Workstation 16.1 Pro
* ThinkPad T480 (i7-8550u, 32GB, 2TB NVMe SSD)

# 参考資料

* [vmware公式ガイド - KIND を有効にして vctl コンテナをノードとして使用した Kubernetes クラスタの実行](https://docs.vmware.com/jp/VMware-Workstation-Pro/16.0/com.vmware.ws.using.doc/GUID-1CA929BB-93A9-4F1C-A3A8-7A3A171FAC35.html)
* [VMware Fusion v12 – Kubernetes / Kind integration](https://cormachogan.com/2020/09/17/vmware-fusion-v12-kubernetes-kind-integration/)

# 実際の作業

まず公式ガイドでは、VMWareホストのPowerShell等端末上でvctlを利用して次のコマンドを実行するように記述があります。

* vctl system start
* vctl kind

```powershell:一般ユーザーの権限でコマンドを実行
PS C:\Users\yasu> vctl system start
Preparing storage...
Container storage has been prepared successfully under C:\Users\yasu\.vctl\storage
Preparing container network...
Container network has been prepared successfully using vmnet: vmnet8
Launching container runtime...
Container runtime has been started.
PS C:\Users\yasu> vctl kind
```

ここまで実行すると別ウィンドウが開きますが、ここから先に何をすれば良いのか公式ガイドでは十分ではありません。

この状態で、kubectlコマンドを実行してもサーバーが起動していないことが分かります。

```powershell:別に開いたウィンドウ上でkubectlコマンドを実行
PS C:\Users\yasu> kubectl get node
Unable to connect to the server: dial tcp [::1]:8080: connectex: No connection could be made because the target machine actively refused it.
```

次に参考にしたドキュメントから、クラスターを作成していますが、これは通常のkindの利用方法のようです。kind関連の文書では困ったらlogを参照するようにと書かれていますが、この環境では利用できないようです。

```text:VMware公式ガイドから抜粋
vctl は kind build および kind export logs kind サブコマンドをサポートしていません。
```

ただ、実際にexport logsを実行してみるとログが出力されています。

```powershell
PS C:\Users\yasu> kind export logs
Exported logs for cluster "kind" to:
C:\Users\yasu\AppData\Local\Temp\103590923

PS C:\Users\yasu> cd C:\Users\yasu\AppData\Local\Temp\103590923
PS C:\Users\yasu\AppData\Local\Temp\103590923\kind-control-plane> ls


    ディレクトリ: C:\Users\yasu\AppData\Local\Temp\103590923\kind-control-plane


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2020/11/23     19:55                containers
d-----        2020/11/23     19:55                pods
-a----        2020/11/23     19:55            375 alternatives.log
-a----        2020/11/23     19:55          30624 containerd.log
-a----        2020/11/23     19:55          12420 inspect.json
-a----        2020/11/23     19:55         165190 journal.log
-a----        2020/11/23     19:55         126832 kubelet.log
-a----        2020/11/23     19:55              7 kubernetes-version.txt
-a----        2020/11/23     19:55              0 serial.log
```

これが期待と違う挙動なのか不明ですが、後からログが出力できることに気がついたので、今回はこのログは参考にしませんでした。

kindでクラスターを作成する前に、正常稼動していない場合もあるので、必ず事前にクラスターの有無を確認しています。

```powershell:【確認】クラスターが定義されている場合は削除してから続行
PS C:\Users\yasu> kind get clusters
kind
PS C:\Users\yasu> kind delete cluster
Deleting cluster "kind" ...
```

```kind get clusters```で定義されているクラスターがなくなってから、クラスターを作成します。

```powershell:開いた別ウィンドウからクラスターの作成
PS C:\Users\yasu> kind get clusters
No kind clusters found.

PS C:\Users\yasu> kind create cluster
Creating cluster "kind" ...
 [32m✓[0m Ensuring node image (kindest/node:v1.19.1) 🖼
 [32m✓[0m Preparing nodes 📦
 [32m✓[0m Writing configuration 📜
 [32m✓[0m Starting control-plane 🕹️
 [32m✓[0m Installing CNI 🔌
 [32m✓[0m Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind! 😊
```

ここまで来たらkubectlコマンドを実行します。

```powershell
PS C:\Users\yasu> kubectl cluster-info --context kind-kind
Kubernetes master is running at https://127.0.0.1:62402
KubeDNS is running at https://127.0.0.1:62402/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```

とりあえずkubeletが普通に実行できるようになりました。

```powershell:kubectlの実行例
PS C:\Users\yasu> kubectl get all --all-namespaces
NAMESPACE            NAME                                             READY   STATUS    RESTARTS   AGE
kube-system          pod/coredns-f9fd979d6-8wdwg                      1/1     Running   0          4m11s
kube-system          pod/coredns-f9fd979d6-w8ct6                      1/1     Running   0          4m11s
kube-system          pod/etcd-kind-control-plane                      1/1     Running   0          4m13s
kube-system          pod/kindnet-hmgtk                                1/1     Running   0          4m10s
kube-system          pod/kube-apiserver-kind-control-plane            1/1     Running   0          4m13s
kube-system          pod/kube-controller-manager-kind-control-plane   1/1     Running   0          4m13s
kube-system          pod/kube-proxy-tbcvt                             1/1     Running   0          4m11s
kube-system          pod/kube-scheduler-kind-control-plane            1/1     Running   0          4m13s
local-path-storage   pod/local-path-provisioner-78776bfc44-ll456      1/1     Running   0          4m4s

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  4m28s
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   4m21s

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kindnet      1         1         1       1            1           <none>                   4m11s
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   4m20s

NAMESPACE            NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
kube-system          deployment.apps/coredns                  2/2     2            2           4m21s
local-path-storage   deployment.apps/local-path-provisioner   1/1     1            1           4m4s

NAMESPACE            NAME                                                DESIRED   CURRENT   READY   AGE
kube-system          replicaset.apps/coredns-f9fd979d6                   2         2         2       4m11s
local-path-storage   replicaset.apps/local-path-provisioner-78776bfc44   1         1         1       4m4s
```

k8s公式ガイドのYAMLを利用して挙動を確認します。

* [Exposing an External IP Address to Access an Application in a Cluster](https://kubernetes.io/docs/tutorials/stateless-application/expose-external-ip-address/)

```powershell:チュートリアルの実行
PS C:\Users\yasu> kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml
deployment.apps/hello-world created

PS C:\Users\yasu> kubectl get pod
NAME                           READY   STATUS              RESTARTS   AGE
hello-world-6df5659cb7-9m9kx   0/1     ContainerCreating   0          48s
hello-world-6df5659cb7-cr7k9   0/1     ContainerCreating   0          48s
hello-world-6df5659cb7-pdgxg   0/1     ContainerCreating   0          48s
hello-world-6df5659cb7-r8wsv   0/1     ContainerCreating   0          48s
hello-world-6df5659cb7-wn5hd   0/1     ContainerCreating   0          48s

PS C:\Users\yasu> kubectl expose deployment hello-world --type=LoadBalancer --name=my-service
service/my-service exposed

PS C:\Users\yasu> kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP          95m
my-service   LoadBalancer   10.102.48.208   <pending>     8080:32715/TCP   14s
```

調子よく進んできましたが、LoadBalancerは配置されていないので永久にExternal-IPはpending状態のままとなります。
ポートフォワードによって特定のPodを指定して、127.0.0.1の特定ポートにフォワードさせることが可能です。

```powershell:
PS C:\Users\yasu> kubectl expose deployment hello-world --type=NodePort  --name=my-service2
service/my-service2 exposed

PS C:\Users\yasu> kubectl port-forward svc/my-service2 9090:8080
Forwarding from 127.0.0.1:9090 -> 8080
Forwarding from [::1]:9090 -> 8080
Handling connection for 9090
```

とりあえず動きましたが、本来であればkind本家のガイドを読んで、ingress controllerを配置するべきなのだと思います。
ただ、kindを利用して本格的な環境を構築するのであれば、VMware上に3VMぐらいを起動して、kubesprayでfull-specなk8sクラスターを構築して、MetalLBでLoadBalancerを構築します。

VMware Workstation Proのネットワーク設定は強力で、自分用に閉じた10.1.1.0/24のようなネットワークを作ったりすることは簡単にできます。VMware上のkindはNATネットワークに接続するのがデフォルト設定なので、公式ガイドにあるように設定を変更すれば、同様に別のVMNetに接続できるのだと思いますが、いまのところは個人的には積極的に利用するつもりはありません。

これは得意分野が何にあるのかに依るのかとは思いますが、kindの経験が本番環境でも活かせるかというと、本番との差分を吸収するノウハウばかりが蓄積されるような印象が強いです。この観点ではkindのようなソリューションの利用は個人的にはあまりお勧めしません。

とはいえkubesprayを推しても、これはこれで問題があります。ただ本番環境とテスト環境をできるだけ同じにしたいという小規模環境であれば、現時点ではベストな選択と思っています。

# 遭遇したエラーについて

最初に試した時には、kindでクラスターが実行されているはずなのに、kubectlコマンドではエラーになってしまいました。

```powershell:別ウィンドウ上でkubectlコマンドを実行
PS C:\Users\yasu> kubectl cluster-info --context kind-kind
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Unable to connect to the server: net/http: TLS handshake timeout
```

Docker Desktopを導入しているので、~/.kube/configファイルにはKindの分が加わって2つのcontextが定義されています。

別のWindowsマシン上で、VMware Workstation 16 Playerを利用した限りでは、この状態で問題なく動いています。

最終的には再起動し、VMware Workstation 16 Proは起動せずにPowerShellの端末を開き、vctl system startから再度実行し無事に起動しました。


## 遭遇したエラーについて ver.2

前述のエラーでいろいろ試している段階で、また別のエラーに遭遇してクラスターが作成できなくなりました。

```powershell
PS C:\Users\yasu> kind create cluster
Creating cluster "kind" ...
 [32m✓[0m Ensuring node image (kindest/node:v1.19.1) 🖼
 [31m✗[0m Preparing nodes 📦
[31mERROR[0m: failed to create cluster: docker run error: command "docker run --hostname kind-control-plane --name kind-control-plane --label io.x-k8s.kind.role=control-plane --privileged --security-opt seccomp=unconfined --security-opt apparmor=unconfined --tmpfs /tmp --tmpfs /run --volume /var --volume /lib/modules:/lib/modules:ro --detach --tty --label io.x-k8s.kind.cluster=kind --net kind --restart=on-failure:1 --publish=127.0.0.1:63985:6443/TCP kindest/node:v1.19.1@sha256:98cf5288864662e37115e362b23e4369c8c4a408f99cbc06e58ac30ddc721600" failed with error: exit status 2
[31mCommand Output[0m: panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x30 pc=0x10d59d2]

goroutine 1 [running]:
gitlab.eng.vmware.com/core-build/vctl/pkg/container.StartExistingContainer(0x159a860, 0xc00003e330, 0x0, 0x0, 0xc0002c4370, 0x1, 0x1, 0xc000046101, 0x1, 0xc00033b33d, ...)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/src/vctl/pkg/containerと/start.go:144 +0xd2
gitlab.eng.vmware.com/core-build/vctl/pkg/container.RunContainer(0x159a860, 0xc00003e330, 0xc0000363a0, 0x12, 0xc000046180, 0x5c, 0xc0002c4370, 0x1, 0x1, 0xc0001f2e40, ...)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/src/vctl/pkg/container/run.go:47 +0x375
gitlab.eng.vmware.com/core-build/vctl/cmd.glob..func28(0x1ebc3c0, 0xc00022a1c0, 0x1, 0x1c, 0x0, 0x0)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/src/vctl/cmd/run.go:59 +0x1b5
github.com/spf13/cobra.(*Command).execute(0x1ebc3c0, 0xc00022a000, 0x1c, 0x1c, 0x1ebc3c0, 0xc00022a000)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/pkg/mod/gitlab.eng.vmware.com/core-build/mirrors_github_spf13_cobra@v0.0.0-20200421035935-b81270fac540/command.go:827 +0x467
github.com/spf13/cobra.(*Command).ExecuteC(0x1ebfac0, 0x13adfa2, 0x10, 0x0)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/pkg/mod/gitlab.eng.vmware.com/core-build/mirrors_github_spf13_cobra@v0.0.0-20200421035935-b81270fac540/command.go:915 +0x30b
github.com/spf13/cobra.(*Command).Execute(...)
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/pkg/mod/gitlab.eng.vmware.com/core-build/mirrors_github_spf13_cobra@v0.0.0-20200421035935-b81270fac540/command.go:865
gitlab.eng.vmware.com/core-build/vctl/cmd.Execute()
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/src/vctl/cmd/root.go:55 +0x5d
main.main()
        d:/build/ob/bora-17139912/kubernetesdesktop/build/release/win64_vc140/kubernetesdesktop/build/src/vctl/main.go:13 +0x5e
```

コンテナのイメージを確認します。

```powershell
PS C:\Users\yasu> vctl images
────                                                                                   ─────────────               ──── 
NAME                                                                                   CREATION TIME               SIZE 
────                                                                                   ─────────────               ──── 
nginx:latest                                                                           2020-11-23T11:44:30+09:00   51.1 MiB
kindest/node@sha256:98cf5288864662e37115e362b23e4369c8c4a408f99cbc06e58ac30ddc721600   2020-11-21T23:22:49+09:00   481.5 MiB
```

kindest/nodeを削除してみます。

```powershell
PS C:\Users\yasu> vctl rmi kindest/node@sha256:98cf5288864662e37115e362b23e4369c8c4a408f99cbc06e58ac30ddc721600
────                                                                                   ──────    ──────
NAME                                                                                   RESULT    REASON
────                                                                                   ──────    ──────
kindest/node@sha256:98cf5288864662e37115e362b23e4369c8c4a408f99cbc06e58ac30ddc721600   REMOVED
```

この状態で2つ目のpowershellを終了し、再び vctl system stop; vctl system start; vctl kindを実行します。

```powershell:最初のPowerShellのコマンドラインに戻りコマンドを実行する
PS C:\Users\yasu> vctl system stop
Stop virtual machine kind-control-plane ...
Virtual machine kind-control-plane is stopped
Terminating container runtime...
成功: PID 20444 のプロセスは強制終了されました。
Container runtime has been stopped.
PS C:\Users\yasu> vctl system start
Preparing storage...
Container storage has been prepared successfully under C:\Users\yasu\.vctl\storage
Preparing container network...
Container network has been prepared successfully using vmnet: vmnet8
Launching container runtime...
Container runtime has been started.
PS C:\Users\yasu> vctl kind
```

再び新たに開いたPowerShellのコマンドラインでkindコマンドを実行していきます。

```powershell:別ウィンドウ上で、kindクラスターを作成
PS C:\Users\yasu> kind get clusters
No kind clusters found.
PS C:\Users\yasu> kind create cluster
Creating cluster "kind" ...
 [32m✓[0m Ensuring node image (kindest/node:v1.19.1) 🖼
 [32m✓[0m Preparing nodes 📦
 [32m✓[0m Writing configuration 📜
 [32m✓[0m Starting control-plane 🕹️
 [32m✓[0m Installing CNI 🔌
 [32m✓[0m Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind! 😊
```

この状態からも結局はうまく動きませんでしたが、再起動したところ問題なく稼動しました。

# さいごに

kindはk8s環境にふれる目的ではお手軽かもしれませんが、VMwareのPro版を使えば複数のVMを別のサブネットワークに接続させることができるので、kubesprayなどで本番と同等の環境を構築した方が便利だと思います。