kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

kindでお手軽Kubernetesマルチクラスタを試す

f:id:kun432:20210901161635p:plain

Kubernetesを触るようになってそこそこ経つんだけど、未だにわからないことのほうが圧倒的に多い。体系的にちゃんと学習する必要があるなぁということで、これまで辞書的にしか使ってこなかったこれを改めて読んでます。

で、色々試すに当たり、ローカル環境でかんたんにマルチクラスタができるものがよいなぁということで、kindを触ってみました。

kind.sigs.k8s.io

詳しく知りたい方はQiitaあたりにたくさん記事があるのでそちらを見てください。あくまでも自分用メモです。

目次

インストール

前提として、Dockerが必要。Macの場合はDocker Desktopをインストールしておいて、Homebrewでかんたんにインストールできる。dockerもHomebrewでいいかもね。

$ brew install kind kubectl
$ kind version
kind v0.11.1 go1.16.4 darwin/amd64

クラスタの作成(シングル)

かんたんにクラスタを作成して起動するだけならkind create clusterでOK。

$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.21.1) 🖼
 ✓ 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

Not sure what to do next? 😅  Check out https://kind.sigs.k8s.io/docs/user/quick-start/

サクッとクラスタが作られます。初回だけnodeのイメージを取得するのに時間が少しかかるみたい。

デフォルトだとクラスタ名はkindになります。

$ kind get clusters
kind

kubeconfig的にはkind-kindになってますね。というか普通にkubectlが使えるようになります。

$ kubectl config get-contexts
CURRENT   NAME        CLUSTER     AUTHINFO    NAMESPACE
*         kind-kind   kind-kind   kind-kind

nodeを見てみる。デフォルトだとcontrol-plane/worker兼用の1台だけっぽい。

$ kubectl get node -o wide
NAME                 STATUS   ROLES                  AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION     CONTAINER-RUNTIME
kind-control-plane   Ready    control-plane,master   8m37s   v1.21.1   172.18.0.2    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2

podはこんな感じ。

$ kubectl get pod --all-namespaces -o wide
NAMESPACE            NAME                                         READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES
kube-system          coredns-558bd4d5db-6w67p                     1/1     Running   0          11h   10.244.0.2   kind-control-plane   <none>           <none>
kube-system          coredns-558bd4d5db-thh9z                     1/1     Running   0          11h   10.244.0.4   kind-control-plane   <none>           <none>
kube-system          etcd-kind-control-plane                      1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
kube-system          kindnet-z78fn                                1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
kube-system          kube-apiserver-kind-control-plane            1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
kube-system          kube-controller-manager-kind-control-plane   1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
kube-system          kube-proxy-k62zn                             1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
kube-system          kube-scheduler-kind-control-plane            1/1     Running   0          11h   172.18.0.2   kind-control-plane   <none>           <none>
local-path-storage   local-path-provisioner-547f784dff-5nhpt      1/1     Running   0          11h   10.244.0.3   kind-control-plane   <none>

試しにnginxのpodをあげてみます。

$ kubectl run nginx --image=nginx
$ kubectl get pod  -o wide
NAME    READY   STATUS    RESTARTS   AGE     IP           NODE                 NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          2m23s   10.244.0.5   kind-control-plane   <none>           <none>
$ kubectl exec -ti nginx -- bash
root@nginx:/# 

普通に使えてますね。

クラスタの削除

削除する場合はkind delete clusterで、サクッと消えます。

$ kind delete cluster
Deleting cluster "kind" ...

クラスタの作成(マルチnode)

kindの最大の特徴はマルチcontrol-plane/マルチworkerが作れること。control-plane3台、worker3台だと、こんな感じのマニフェストになります。ちなみに、nameでクラスタ名の指定ができます。

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: sample
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
- role: worker

クラスタ作成時に--configでこのマニフェストを指定します。

$ kind create cluster --config multi.yaml
Creating cluster "sample" ...
 ✓ Ensuring node image (kindest/node:v1.21.1) 🖼
 ✓ Preparing nodes 📦 📦 📦 📦 📦 📦
 ✓ Configuring the external load balancer ⚖️
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
 ✓ Joining more control-plane nodes 🎮
 ✓ Joining worker nodes 🚜
Set kubectl context to "kind-sample"
You can now use your cluster with:

kubectl cluster-info --context kind-sample

Not sure what to do next? 😅  Check out https://kind.sigs.k8s.io/docs/user/quick-start/

nodeを見てみるとちゃんと複数立ってますね。

$ kubectl get node -o wide
NAME                    STATUS   ROLES                  AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION     CONTAINER-RUNTIME
sample-control-plane    Ready    control-plane,master   8m55s   v1.21.1   172.18.0.7    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2
sample-control-plane2   Ready    control-plane,master   8m12s   v1.21.1   172.18.0.6    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2
sample-control-plane3   Ready    control-plane,master   7m18s   v1.21.1   172.18.0.8    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2
sample-worker           Ready    <none>                 7m      v1.21.1   172.18.0.3    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2
sample-worker2          Ready    <none>                 6m59s   v1.21.1   172.18.0.4    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2
sample-worker3          Ready    <none>                 6m59s   v1.21.1   172.18.0.5    <none>        Ubuntu 21.04   5.10.25-linuxkit   containerd://1.5.2

dockerコマンドで見てみると、haproxyも一つ立っているのがわかる。

$ docker ps
CONTAINER ID   IMAGE                                COMMAND                  CREATED         STATUS         PORTS                       NAMES
a9cd9e1dfecc   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes                               sample-worker
a319976c1294   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes   127.0.0.1:49999->6443/tcp   sample-control-plane
06382bd1fe9d   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes                               sample-worker2
41c70051f965   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes   127.0.0.1:50002->6443/tcp   sample-control-plane3
481c1f7a9f47   kindest/haproxy:v20200708-548e36db   "/docker-entrypoint.…"   9 minutes ago   Up 9 minutes   127.0.0.1:50000->6443/tcp   sample-external-load-balancer
5cea2faf1a7c   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes                               sample-worker3
9d73f13cf90c   kindest/node:v1.21.1                 "/usr/local/bin/entr…"   9 minutes ago   Up 9 minutes   127.0.0.1:50001->6443/tcp   sample-control-plane2

こいつがapiserverへのLoad Balancerになっている。

$ docker exec -ti sample-external-load-balancer sh
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 haproxy -sf 8 -W -db -f /usr/local/etc/haproxy/haproxy.cfg
   32 root      0:05 haproxy -sf 8 -W -db -f /usr/local/etc/haproxy/haproxy.cfg
   36 root      0:00 sh
   44 root      0:00 ps

/ # cat /usr/local/etc/haproxy/haproxy.cfg
(snip)
frontend control-plane
  bind *:6443

  default_backend kube-apiservers

backend kube-apiservers
  option httpchk GET /healthz
  # TODO: we should be verifying (!)

  server sample-control-plane sample-control-plane:6443 check check-ssl verify none resolvers docker resolve-prefer ipv4
  server sample-control-plane2 sample-control-plane2:6443 check check-ssl verify none resolvers docker resolve-prefer ipv4
  server sample-control-plane3 sample-control-plane3:6443 check check-ssl verify none resolvers docker resolve-prefer ipv4
/ #

マルチnodeなので、deploymentを立ててみる。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: nginx
          image: nginx:1.19.4
          ports:
            - containerPort: 80

複数のnodeで起動していることがわかる。

$ kubectl get pod -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP           NODE             NOMINATED NODE   READINESS GATES
my-app-58b49559b8-bwm8z   1/1     Running   0          43s   10.244.4.2   sample-worker3   <none>           <none>
my-app-58b49559b8-jdntf   1/1     Running   0          43s   10.244.3.2   sample-worker    <none>           <none>
my-app-58b49559b8-vwgjc   1/1     Running   0          43s   10.244.5.2   sample-worker2   <none>           <none>

ローカルPCからクラスタ内podへのネットワークアクセス

kindで作成したクラスタはdockerで構成されているので、そのままではpodへネットワークアクセスできない。extraPortmappingsを使う。

まずは1 control-plain/1 workerで試してみる。クラスタ作成用マニフェストをこんな感じで作成する。

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
name: sample2
nodes:
- role: control-plane
- role: worker
  extraPortMappings:
  - containerPort: 30000
    hostPort: 30000
    protocol: TCP

クラスタ作成

$ kind create cluster --config sample2.yaml

podとserviceはこんな感じで。

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  containers:
  - name: nginx
    image: nginx:1.19.2
    ports:
      - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30000

curlでアクセスしてみる

$ curl localhost:30000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
(snip)

dockerでみるとworkerのpodへport-forwardされていることがわかる。

$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                       NAMES
bf8df82909a2   kindest/node:v1.21.1   "/usr/local/bin/entr…"   2 minutes ago   Up 2 minutes   0.0.0.0:30000->30000/tcp    sample2-worker
4756002bd30d   kindest/node:v1.21.1   "/usr/local/bin/entr…"   2 minutes ago   Up 2 minutes   127.0.0.1:53630->6443/tcp   sample2-control-plane

うーん、nodeportの場合、マルチクラスタで同じことをやる場合にはちょっとひねりが必要な感じ。

続きは次回。