Kindでマルチノードクラスタを作る方法

akihiros · June 2, 2025

もういつ用意したか覚えてませんが、簡易的なKubernetes環境としてWSL+kindを使えるようにしていました。昔はminikubeを使ってましたが軽いという噂を聞いてkindに切り替えた記憶があります。kindのデフォルト設定はシングルノードなので、ノードの理解がイマイチしにくいという欠点がありました。そこで今回はシングルノードのkindクラスタを一度削除し、マルチノード環境を作り直してみます。

マルチノードクラスタの構築

まずはシングルクラスタを削除します。

# 既存クラスタを削除
$ kind delete cluster

# マルチクラスタ用のyamlを作成して作成
$ vim k8s/kind-limited-config.yaml
# ------------------------------
# k8s/kind-limited-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
# ------------------------------
# マルチノードクラスタを作成
$ kind create cluster --config k8s/kind-limited-config.yaml 

# 確認
$ kubectl get nodes
NAME                 STATUS   ROLES           AGE     VERSION
kind-control-plane   Ready    control-plane   3m20s   v1.32.2
kind-worker          Ready    <none>          3m8s    v1.32.2
kind-worker2         Ready    <none>          3m8s    v1.32.2

これでマルチノードクラスタを作成できたので、Nginx Podで通信試験してみます。まずはDeploymentで3つのPodを作成し、各ノードに割り当てられたことを確認します。

$ vim k8s/deployment-nginx.yaml
# ------------------------------
# k8s/deployment-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "200m"
            memory: "256Mi"
# ------------------------------
$ kubectl apply -f k8s/deployment-nginx.yaml
NAME                                    READY   STATUS              RESTARTS   AGE
pod/nginx-deployment-5656fbf665-gf2fb   0/1     ContainerCreating   0          5s
pod/nginx-deployment-5656fbf665-r2v7m   0/1     ContainerCreating   0          5s
pod/nginx-deployment-5656fbf665-xzl7x   0/1     ContainerCreating   0          5s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6m1s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   0/3     3            0           5s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-5656fbf665   3         3         0       5s

各Podがどのノードに割り当てられたか確認します。想定通りworkerとworker2に分散されました。

$ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-5656fbf665-gf2fb   1/1     Running   0          35m   10.244.1.2   kind-worker    <none>           <none>
nginx-deployment-5656fbf665-r2v7m   1/1     Running   0          35m   10.244.2.3   kind-worker2   <none>           <none>
nginx-deployment-5656fbf665-xzl7x   1/1     Running   0          35m   10.244.2.2   kind-worker2   <none>           <none>

次にServiceを作成します。

$ vim k8s/service-nginx.yaml
# ------------------------------
# k8s/service-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  selector:
    app: nginx
  ports:
    - port: 80        # Service自体のポート
      targetPort: 80  # Pod内nginxのポート  
      nodePort: 30080 # Node上で公開されるポート
  type: NodePort
# ------------------------------

yamlからServiceを作成。

$ kubectl apply -f k8s/service-nginx.yaml

$ kubectl get services
NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes       ClusterIP   10.96.0.1     <none>        443/TCP        43m
nginx-nodeport   NodePort    10.96.30.16   <none>        80:30080/TCP   9s

これで外部から30080ポートでNginxにアクセスできるはず。

$ curl http://localhost:30080
curl: (7) Failed to connect to localhost port 30080 after 0 ms: Couldn't connect to server

出来ませんでした。

KindでNodePortを使うにはポートマッピング設定を追加する工夫が必要なためですね。公式ではkind – ConfigurationextraPortMappingsを使ってDockerで永続的にポートマッピングをする例が提示されていました。今回は簡易試験なのでkubectlで一時的に解消してみようと思います。

まずはポート探し。8080が使われていないことを確認します。

$ netstat -tlnp | grep 8080
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)

# nginx-nodeportの80番ポートを8080にフォーワード
$ kubectl port-forward service/nginx-nodeport 8080:80 &

# 8080がLISTENになったことを確認
$ netstat -tlnp | grep 8080
tcp        0      0 127.0.0.1:8080          0.0.0.0:*               LISTEN      61671/kubectl       
tcp6       0      0 ::1:8080                :::*                    LISTEN      61671/kubectl

改めて通信試験してみましょう。

# 改めて接続試験
$ curl http://localhost:8080
Handling connection for 8080
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>

無事成功しましたね。最後にjobをkillして検証完了です。

# ポートフォワード解除対応
$ jobs
[1]+  Running                 kubectl port-forward service/nginx-nodeport 8080:80 &

# フォーワードを解除
$ kill %1

補足: リソース制限の失敗

一般的な環境では複数のVMを用意し、それらを各ノードとするため利用可能なリソースはVMのリソースに依存します。 しかし、kindクラスタはDockerコンテナ上に構築されるため、コンテナが稼働するホストのリソースに依存します。

# 現在の設定値
$ docker stats --no-stream --format "table {.Name}\t{.CPUPerc}\t{.MemUsage}\t{.MemPerc}"
NAME                 CPU %     MEM USAGE / LIMIT     MEM %
kind-control-plane   11.39%    604.5MiB / 7.719GiB   7.65%
kind-worker2         0.78%     152.1MiB / 7.719GiB   1.92%
kind-worker          0.59%     148.1MiB / 7.719GiB   1.87%

とはいえ、無尽蔵にリソースを食われるわけにはいかないので、kindクラスタのリソース制限を試みました。

# コンテナにリソース制限
$ docker update --cpus="2.0" --memory="3g" --memory-swap="3g" kind-control-plane
$ docker update --cpus="3.0" --memory="2g" --memory-swap="2g" kind-worker
$ docker update --cpus="3.0" --memory="2g" --memory-swap="2g" kind-worker2

# Dockerコンテナの設定値が変更されたことを確認
$ docker stats --no-stream --format "table {.Name}\t{.CPUPerc}\t{.MemUsage}\t{.MemPerc}"
NAME                 CPU %     MEM USAGE / LIMIT   MEM %
kind-control-plane   7.32%     607.5MiB / 3GiB     19.78%
kind-worker2         0.72%     152.6MiB / 2GiB     7.45%
kind-worker          1.26%     150.8MiB / 2GiB     7.37%

# コンテナ再起動
$ docker restart kind-control-plane kind-worker kind-worker2

# クラスタのリソース制限を確認
$ kubectl describe node kind-control-plane | grep -A 5 "Capacity"
Capacity:
  cpu:                8
  ephemeral-storage:  1055762868Ki
  hugepages-1Gi:      0
  hugepages-2Mi:      0
  memory:             8093720Ki

結果、失敗。コンテナは制限できていますがkindクラスタ側ではホストのリソースをそのまま参照してしまっているようです。

Twitter, Facebook