Portal/Notes πŸ“
Cka

Multi-Node Cluster

Versi Bahasa Indonesia. Baca dalam Bahasa Inggris

Cluster Kubernetes multi-node adalah cluster yang terdiri dari setidaknya satu atau lebih node ControlPlane dan satu atau lebih node Worker. Node Control Plane bertanggung jawab untuk mengelola siklus hidup cluster dan menjadwalkan workload. Node Worker menjalankan aplikasi sebenarnya (Pod).

Kubernetes Cluster Components Source: https://kubernetes.io/docs/concepts/architecture/

Workloads Scheduling

Secara default, Kubernetes tidak menjadwalkan Pod di node control plane untuk workload biasa. Ini untuk memastikan control plane tetap didedikasikan untuk mengelola cluster dan tidak dibebani dengan menjalankan workload aplikasi. Ini hanya berlaku jika node memiliki taints ini.

Taints: node-role.kubernetes.io/control-plane:NoSchedule

Mari coba dengan minikube, pertama kita perlu memulai cluster baru dengan 3 node menggunakan perintah di bawah.

➜ minikube start --nodes 3 -p multinode 

πŸ˜„  [multinode] minikube v1.34.0 on Darwin 15.3.1 (arm64)
✨  Automatically selected the docker driver
πŸ“Œ  Using Docker Desktop driver with root privileges
πŸ‘  Starting "multinode" primary control-plane node in "multinode" cluster
🚜  Pulling base image v0.0.45 ...
πŸ”₯  Creating docker container (CPUs=2, Memory=2200MB) ...
🐳  Preparing Kubernetes v1.31.0 on Docker 27.2.0 ...
    β–ͺ Generating certificates and keys ...
    β–ͺ Booting up control plane ...
    β–ͺ Configuring RBAC rules ...
πŸ”—  Configuring CNI (Container Networking Interface) ...
πŸ”Ž  Verifying Kubernetes components...
    β–ͺ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass

πŸ‘  Starting "multinode-m02" worker node in "multinode" cluster
🚜  Pulling base image v0.0.45 ...
πŸ”₯  Creating docker container (CPUs=2, Memory=2200MB) ...
🌐  Found network options:
    β–ͺ NO_PROXY=192.168.49.2
🐳  Preparing Kubernetes v1.31.0 on Docker 27.2.0 ...
    β–ͺ env NO_PROXY=192.168.49.2
πŸ”Ž  Verifying Kubernetes components...

πŸ‘  Starting "multinode-m03" worker node in "multinode" cluster
🚜  Pulling base image v0.0.45 ...
πŸ”₯  Creating docker container (CPUs=2, Memory=2200MB) ...
🌐  Found network options:
    β–ͺ NO_PROXY=192.168.49.2,192.168.49.3
🐳  Preparing Kubernetes v1.31.0 on Docker 27.2.0 ...
    β–ͺ env NO_PROXY=192.168.49.2
    β–ͺ env NO_PROXY=192.168.49.2,192.168.49.3
πŸ”Ž  Verifying Kubernetes components...
πŸ„  Done! kubectl is now configured to use "multinode" cluster and "default" namespace by default

Ini akan memulai cluster Kubernetes dengan 3 node, 1 node control plane dan 2 node worker.

➜ kubectl get nodes
NAME            STATUS   ROLES           AGE   VERSION
multinode       Ready    control-plane   48s   v1.31.0
multinode-m02   Ready    <none>          35s   v1.31.0
multinode-m03   Ready    <none>          25s   v1.31.0

Kemudian mari buat deployment sederhana menggunakan image nginx dengan 3 replika dan apply.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
➜ kubectl apply -f deployment.yaml 
deployment.apps/nginx-deployment created
➜ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE     IP           NODE            NOMINATED NODE   READINESS GATES
nginx-deployment-54b9c68f67-fq928   1/1     Running   0          4m56s   10.244.1.2   multinode-m02   <none>           <none>
nginx-deployment-54b9c68f67-t85zh   1/1     Running   0          4m56s   10.244.2.2   multinode-m03   <none>           <none>
nginx-deployment-54b9c68f67-wvzng   1/1     Running   0          4m56s   10.244.0.3   multinode       <none>           <none>

Seperti yang kita lihat di atas, pod tersebar merata di semua node, termasuk node control plane yang seharusnya tidak terjadi. Ini karena minikube tidak menambahkan taint NoSchedule secara default.

➜ kubectl describe nodes | grep Taint
Taints:             <none>
Taints:             <none>
Taints:             <none>

Jika tidak ada taint NoSchedule di node control-plane, node tersebut bisa menerima Pod. Dengan 3 replika dan 3 node, scheduler mendistribusikan Pod secara merata. Untuk mencegah ini, kita bisa menambahkan taint secara manual menggunakan perintah di bawah.

➜ kubectl taint nodes multinode node-role.kubernetes.io/control-plane:NoSchedule
node/multinode tainted
➜ kubectl describe nodes multinode | grep Taint
Taints:             node-role.kubernetes.io/control-plane:NoSchedule

Kemudian hapus pod yang dijadwalkan di node control plane.

➜ kubectl delete pod nginx-deployment-54b9c68f67-wvzng 
pod "nginx-deployment-54b9c68f67-wvzng" deleted

Cek daftar pod lagi dan kamu akan melihat pod baru tidak dijadwalkan di node control plane.

➜ kubectl get pods -o wide                            
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES
nginx-deployment-54b9c68f67-fq928   1/1     Running   0          22m   10.244.1.2   multinode-m02   <none>           <none>
nginx-deployment-54b9c68f67-hd6bq   1/1     Running   0          14s   10.244.2.3   multinode-m03   <none>           <none>
nginx-deployment-54b9c68f67-t85zh   1/1     Running   0          22m   10.244.2.2   multinode-m03   <none>           <none>

Node Specific Deployment

Pada akhirnya kita ingin men-deploy atau menempatkan Pod ke node tertentu karena beberapa alasan. Misalnya kita ingin men-deploy service database di region EU untuk kepatuhan GDPR, menempatkan service observability di node yang berbeda untuk meningkatkan keandalan, mengisolasi workload CPU intensif di node yang berbeda, dll.

Kubernetes menyediakan mekanisme seperti nodeSelector, nodeAffinity, serta taints dan tolerations untuk mengontrol penempatan pod.

nodeSelector

nodeSelector adalah cara paling sederhana yang direkomendasikan untuk men-deploy/menempatkan Pod ke node tertentu. Kita bisa menambahkan field nodeSelector ke spesifikasi Pod dan menentukan label node yang ingin kita targetkan. Pastikan kamu memberi label pada node dengan benar. Kubernetes hanya akan menjadwalkan Pod ke node yang memiliki setiap label yang kita tentukan.

Pertama, mari tambahkan label ke node multinode-m02 sehingga kita bisa menggunakannya sebagai node selector.

➜ kubectl label nodes multinode-m02 node-type=infra
node/multinode-m02 labeled

Kemudian update file deployment kita untuk menambahkan field nodeSelector di dalam template.spec. Ini akan memberi tahu scheduler Kubernetes untuk menjadwalkan pod ke node yang memiliki label yang sama seperti yang ditentukan di node selector.

nodeSelector:
  node-type: infra

Apply ulang file yaml dan cek daftar pod lagi. Kamu akan melihat bahwa semua pod berjalan di node multinode-m02.

➜ kubectl apply -f deployment.yaml
deployment.apps/nginx-deployment configured
➜ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES
nginx-deployment-5579449f87-8c26w   1/1     Running   0          23s   10.244.1.3   multinode-m02   <none>           <none>
nginx-deployment-5579449f87-cjbbf   1/1     Running   0          16s   10.244.1.5   multinode-m02   <none>           <none>
nginx-deployment-5579449f87-kdk45   1/1     Running   0          19s   10.244.1.4   multinode-m02   <none>           <none>

nodeAffinity

Mirip dengan node selector, nodeAffinity juga memberikan batasan pada node mana Pod dapat dijadwalkan. Perbedaannya adalah node affinity bisa memiliki aturan yang lebih kompleks (required dan preferred).

  • requiredDuringSchedulingIgnoredDuringExecution: Scheduler tidak dapat menjadwalkan Pod kecuali aturannya terpenuhi (Hard Requirements).
  • preferredDuringSchedulingIgnoredDuringExecution: Scheduler mencoba mencari node yang memenuhi aturan. Jika node yang cocok tidak tersedia, scheduler tetap menjadwalkan Pod (Soft Requirements).

Kali ini mari tambahkan label ke node multinode-m03 sehingga kita bisa menggunakannya untuk aturan affinity.

➜ kubectl label nodes multinode-m03 node-type=product
node/multinode-m03 labeled

Tambahkan konfigurasi node affinity berikut di field template.spec. Jangan lupa untuk menghapus node selector yang sebelumnya ditambahkan.

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: node-type
              operator: In
              values:
                - product

Apply ulang file yaml dan cek daftar pod lagi. Kamu akan melihat bahwa semua pod berjalan di node multinode-m03.

➜ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE            NOMINATED NODE   READINESS GATES
nginx-deployment-78b49dbd66-6nkgj   1/1     Running   0          13s   10.244.2.4   multinode-m03   <none>           <none>
nginx-deployment-78b49dbd66-brdvt   1/1     Running   0          5s    10.244.2.6   multinode-m03   <none>           <none>
nginx-deployment-78b49dbd66-j27td   1/1     Running   0          9s    10.244.2.5   multinode-m03   <none>           <none>

Ketika nodeSelector dan nodeAffinity dengan aturan required hadir bersamaan, scheduler Kubernetes akan selalu mencoba memenuhi kedua persyaratan. Jika tidak ada node yang memenuhi kedua persyaratan, pod akan stuck di status Pending. Jika kita cek events, akan ada Warning: FailedScheduling dengan pesan seperti di bawah.

32s         Warning   FailedScheduling    Pod/nginx-deployment-785475985d-vdv8q    0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 node(s) didn't match Pod's node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling.

References


Edit on GitHub

Last updated on

Multi-Node Cluster | Faisal Affan