コンテナ上で動くノードからなるKubernetesクラスタ Kind を試してみた

kindは、Docker コンテナのノード上で動作するKubeneteクラスタである。Kubernetesのセルフテストのために開発されたものだが、ローカル環境での開発に利用できるかもしれない。仮想マシンを利用するKubernetesクラスタに比べると、軽量で起動も早い。しかし、非常にクセが強いので、開発環境に使えるかは判断が必要だ。

![スクリーンショット 2020-07-29 22.35.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42829/113be8a4-244b-0671-5aa0-8ff099e10d30.png)


## kindのインストール

Macの例であるが、インストールは極めて簡単だ。

~~~console:
$ brew install kind
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 4 taps (homebrew/core, homebrew/cask, minio/stable and argoproj/tap).
<以下省略>
~~~



## とりあえず起動

動作確認も兼ねて、とりあえず、構成ファイルを指定しないで、起動して見る。

~~~console:
$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.18.2) 🖼 
 ✓ Preparing nodes 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ 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! 😊
~~~

起動の確認として、APIサーバーの情報を表示してみる。

~~~console:
$ kubectl cluster-info --context kind-kind
Kubernetes master is running at https://127.0.0.1:49320
KubeDNS is running at https://127.0.0.1:49320/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

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

マスターノードが一つだけ起動している。

~~~console:
$ kubectl get node
NAME                 STATUS   ROLES    AGE    VERSION
kind-control-plane   Ready    master   113s   v1.18.2
~~~

今回のクラスタは削除して、次へすすむ。

~~~console:
$ kind delete cluster
Deleting cluster "kind" ...
~~~

## マルチノードクラスタ

Kindでマルチノードクラスタを起動するには、以下の構成ファイルを作成する。nodes以下にノードの役割を記述するだけだ。

~~~yaml:config-multi-node.yaml
# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
~~~

構成ファイルを指定してクラスタを起動する。

~~~console:
$ kind create cluster --config config-multi-node.yaml 
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.18.2) 🖼
 ✓ Preparing nodes 📦 📦 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
Set kubectl context to "kind-kind"
<以下省略>
~~~

起動の確認としてノードをリストする。

~~~console:
$ kubectl get node
NAME                 STATUS   ROLES    AGE   VERSION
kind-control-plane   Ready    master   74s   v1.18.2
kind-worker          Ready    <none>   39s   v1.18.2
kind-worker2         Ready    <none>   39s   v1.18.2
~~~

起動しているポッドを全数表示する。
CoreDNS、etc、kube-apiserver, kube-controller-manager, kube-porxy, kube-scheduklerが動作しているのがわかる。
それから CNI のネットワークプラグインは、kindnet-* というポッドが使われているのがわかる。

~~~console:
$ kubectl get pod --all-namespaces
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE
kube-system          coredns-66bff467f8-sx4c6                     1/1     Running   0          2m18s
kube-system          coredns-66bff467f8-tbnc4                     1/1     Running   0          2m18s
kube-system          etcd-kind-control-plane                      1/1     Running   0          2m34s
kube-system          kindnet-9hv4d                                1/1     Running   1          2m3s
kube-system          kindnet-plvx9                                1/1     Running   0          2m17s
kube-system          kindnet-sbrjh                                1/1     Running   0          2m3s
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          2m34s
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          2m34s
kube-system          kube-proxy-ds9b9                             1/1     Running   0          2m3s
kube-system          kube-proxy-lmlk8                             1/1     Running   0          2m17s
kube-system          kube-proxy-n8bz8                             1/1     Running   0          2m3s
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          2m34s
local-path-storage   local-path-provisioner-bd4bb6b75-r5t5d       1/1     Running   0          2m18s
~~~

Docker Desktop 上で動作しているので、docker ps で動作中のコンテナをリストして見る。ノードの分だけコンテナが動作しているのが判る。

~~~console:
$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                       NAMES
9d393ea2af42        kindest/node:v1.18.2   "/usr/local/bin/entr…"   3 minutes ago       Up 3 minutes                                    kind-worker2
abe63ea3a5d1        kindest/node:v1.18.2   "/usr/local/bin/entr…"   3 minutes ago       Up 3 minutes                                    kind-worker
8278c8c43a52        kindest/node:v1.18.2   "/usr/local/bin/entr…"   3 minutes ago       Up 3 minutes        127.0.0.1:49513->6443/tcp   kind-control-plane
~~~

ストレージクラスを表示して確認する。プロビジョナーには local-pathが使われることが読み取れる。

~~~console:
$ kubectl get sc
NAME                 PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
standard (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  4m21s
~~~


## マルチマスター

もう一つ、マルチノードのクラスタを構成してみる。

~~~yaml:config-multi-master.yaml 
# a cluster with 3 control-plane nodes and 3 workers
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker
~~~

構成ファイルを指定して、クラスタを起動する。

~~~console:
$ kind create cluster --config config-multi-master.yaml 
~~~

ノードをリストする。 EXTERNAL-IPが付与されない点に注目。

~~~console:
$ kubectl get node -o wide
NAME                  STATUS   ROLES    AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION     CONTAINER-RUNTIME
kind-control-plane    Ready    master   4m43s   v1.18.2   172.21.0.6    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
kind-control-plane2   Ready    master   4m13s   v1.18.2   172.21.0.5    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
kind-control-plane3   Ready    master   3m26s   v1.18.2   172.21.0.7    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
kind-worker           Ready    <none>   3m11s   v1.18.2   172.21.0.4    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
kind-worker2          Ready    <none>   3m11s   v1.18.2   172.21.0.8    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
kind-worker3          Ready    <none>   3m10s   v1.18.2   172.21.0.3    <none>        Ubuntu 19.10   4.19.76-linuxkit   containerd://1.3.3-14-g449e9269
~~~

全てのネームスペースのポッドを表して見る。マスターノード 3台のポッドは、それぞれ起動していることが判る。

~~~console:
maho:kind maho$ kubectl get pod --all-namespaces
NAMESPACE            NAME                                          READY   STATUS    RESTARTS   AGE
kube-system          coredns-66bff467f8-64n5z                      1/1     Running   0          6m4s
kube-system          coredns-66bff467f8-vmcc8                      1/1     Running   0          6m4s
kube-system          etcd-kind-control-plane                       1/1     Running   0          6m15s
kube-system          etcd-kind-control-plane2                      1/1     Running   0          5m37s
kube-system          etcd-kind-control-plane3                      1/1     Running   0          3m46s
kube-system          kindnet-946cg                                 1/1     Running   0          6m3s
kube-system          kindnet-c94gg                                 1/1     Running   0          4m45s
kube-system          kindnet-gdpn8                                 1/1     Running   0          5m47s
kube-system          kindnet-tzh4d                                 1/1     Running   0          4m44s
kube-system          kindnet-x79zx                                 1/1     Running   2          5m
kube-system          kindnet-zchc6                                 1/1     Running   2          4m45s
kube-system          kube-apiserver-kind-control-plane             1/1     Running   0          6m15s
kube-system          kube-apiserver-kind-control-plane2            1/1     Running   0          4m30s
kube-system          kube-apiserver-kind-control-plane3            1/1     Running   1          3m53s
kube-system          kube-controller-manager-kind-control-plane    1/1     Running   1          6m15s
kube-system          kube-controller-manager-kind-control-plane2   1/1     Running   0          4m42s
kube-system          kube-controller-manager-kind-control-plane3   1/1     Running   0          3m57s
kube-system          kube-proxy-7ffq2                              1/1     Running   0          4m45s
kube-system          kube-proxy-8hdbb                              1/1     Running   0          6m3s
kube-system          kube-proxy-fpds6                              1/1     Running   0          5m
kube-system          kube-proxy-kbwss                              1/1     Running   0          4m45s
kube-system          kube-proxy-lvkrc                              1/1     Running   0          4m44s
kube-system          kube-proxy-wd5rm                              1/1     Running   0          5m47s
kube-system          kube-scheduler-kind-control-plane             1/1     Running   1          6m15s
kube-system          kube-scheduler-kind-control-plane2            1/1     Running   0          4m36s
kube-system          kube-scheduler-kind-control-plane3            1/1     Running   0          4m
local-path-storage   local-path-provisioner-bd4bb6b75-wqp5k        1/1     Running   1          6m4s
~~~

コンテナからノードに入って、プロセスの状況を確認してみる。contianerd と kubelet が起動していることが読み取れる。

~~~console:
$ docker exec -it 16a5392ba6c6 bash
root@kind-control-plane:/# ps -ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /sbin/init
  114 ?        S<s    0:00 /lib/systemd/systemd-journald
  125 ?        Ssl    0:07 /usr/local/bin/containerd
  421 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 87e541960ab1c3ba36c7faac8c46016e5968da2092a0e0ce71d2b5d3a435c48e -address /run/containerd/containerd.sock
  422 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id b596cdfc5bfcdd7eedcbe4f89fb6b807a1bcbdd5d6595b1dca7a6f1befb9bb00 -address /run/containerd/containerd.sock
  423 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id b6d6ca329468c2d41c3b7266233e0e0c14a85622759537fbe52579ed1a20ce2b -address /run/containerd/containerd.sock
  427 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 73b3ecd02605d64730e6d32972d543f1f1eb2e95538a758ea0f7b3c34d954986 -address /run/containerd/containerd.sock
  503 ?        Ss     0:00 /pause
  504 ?        Ss     0:00 /pause
  505 ?        Ss     0:00 /pause
  523 ?        Ss     0:00 /pause
  645 ?        Ssl    0:37 kube-apiserver --advertise-address=172.21.0.6 --allow-privileged=true --authorization-mode=Node,RBAC --client-ca-file=/etc/kubernetes/pki/ca.crt --enable-admission-plugins=NodeRestriction --enable-bootstrap-token
  725 ?        Ssl    0:29 etcd --advertise-client-urls=https://172.21.0.6:2379 --cert-file=/etc/kubernetes/pki/etcd/server.crt --client-cert-auth=true --data-dir=/var/lib/etcd --initial-advertise-peer-urls=https://172.21.0.6:2380 --initia
  795 ?        Ssl    0:15 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=remote --container-runtime-endpoi
 1018 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id d8f2ca0244e580d253bbb0018d5f0bf3ef3fd402fb735958e747064a9136f7fe -address /run/containerd/containerd.sock
 1027 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 6bc58fe6b05a92eeb523ac130ce031a27080798dc4ea485c7dd4d58beaf11dfe -address /run/containerd/containerd.sock
 1063 ?        Ss     0:00 /pause
 1070 ?        Ss     0:00 /pause
 1126 ?        Ssl    0:00 /bin/kindnetd
 1136 ?        Ssl    0:00 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=kind-control-plane
 1345 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 5c9559c4d48d44ed92e10f3897b95bed1f3b93f3b213c47df2b6022c6c4d0412 -address /run/containerd/containerd.sock
 1351 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 52b9e5bb4ecf79408851683a4415313629061feaaa69337ac35658f9b9dfa086 -address /run/containerd/containerd.sock
 1378 ?        Sl     0:00 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id e53dc2378582ba57ecc88c6ad87c015c7087c7d2297242c855aa7f4bde357f05 -address /run/containerd/containerd.sock
 1418 ?        Ss     0:00 /pause
 1420 ?        Ss     0:00 /pause
 1432 ?        Ss     0:00 /pause
 1514 ?        Ssl    0:01 /coredns -conf /etc/coredns/Corefile
 1526 ?        Ssl    0:01 /coredns -conf /etc/coredns/Corefile
 1790 ?        Ssl    0:03 kube-scheduler --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-el
 1797 ?        Ssl    0:00 local-path-provisioner --debug start --helper-image k8s.gcr.io/debian-base:v2.0.0 --config /etc/config/config.json
 1862 ?        Ssl    0:02 kube-controller-manager --allocate-node-cidrs=true --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf --bind-address=127.0.0.1 -
 2877 pts/1    Ss     0:00 bash
 2884 pts/1    R+     0:00 ps -ax
~~~


## アプリケーションの動作確認

簡単なアプリケーションとして、NGINXを起動する。

~~~console:
$ kubectl apply -f https://raw.githubusercontent.com/takara9/codes_for_lessons/master/step09/deploy.yml
deployment.apps/web-deploy created

$ kubectl apply -f https://raw.githubusercontent.com/takara9/codes_for_lessons/master/step09/svc-lb.yml
service/web-service-lb created
~~~

アプリをデプロイして起動した結果である。 LoadBalancer は連携先が無いので、pendingとなる。そこで NodePort にアクセスを試みたが、残念ながらアクセスできなかった。設定が足りないうようだ。

~~~console:
$ kubectl get pod
NAME                          READY   STATUS    RESTARTS   AGE
mypod                         1/1     Running   0          39m
web-deploy-756987f8f4-j6fpz   1/1     Running   0          56m
web-deploy-756987f8f4-jnt4s   1/1     Running   0          56m
web-deploy-756987f8f4-wh9m5   1/1     Running   0          56m

$ kubectl get svc
NAME             TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP      10.96.0.1      <none>        443/TCP        68m
web-service-lb   LoadBalancer   10.104.142.6   <pending>     80:30504/TCP   56m

$ kubectl get deploy
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
web-deploy   3/3     3            3           57m
~~~

アクセステスト用のポッドを起動して、curlでNGINXをアクセスと、いつもの結果が返ってきた。

~~~console:
$ kubectl run -it mypod --image=maho/my-ubuntu:0.1 -- bash
If you don't see a command prompt, try pressing enter.

root@mypod:/# curl http://web-service-lb/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
~~~

## まとめ

Kubernetesのノードを丸ごとコンテナで動かして、クラスタを構成する発想は素晴らしい。ノードはサーバーという固定概念に縛られてはいけないことを思い知った。


##　参考資料
* Kind https://kind.sigs.k8s.io/
* GitHun Kind https://github.com/kubernetes-sigs/kind