Di episode ini kita akan coba bahas Kubernetes Node Selector, mekanisme simple untuk kontrol Pod placement di specific node. Kita akan mempelajari cara menggunakan label dan node selector untuk schedule Pod di node dengan karakteristik spesifik.

Catatan
Untuk kalian yang ingin membaca episode sebelumnya, bisa click thumbnail episode 15 di bawah ini
Di episode sebelumnya kita sudah belajar tentang CronJob, yang membuat Job berdasarkan time-based schedule. Selanjutnya di episode 16 kali ini, kita akan coba bahas Node Selector, konsep fundamental untuk kontrol dimana Pod run di cluster kalian.
Catatan: Disini saya akan menggunakan Kubernetes Cluster yang di install melalui K3s.
By default, Kubernetes scheduler otomatis place Pod di available node. Tapi kadang kalian butuh kontrol atas Pod placement - mungkin kalian ingin GPU workload di GPU node, atau production Pod di high-performance node. Node Selector menyediakan cara simple untuk achieve ini.
Node Selector adalah cara paling simple untuk constrain Pod agar run di specific node. Dia menggunakan label matching untuk select node dimana Pod harus di-schedule. Kalian add label ke node, kemudian specify label tersebut di Pod specification menggunakan nodeSelector.
Bayangkan Node Selector seperti filtering - kalian label node dengan karakteristik (GPU, SSD, high-memory), kemudian tell Pod untuk hanya run di node dengan specific label. Scheduler hanya consider node yang match semua specified label.
Karakteristik kunci Node Selector:
Node Selector berguna untuk berbagai scenario dimana kalian butuh kontrol atas Pod placement:
Tanpa Node Selector, kalian perlu:
Sebelum menggunakan Node Selector, kalian perlu memahami node label. Label adalah key-value pair yang attached ke node.
Cek existing node label:
sudo kubectl get nodes --show-labelsLihat label untuk specific node:
sudo kubectl describe node <node-name>Kubernetes otomatis add beberapa label ke node:
kubernetes.io/hostname - Node's hostnamekubernetes.io/os - Operating system (linux, windows)kubernetes.io/arch - CPU architecture (amd64, arm64)node.kubernetes.io/instance-type - Cloud instance typetopology.kubernetes.io/region - Cloud regiontopology.kubernetes.io/zone - Cloud availability zoneAdd label ke node:
sudo kubectl label nodes <node-name> <key>=<value>Contoh - label node dengan SSD storage:
sudo kubectl label nodes node1 disktype=ssdContoh - label node sebagai production:
sudo kubectl label nodes node2 environment=productionContoh - label node dengan GPU:
sudo kubectl label nodes node3 gpu=nvidia-tesla-v100Remove label dari node:
sudo kubectl label nodes <node-name> <key>-Contoh:
sudo kubectl label nodes node1 disktype-Update existing label:
sudo kubectl label nodes <node-name> <key>=<new-value> --overwriteContoh:
sudo kubectl label nodes node1 disktype=nvme --overwriteSetelah node dilabel, kalian bisa gunakan nodeSelector di Pod specification.
Pertama, label node:
sudo kubectl label nodes node1 disktype=ssdBuat Pod dengan node selector:
apiVersion: v1
kind: Pod
metadata:
name: nginx-ssd
spec:
containers:
- name: nginx
image: nginx:1.25
nodeSelector:
disktype: ssdApply konfigurasi:
sudo kubectl apply -f pod-node-selector.ymlVerify Pod placement:
sudo kubectl get pod nginx-ssd -o widePod hanya akan schedule di node dengan label disktype=ssd.
Kalian bisa specify multiple label (semua harus match):
Pertama, label node dengan multiple label:
sudo kubectl label nodes node1 disktype=ssd
sudo kubectl label nodes node1 environment=productionBuat Pod yang require both label:
apiVersion: v1
kind: Pod
metadata:
name: app-production
spec:
containers:
- name: app
image: nginx:1.25
nodeSelector:
disktype: ssd
environment: productionPod ini hanya schedule di node dengan BOTH disktype=ssd AND environment=production.
Gunakan Kubernetes built-in label:
apiVersion: v1
kind: Pod
metadata:
name: linux-amd64-pod
spec:
containers:
- name: app
image: nginx:1.25
nodeSelector:
kubernetes.io/os: linux
kubernetes.io/arch: amd64Pod ini hanya run di Linux node dengan AMD64 architecture.
Node Selector bekerja dengan semua Pod controller:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
nodeSelector:
environment: production
disktype: ssdSemua 3 replica hanya akan schedule di node dengan both label.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: monitoring-agent
spec:
selector:
matchLabels:
app: monitoring
template:
metadata:
labels:
app: monitoring
spec:
containers:
- name: agent
image: monitoring-agent:latest
nodeSelector:
monitoring: enabledDaemonSet ini hanya run di node yang dilabel dengan monitoring=enabled.
apiVersion: batch/v1
kind: Job
metadata:
name: data-processor
spec:
template:
spec:
containers:
- name: processor
image: data-processor:latest
resources:
requests:
memory: "2Gi"
cpu: "2000m"
nodeSelector:
workload: batch-processing
memory: high
restartPolicy: NeverJob ini run di node yang suitable untuk batch processing dengan high memory.
Label GPU node:
sudo kubectl label nodes gpu-node-1 gpu=nvidia-tesla-v100
sudo kubectl label nodes gpu-node-2 gpu=nvidia-tesla-v100Buat GPU workload:
apiVersion: v1
kind: Pod
metadata:
name: ml-training
spec:
containers:
- name: trainer
image: tensorflow/tensorflow:latest-gpu
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
gpu: nvidia-tesla-v100Label node by environment:
sudo kubectl label nodes node1 node2 environment=production
sudo kubectl label nodes node3 node4 environment=developmentProduction deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-production
spec:
replicas: 5
selector:
matchLabels:
app: api
env: prod
template:
metadata:
labels:
app: api
env: prod
spec:
containers:
- name: api
image: api:v2.0
nodeSelector:
environment: productionDevelopment deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-development
spec:
replicas: 2
selector:
matchLabels:
app: api
env: dev
template:
metadata:
labels:
app: api
env: dev
spec:
containers:
- name: api
image: api:dev
nodeSelector:
environment: developmentLabel node by storage type:
sudo kubectl label nodes node1 node2 disktype=ssd
sudo kubectl label nodes node3 node4 disktype=hddDatabase di SSD:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
nodeSelector:
disktype: ssdLog storage di HDD:
apiVersion: v1
kind: Pod
metadata:
name: log-aggregator
spec:
containers:
- name: aggregator
image: fluentd:latest
nodeSelector:
disktype: hddLabel node by region:
sudo kubectl label nodes node1 node2 region=us-east
sudo kubectl label nodes node3 node4 region=us-westDeploy ke specific region:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-us-east
spec:
replicas: 3
selector:
matchLabels:
app: web
region: us-east
template:
metadata:
labels:
app: web
region: us-east
spec:
containers:
- name: web
image: nginx:1.25
nodeSelector:
region: us-eastLabel node by cost tier:
sudo kubectl label nodes node1 node2 cost=high-performance
sudo kubectl label nodes node3 node4 node5 cost=standardCritical workload di high-performance node:
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
spec:
replicas: 3
selector:
matchLabels:
app: payment
template:
metadata:
labels:
app: payment
spec:
containers:
- name: payment
image: payment-service:latest
nodeSelector:
cost: high-performanceNon-critical workload di standard node:
apiVersion: apps/v1
kind: Deployment
metadata:
name: background-jobs
spec:
replicas: 5
selector:
matchLabels:
app: jobs
template:
metadata:
labels:
app: jobs
spec:
containers:
- name: worker
image: job-worker:latest
nodeSelector:
cost: standardJika Pod pending, cek apakah matching node exist:
sudo kubectl describe pod <pod-name>Look for event seperti:
Warning FailedScheduling Pod didn't match node selectorCek available node dengan required label:
sudo kubectl get nodes -l disktype=ssdJika tidak ada node yang match, either:
Verify dimana Pod running:
sudo kubectl get pods -o wideCek apakah Pod di expected node:
sudo kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,NODE_SELECTOR:.spec.nodeSelectorLihat semua Pod di specific node:
sudo kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=<node-name>Problem: Label name mismatch antara node dan Pod.
Solusi: Double-check label name:
# Check node label
sudo kubectl get nodes --show-labels
# Verify Pod nodeSelector
sudo kubectl get pod <pod-name> -o yaml | grep -A 5 nodeSelectorProblem: Tidak ada node yang punya required label.
Solusi: Verify node dengan required label exist:
sudo kubectl get nodes -l <key>=<value>Problem: Node baru ditambahkan tanpa required label.
Solusi: Buat checklist atau automation untuk labeling new node:
# Label new node immediately after adding
sudo kubectl label nodes <new-node> environment=production disktype=ssdProblem: Expect OR logic, tapi nodeSelector gunakan AND.
Solusi: Node Selector hanya support AND logic. Untuk OR logic, gunakan Node Affinity (covered di next episode).
# Ini require BOTH label (AND logic)
nodeSelector:
disktype: ssd
environment: productionProblem: Terlalu banyak nodeSelector constraint prevent scheduling.
Solusi: Gunakan hanya necessary constraint:
# Terlalu constrained
nodeSelector:
disktype: ssd
environment: production
region: us-east
zone: us-east-1a
instance-type: m5.xlarge
# Better - hanya essential constraint
nodeSelector:
environment: production
disktype: ssdProblem: Semua matching node full.
Solusi: Ensure enough capacity di labeled node:
# Check node capacity
sudo kubectl describe nodes -l environment=productionPilih clear, descriptive label name:
# Bagus
sudo kubectl label nodes node1 disktype=ssd
sudo kubectl label nodes node1 environment=production
# Hindari
sudo kubectl label nodes node1 type=1
sudo kubectl label nodes node1 env=prodMaintain documentation dari label schema kalian:
# Label Schema Documentation
# disktype: ssd | hdd | nvme
# environment: production | staging | development
# region: us-east | us-west | eu-central
# gpu: nvidia-tesla-v100 | nvidia-a100 | noneStandardize label value across cluster kalian:
# Consistent
environment=production # Always lowercase
environment=staging
environment=development
# Inconsistent (hindari)
environment=Production
environment=STAGING
environment=devAutomate node labeling during cluster setup:
# Di node provisioning script
kubectl label nodes $NODE_NAME \
environment=production \
disktype=ssd \
region=us-eastSelalu set resource request dengan nodeSelector:
spec:
containers:
- name: app
image: app:latest
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
nodeSelector:
environment: productionReserve nodeSelector untuk workload dengan specific requirement:
# Good use case - GPU workload
nodeSelector:
gpu: nvidia-tesla-v100
# Good use case - High-performance database
nodeSelector:
disktype: nvme
memory: high
# Unnecessary - generic web app
# nodeSelector:
# kubernetes.io/os: linux # Usually not neededTrack label change untuk audit purpose:
# View recent event
sudo kubectl get events --sort-by='.lastTimestamp' | grep -i labelTest nodeSelector di development dulu:
# Test di dev namespace
kubectl apply -f pod-node-selector.yml -n development
# Verify placement
kubectl get pod -n development -o wide
# Kemudian deploy ke production
kubectl apply -f pod-node-selector.yml -n productionNode Selector simple tapi punya limitasi:
Tidak bisa gunakan operator seperti "not equal" atau "in":
# Node Selector - hanya support equality
nodeSelector:
disktype: ssd # Harus equal "ssd"
# Tidak bisa:
# disktype != hdd
# disktype in (ssd, nvme)
# disktype existsUntuk advanced matching, gunakan Node Affinity (next episode).
Tidak bisa express OR logic:
# Tidak bisa bilang: disktype=ssd OR disktype=nvme
# Semua label harus match (AND logic)
nodeSelector:
disktype: ssd
environment: productionNode Selector adalah hard requirement. Pod tidak akan schedule jika tidak ada matching node.
Untuk soft preference, gunakan Node Affinity (next episode).
Gunakan Node Selector saat:
Consider Node Affinity saat:
Pada episode 16 ini, kita telah membahas Node Selector di Kubernetes secara mendalam. Kita sudah belajar apa itu Node Selector, cara label node, dan cara menggunakan nodeSelector untuk kontrol Pod placement.
Key takeaway:
Node Selector essential untuk kontrol Pod placement di Kubernetes. Dengan memahami Node Selector, kalian bisa ensure workload run di appropriate node, optimize resource usage, dan maintain environment separation.
Bagaimana, makin jelas kan tentang Node Selector di Kubernetes? Di episode 17 berikutnya, kita akan membahas bekerja dengan all keyword, yang menyediakan cara convenient untuk manage multiple Kubernetes resource sekaligus menggunakan kubectl get all dan kubectl delete all. Jadi, pastikan tetap semangat belajar dan nantikan episode selanjutnya!