Belajar Kubernetes - Episode 16 - Pengenalan dan Penjelasan Node Selector

Belajar Kubernetes - Episode 16 - Pengenalan dan Penjelasan Node Selector

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.

Arman Dwi Pangestu
Arman Dwi PangestuMarch 19, 2026
0 views
9 min read

Pendahuluan

Catatan

Untuk kalian yang ingin membaca episode sebelumnya, bisa click thumbnail episode 15 di bawah ini

Episode 15Episode 15

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.

Apa Itu Node Selector?

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:

  • Label-based selection - Menggunakan key-value label untuk match node
  • Simple syntax - Mudah dipahami dan diimplementasikan
  • Equality matching - Hanya support exact label match
  • Multiple label - Bisa specify multiple label (AND logic)
  • Scheduling constraint - Pod tidak akan schedule jika tidak ada matching node
  • Node labeling - Require manual node labeling

Kenapa Kita Butuh Node Selector?

Node Selector berguna untuk berbagai scenario dimana kalian butuh kontrol atas Pod placement:

  • Hardware requirement - Schedule GPU workload di GPU node
  • Storage type - Place Pod di node dengan SSD atau NVMe storage
  • Environment separation - Keep production dan development Pod terpisah
  • Geographic location - Schedule Pod di specific region atau zone
  • Node capability - Gunakan node dengan specific CPU architecture
  • Cost optimization - Gunakan cheaper node untuk non-critical workload
  • Compliance - Keep sensitive workload di specific node
  • Performance - Schedule high-performance app di powerful node

Tanpa Node Selector, kalian perlu:

  • Manually schedule Pod di specific node
  • Gunakan more complex affinity rule
  • Accept random Pod placement by scheduler

Node Label

Sebelum menggunakan Node Selector, kalian perlu memahami node label. Label adalah key-value pair yang attached ke node.

Melihat Node Label

Cek existing node label:

Kubernetesbash
sudo kubectl get nodes --show-labels

Lihat label untuk specific node:

Kubernetesbash
sudo kubectl describe node <node-name>

Built-in Node Label

Kubernetes otomatis add beberapa label ke node:

  • kubernetes.io/hostname - Node's hostname
  • kubernetes.io/os - Operating system (linux, windows)
  • kubernetes.io/arch - CPU architecture (amd64, arm64)
  • node.kubernetes.io/instance-type - Cloud instance type
  • topology.kubernetes.io/region - Cloud region
  • topology.kubernetes.io/zone - Cloud availability zone

Menambahkan Custom Label

Add label ke node:

Kubernetesbash
sudo kubectl label nodes <node-name> <key>=<value>

Contoh - label node dengan SSD storage:

Kubernetesbash
sudo kubectl label nodes node1 disktype=ssd

Contoh - label node sebagai production:

Kubernetesbash
sudo kubectl label nodes node2 environment=production

Contoh - label node dengan GPU:

Kubernetesbash
sudo kubectl label nodes node3 gpu=nvidia-tesla-v100

Menghapus Label

Remove label dari node:

Kubernetesbash
sudo kubectl label nodes <node-name> <key>-

Contoh:

Kubernetesbash
sudo kubectl label nodes node1 disktype-

Update Label

Update existing label:

Kubernetesbash
sudo kubectl label nodes <node-name> <key>=<new-value> --overwrite

Contoh:

Kubernetesbash
sudo kubectl label nodes node1 disktype=nvme --overwrite

Menggunakan Node Selector

Setelah node dilabel, kalian bisa gunakan nodeSelector di Pod specification.

Contoh 1: Basic Node Selector

Pertama, label node:

Kubernetesbash
sudo kubectl label nodes node1 disktype=ssd

Buat Pod dengan node selector:

Kubernetespod-node-selector.yml
apiVersion: v1
kind: Pod
metadata:
    name: nginx-ssd
spec:
    containers:
        - name: nginx
          image: nginx:1.25
    nodeSelector:
        disktype: ssd

Apply konfigurasi:

Kubernetesbash
sudo kubectl apply -f pod-node-selector.yml

Verify Pod placement:

Kubernetesbash
sudo kubectl get pod nginx-ssd -o wide

Pod hanya akan schedule di node dengan label disktype=ssd.

Contoh 2: Multiple Label Selector

Kalian bisa specify multiple label (semua harus match):

Pertama, label node dengan multiple label:

Kubernetesbash
sudo kubectl label nodes node1 disktype=ssd
sudo kubectl label nodes node1 environment=production

Buat Pod yang require both label:

Kubernetespod-multiple-selectors.yml
apiVersion: v1
kind: Pod
metadata:
    name: app-production
spec:
    containers:
        - name: app
          image: nginx:1.25
    nodeSelector:
        disktype: ssd
        environment: production

Pod ini hanya schedule di node dengan BOTH disktype=ssd AND environment=production.

Contoh 3: Menggunakan Built-in Label

Gunakan Kubernetes built-in label:

Kubernetespod-builtin-labels.yml
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: amd64

Pod ini hanya run di Linux node dengan AMD64 architecture.

Node Selector dengan Deployment

Node Selector bekerja dengan semua Pod controller:

Contoh 1: Deployment dengan Node Selector

Kubernetesdeployment-node-selector.yml
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: ssd

Semua 3 replica hanya akan schedule di node dengan both label.

Contoh 2: DaemonSet dengan Node Selector

Kubernetesdaemonset-node-selector.yml
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: enabled

DaemonSet ini hanya run di node yang dilabel dengan monitoring=enabled.

Contoh 3: Job dengan Node Selector

Kubernetesjob-node-selector.yml
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: Never

Job ini run di node yang suitable untuk batch processing dengan high memory.

Contoh Praktis

Contoh 1: GPU Workload

Label GPU node:

Kubernetesbash
sudo kubectl label nodes gpu-node-1 gpu=nvidia-tesla-v100
sudo kubectl label nodes gpu-node-2 gpu=nvidia-tesla-v100

Buat GPU workload:

Kubernetesgpu-workload.yml
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-v100

Contoh 2: Environment Separation

Label node by environment:

Kubernetesbash
sudo kubectl label nodes node1 node2 environment=production
sudo kubectl label nodes node3 node4 environment=development

Production deployment:

Kubernetesproduction-deployment.yml
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: production

Development deployment:

Kubernetesdevelopment-deployment.yml
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: development

Contoh 3: Storage Type Selection

Label node by storage type:

Kubernetesbash
sudo kubectl label nodes node1 node2 disktype=ssd
sudo kubectl label nodes node3 node4 disktype=hdd

Database di SSD:

Kubernetesdatabase-ssd.yml
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: ssd

Log storage di HDD:

Kuberneteslog-storage-hdd.yml
apiVersion: v1
kind: Pod
metadata:
    name: log-aggregator
spec:
    containers:
        - name: aggregator
          image: fluentd:latest
    nodeSelector:
        disktype: hdd

Contoh 4: Geographic Placement

Label node by region:

Kubernetesbash
sudo kubectl label nodes node1 node2 region=us-east
sudo kubectl label nodes node3 node4 region=us-west

Deploy ke specific region:

Kubernetesregional-deployment.yml
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-east

Contoh 5: Cost Optimization

Label node by cost tier:

Kubernetesbash
sudo kubectl label nodes node1 node2 cost=high-performance
sudo kubectl label nodes node3 node4 node5 cost=standard

Critical workload di high-performance node:

Kubernetescritical-workload.yml
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-performance

Non-critical workload di standard node:

Kubernetesnon-critical-workload.yml
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: standard

Troubleshooting Node Selector

Pod Stuck di Pending State

Jika Pod pending, cek apakah matching node exist:

Kubernetesbash
sudo kubectl describe pod <pod-name>

Look for event seperti:

plaintext
Warning  FailedScheduling  Pod didn't match node selector

Cek available node dengan required label:

Kubernetesbash
sudo kubectl get nodes -l disktype=ssd

Jika tidak ada node yang match, either:

  1. Add label ke node
  2. Remove/modify nodeSelector

Checking Pod Placement

Verify dimana Pod running:

Kubernetesbash
sudo kubectl get pods -o wide

Cek apakah Pod di expected node:

Kubernetesbash
sudo kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,NODE_SELECTOR:.spec.nodeSelector

Listing Pod by Node

Lihat semua Pod di specific node:

Kubernetesbash
sudo kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=<node-name>

Kesalahan Umum dan Pitfall

Kesalahan 1: Typo di Label Name

Problem: Label name mismatch antara node dan Pod.

Solusi: Double-check label name:

Kubernetesbash
# Check node label
sudo kubectl get nodes --show-labels
 
# Verify Pod nodeSelector
sudo kubectl get pod <pod-name> -o yaml | grep -A 5 nodeSelector

Kesalahan 2: Tidak Ada Matching Node

Problem: Tidak ada node yang punya required label.

Solusi: Verify node dengan required label exist:

Kubernetesbash
sudo kubectl get nodes -l <key>=<value>

Kesalahan 3: Lupa Label New Node

Problem: Node baru ditambahkan tanpa required label.

Solusi: Buat checklist atau automation untuk labeling new node:

Kubernetesbash
# Label new node immediately after adding
sudo kubectl label nodes <new-node> environment=production disktype=ssd

Kesalahan 4: Menggunakan OR Logic

Problem: Expect OR logic, tapi nodeSelector gunakan AND.

Solusi: Node Selector hanya support AND logic. Untuk OR logic, gunakan Node Affinity (covered di next episode).

Kubernetesyml
# Ini require BOTH label (AND logic)
nodeSelector:
    disktype: ssd
    environment: production

Kesalahan 5: Overconstraining Pod

Problem: Terlalu banyak nodeSelector constraint prevent scheduling.

Solusi: Gunakan hanya necessary constraint:

Kubernetesyml
# 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: ssd

Kesalahan 6: Tidak Consider Node Capacity

Problem: Semua matching node full.

Solusi: Ensure enough capacity di labeled node:

Kubernetesbash
# Check node capacity
sudo kubectl describe nodes -l environment=production

Best Practice

Gunakan Meaningful Label Name

Pilih clear, descriptive label name:

Kubernetesbash
# 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=prod

Document Labeling Strategy Kalian

Maintain documentation dari label schema kalian:

yaml
# Label Schema Documentation
# disktype: ssd | hdd | nvme
# environment: production | staging | development
# region: us-east | us-west | eu-central
# gpu: nvidia-tesla-v100 | nvidia-a100 | none

Gunakan Consistent Label Value

Standardize label value across cluster kalian:

Kubernetesbash
# Consistent
environment=production  # Always lowercase
environment=staging
environment=development
 
# Inconsistent (hindari)
environment=Production
environment=STAGING
environment=dev

Label Node During Provisioning

Automate node labeling during cluster setup:

Kubernetesbash
# Di node provisioning script
kubectl label nodes $NODE_NAME \
    environment=production \
    disktype=ssd \
    region=us-east

Combine dengan Resource Request

Selalu set resource request dengan nodeSelector:

Kubernetesyml
spec:
    containers:
        - name: app
          image: app:latest
          resources:
              requests:
                  memory: "512Mi"
                  cpu: "500m"
              limits:
                  memory: "1Gi"
                  cpu: "1000m"
    nodeSelector:
        environment: production

Gunakan untuk Critical Workload

Reserve nodeSelector untuk workload dengan specific requirement:

Kubernetesyml
# 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 needed

Monitor Node Label Change

Track label change untuk audit purpose:

Kubernetesbash
# View recent event
sudo kubectl get events --sort-by='.lastTimestamp' | grep -i label

Test Sebelum Production

Test nodeSelector di development dulu:

Kubernetesbash
# 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 production

Limitasi Node Selector

Node Selector simple tapi punya limitasi:

Hanya Equality Matching

Tidak bisa gunakan operator seperti "not equal" atau "in":

Kubernetesyml
# Node Selector - hanya support equality
nodeSelector:
    disktype: ssd  # Harus equal "ssd"
 
# Tidak bisa:
# disktype != hdd
# disktype in (ssd, nvme)
# disktype exists

Untuk advanced matching, gunakan Node Affinity (next episode).

AND Logic Saja

Tidak bisa express OR logic:

Kubernetesyml
# Tidak bisa bilang: disktype=ssd OR disktype=nvme
# Semua label harus match (AND logic)
nodeSelector:
    disktype: ssd
    environment: production

Tidak Ada Soft Preference

Node Selector adalah hard requirement. Pod tidak akan schedule jika tidak ada matching node.

Untuk soft preference, gunakan Node Affinity (next episode).

Kapan Menggunakan Node Selector

Gunakan Node Selector saat:

  • Kalian butuh simple, straightforward node selection
  • Kalian punya clear, specific node requirement
  • Kalian ingin easy-to-understand Pod specification
  • Kalian menggunakan equality-based label matching

Consider Node Affinity saat:

  • Kalian butuh complex selection logic (OR, NOT, IN)
  • Kalian ingin soft preference (preferred tapi not required)
  • Kalian butuh more flexible matching operator
  • Kalian implement advanced scheduling strategy

Penutup

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 adalah cara paling simple untuk constrain Pod placement
  • Menggunakan label matching untuk select node
  • Require manual node labeling sebelum use
  • Support multiple label dengan AND logic
  • Bekerja dengan semua Pod controller (Deployment, DaemonSet, Job, dll)
  • Hanya support equality matching (key=value)
  • Pod tidak akan schedule jika tidak ada matching node
  • Perfect untuk hardware requirement, environment separation, dan cost optimization
  • Gunakan meaningful, consistent label name
  • Document labeling strategy kalian

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!


Related Posts