NodePool adalah jantung scheduling Karpenter. Episode ini membedah struktur spec.template, requirements, disruption, dan weight, lalu bagaimana Karpenter mencocokkan pod dengan pool dan menandai node yang dibuatnya.

Di episode 3 kalian sudah berhasil membuat Karpenter memprovisikan node pertama: NodePool bernama default menunjuk ke EC2NodeClass, workload nginx langsung dijadwalkan, dan NodeClaim muncul. Sekarang kita bedah komponen yang paling menentukan perilaku Karpenter: NodePool.
Episode ini membedah struktur lengkap NodePool — spec.template, requirements, disruption, dan weight — lalu menjelaskan bagaimana Karpenter mencocokkan pod dengan pool yang tepat, dan label/annotasi apa saja yang ditempelkan pada node yang dibuatnya.
NodePool terdiri dari dua bagian besar: spec.template yang mendefinisikan node, dan spec.disruption yang mengatur kapan node boleh diganti. Ada juga spec.weight untuk preferensi antar pool. Mari kita lihat contoh lengkapnya:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: general
spec:
weight: 10
template:
metadata:
labels:
team: platform
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: node.kubernetes.io/instance-type
operator: In
values: ["m5.large", "m6i.large", "m6a.large"]
taints:
- key: workloads
value: "true"
effect: PreferNoSchedule
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720hspec.template.metadata berisi label dan anotasi yang akan ditempelkan ke node baru, misalnya team: platform untuk grouping biaya. spec.template.spec berisi tiga hal penting:
Requirement memakai bentuk key, operator, dan values. Operator yang tersedia: In, NotIn, Gt, Lt, dan Exists. Key yang umum dipakai:
| Key | Contoh nilai | Arti |
|---|---|---|
| node.kubernetes.io/instance-type | m5.large, m6i.large | Filter instance type |
| karpenter.sh/capacity-type | on-demand, spot | Jenis kapasitas |
| topology.kubernetes.io/zone | ap-southeast-1a | Availability zone |
| kubernetes.io/arch | amd64, arm64 | Arsitektur CPU |
| karpenter.sh/instance-category | general, compute | Kategori family |
| karpenter.sh/instance-family | m5, c6i | Family instance |
Kombinasi requirement inilah yang menentukan "ruang pencarian" instance Karpenter. Semakin spesifik, semakin terbatas pilihan — semakin luas, semakin besar peluang dapat harga murah lewat binpacking.
spec.disruption mengontrol kapan node boleh dihentikan:
Ketika beberapa NodePool sama-sama cocok dengan pod, spec.weight menentukan pemenangnya. Semakin tinggi nilai weight (skala 0-100), semakin diutamakan pool tersebut. Jika bobotnya sama, Karpenter memilih pool yang urutannya paling awal.
Scheduling di Karpenter pada dasarnya membalik logika scheduler standar: alih-alih mencari node untuk pod, Karpenter mencari kombinasi instance yang bisa memenuhi semua pod yang mengantre. Prosesnya melibatkan:
Total request CPU, memory, GPU, dan storage dari semua pod dihitung untuk menentukan ukuran instance minimal. Pod dengan request yang saling melengkapi bisa di-binpack ke satu node.
Label yang diminta pod lewat nodeSelector atau nodeAffinity dicocokkan dengan label dari spec.template NodePool. Contoh: pod dengan nodeSelector disktype: ssd hanya cocok dengan pool yang mendefinisikan label disktype: ssd.
Node dari NodePool bisa diberi taint. Pod yang tidak punya toleration yang cocok akan ditolak pool tersebut. Ini cara paling umum memisahkan workload: pool khusus Spot dengan taint, hanya pod yang siap diganggu yang boleh masuk.
Note
Karpenter juga menghormati constraint Kubernetes lain seperti node affinity, pod affinity/anti-affinity, dan topology spread constraints. Semua itu turut mempersempit pilihan instance — jadi jangan heran jika kombinasi constraint membuat Karpenter memilih instance yang lebih besar.
Saat node lahir dari sebuah pool, Karpenter menempelkan label dan anotasi yang menjadi jendela observability:
| Label/Anotasi | Tipe | Isi |
|---|---|---|
| karpenter.sh/nodepool | label | Nama NodePool asal node |
| karpenter.sh/capacity-type | label | spot atau on-demand |
| node.kubernetes.io/instance-type | label | Instance type terpilih |
| topology.kubernetes.io/zone | label | AZ tempat instance diluncurkan |
| karpenter.sh/registered | anotasi | Menandakan node sudah terdaftar |
| karpenter.sh/do-not-disrupt | anotasi | Melindungi pod dari konsolidasi |
kubectl get nodes -l karpenter.sh/nodepool=general -o wide
kubectl describe node <node-name>
kubectl get nodeclaimsLabel karpenter.sh/nodepool dan karpenter.sh/capacity-type inilah yang biasa dipakai untuk tagging biaya dan grouping node. Menambahkan anotasi karpenter.sh/do-not-disrupt pada pod penting akan membuat Karpenter melewatinya saat konsolidasi.
Praktik umum di production: beberapa NodePool untuk kebutuhan berbeda — satu untuk workload umum, satu khusus Spot yang lebih murah, satu lagi untuk GPU. Contoh pembagian:
| NodePool | capacity-type | instance-family | weight |
|---|---|---|---|
| general | on-demand | m5, m6i, m6a | 10 |
| spot | spot | c5, c6i | 20 |
| gpu | on-demand | g5, p4d | 0 |
Dengan weight lebih tinggi, pool spot akan dipilih lebih dulu selama pod-nya toleran terhadap taint Spot. Ini strategi hemat biaya yang paling sering dipakai.
Episode 4 membedah NodePool — inti dari kebijakan scheduling Karpenter. Kalian memahami struktur spec.template dengan requirements dan taints, kebijakan disruption seperti consolidationPolicy dan expireAfter, weight untuk preferensi antar pool, serta mekanisme Karpenter mencocokkan pod — resource request, label, dan taints — dengan pool yang tepat. Label dan anotasi karpenter.sh menjadi alat observability yang tak ternilai.
Inti yang harus dibawa pulang:
Di episode 5 kita pindah ke sisi infrastruktur: EC2NodeClass. Kita akan membahas AMI selection, security groups, subnets, instance profile, userData, serta cara menggabungkan beberapa NodeClass untuk workload yang berbeda. Sampai jumpa di episode berikutnya!