こんにちは。GMO NIKKO の Y.S です。
先日、kind という ローカル環境でマルチノードな Kubernetes クラスタを動かすことができるツールがあることを知り、試してみたので紹介します。kind という名前は docker in docker の dind 風に、Kubernetes-in–Docker で kind とのことです。
Docker 上のコンテナを Kubernetes のワーカーノードとして利用することで、Kubernetes クラスタを構築し、ローカル環境で Minikube のようなシングルノードではできないマルチノードなクラスタを動作させることができます。
また、高速・軽量・クラスプラットフォームという特徴があり、ローカル環境だでけなく、CI のテスト環境にもよく利用されているようです。例えば、Kubernetes 本体のテストでも使用されています。
Kubernetes のバージョンを変更してクラスタを作ることもできるので、新しい Kubernetes バージョンでの動作確認、古い Kubernetes バージョンでの後方互換の確認、といったケースでも使えます。
今回は Docker Desktop for Mac の環境に kind をインストールしていきます。(Docker Desktop の Kubernetes は無効にしておきます)
kind の QuickStart に従って Go の最新版(1.13 以上)をインストールします。今回は Mac 用の公式インストーラを使いました。
インストールされた go
と GOPATH 配下にインストールされることになる kind
を実行できるよう、PATH 変数に追加します。
1 2 3 |
export PATH=$PATH:/usr/local/go/bin export PATH=$PATH:$(go env GOPATH)/bin |
kind をインストールします。
1 2 3 4 5 6 7 8 9 10 11 |
$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.5.1 go: finding sigs.k8s.io v0.5.1 go: finding sigs.k8s.io/kind v0.5.1 go: downloading sigs.k8s.io/kind v0.5.1 : : $ type kind kind is hashed (/Users/usr******/go/bin/kind) $ kind version v0.5.1 |
kind
コマンドを使ってクラスタを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ kind create cluster Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.15.3) ✓ Preparing nodes ✓ Creating kubeadm config ✓ Starting control-plane ️ ✓ Installing CNI ✓ Installing StorageClass Cluster creation complete. You can now use the cluster with: export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" kubectl cluster-info |
最初の node image の取得にしばらく時間がかかりましたが、それでも数分で立ちがりました。kubectl の環境変数をセットして、いくつかコマンドを試してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
$ export KUBECONFIG="$(kind get kubeconfig-path --name="kind")" $ kubectl get nodes NAME STATUS ROLES AGE VERSION kind-control-plane Ready master 4h1m v1.15.3 $ kubectl get pods No resources found. $ kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-5c98db65d4-b4ctx 1/1 Running 0 4h2m coredns-5c98db65d4-fcsr7 1/1 Running 0 4h2m etcd-kind-control-plane 1/1 Running 0 4h2m kindnet-6bnbv 1/1 Running 0 4h2m kube-apiserver-kind-control-plane 1/1 Running 0 4h1m kube-controller-manager-kind-control-plane 1/1 Running 0 4h1m kube-proxy-69gbs 1/1 Running 0 4h2m kube-scheduler-kind-control-plane 1/1 Running 0 4h1m $ kubectl top nodes Error from server (NotFound): the server could not find the requested resource (get services http:heapster:) |
デフォルトではクラスタ名 kind のシングルノードクラスタが作られます。
また、Kubernetes のバージョンは執筆時点で最新安定版の 1.15.3 のバージョンとなっています。 heapster の pod は含まれてなくてメトリクスは取れないようです。docker stats
コマンドで見ると下のようなリソース使用状況でした。
1 2 3 4 |
$ docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 990109756cca kind-control-plane 25.49% 1.478GiB / 9.744GiB 15.17% 53.2MB / 1.41MB 190kB / 58.1MB 346 |
次にマルチノードのクラスタをクラスタ名 kind-2 で作成してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
$ cat <<EOD > config.yaml kind: Cluster apiVersion: kind.sigs.k8s.io/v1alpha3 nodes: - role: control-plane - role: worker - role: worker EOD $ kind create cluster --name kind-2 --config config.yaml Creating cluster "kind-2" ... ✓ Ensuring node image (kindest/node:v1.15.3) ✓ Preparing nodes ✓ Creating kubeadm config ✓ Starting control-plane ️ ✓ Installing CNI ✓ Installing StorageClass ✓ Joining worker nodes Cluster creation complete. You can now use the cluster with: export KUBECONFIG="$(kind get kubeconfig-path --name="kind-2")" kubectl cluster-info $ docker stats --no-stream CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 5fbdb34417c3 kind-2-worker 3.10% 220MiB / 9.744GiB 2.20% 216kB / 72.2kB 0B / 90.1kB 100 4ed59fae0bda kind-2-worker2 2.92% 223.5MiB / 9.744GiB 2.24% 219kB / 68.1kB 0B / 53.2kB 102 bd585648f909 kind-2-control-plane 25.62% 1.195GiB / 9.744GiB 12.26% 138kB / 436kB 0B / 57.8MB 332 990109756cca kind-control-plane 21.25% 1.483GiB / 9.744GiB 15.22% 53.2MB / 1.41MB 190kB / 58.1MB 346 $ export KUBECONFIG="$(kind get kubeconfig-path --name="kind-2")" $ kubectl get nodes NAME STATUS ROLES AGE VERSION kind-2-control-plane Ready master 2m44s v1.15.3 kind-2-worker Ready 2m v1.15.3 kind-2-worker2 Ready 2m v1.15.3 |
ノードの数だけそれに対応するコンテナが作られています。
nginx をデプロイしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$ cat <<EOD > deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: "nginx:1.16.1" EOD $ kubectl create -f deployment.yaml $ kubectl create service nodeport nginx --tcp=8080:80 $ kubectl port-forward --address localhost svc/nginx 8080:8080 |
curl で nginx のデフォルトページが出力されることを確認します。
1 2 3 4 5 |
$ curl http://localhost:8080 : : |
シングルノードのクラスタではできなかった、pod の配置を制御する podAffinity と podAntiAffinity の設定を変えて実際の pod の配置がどうなるか試して見ます。
まず、デプロイ済みの nginx の pod が配置されているノードを確認します。
1 2 3 4 5 6 |
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-84f65d7866-8dzdv 1/1 Running 0 7s 10.244.1.6 kind-2-worker nginx-84f65d7866-8sc8b 1/1 Running 0 17s 10.244.2.3 kind-2-worker2 |
配置されたノードを見てみると、2つのワーカーノード ( kind-2-worker, kind-2-worker2 ) にぞれぞれに配置されているので、 同じノードに配置されるように podAffinity を設定してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
$ cat <<EOD > deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: "nginx:1.16.1" affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: "kubernetes.io/hostname" EOD $ kubectl apply -f deployment.yaml $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-576c9f474b-9mkpv 1/1 Running 0 12s 10.244.2.5 kind-2-worker2 nginx-576c9f474b-dcbqp 1/1 Running 0 10s 10.244.2.6 kind-2-worker2 |
同じノードに配置されました。次に同じノードに配置されないよう podAntiAffinity を設定してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$ cat <<EOD > deployment.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx spec: replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: "nginx:1.16.1" affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - nginx topologyKey: "kubernetes.io/hostname" EOD $ kubectl apply -f deployment.yaml $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-576c9f474b-9mkpv 1/1 Running 0 2m 10.244.2.5 kind-2-worker2 nginx-5cdd6487d-5c2xz 0/1 Pending 0 4s nginx-5cdd6487d-qzhl9 1/1 Running 0 5s 10.244.1.9 kind-2-worker |
pod が違うノードに配置されていることが確認できました。一通り動作確認できたので、クラスタ削除してクリーンアップします。
1 2 3 4 |
$ kind delete cluster --name kind $ kind delete cluster --name kind-2 $ unset KUBECONFIG |
クラスタの削除は作成時よりも早く処理が終わりました。
今回は Docker Desktop for Mac の環境で、マルチノードなKubernetes クラスタを作り、podAffinity と podAntiAffinity の設定を試してみました。現状では、デフォルトでメトリクスのデータが取れないなど一部機能に制限はありますが、実際に使われる マルチノードなKubernetes クラスタに近い環境でワークロードのテストができ、クラスタの作成・削除も手軽にできるので、非常に便利に感じました。興味がある人は是非お試しください。