Halo sobat sekolahlinux, pada artikel ini saya akan sedikit share tentang implementasi aws pada karpenter, pada dasarnya karpenter adalah sebuah tool yang berguna untuk melakukan node autoscale pada aws eks
kenapa saya membuat artikel ini, karena diluar sana saya merasa sedikit sekali artikel yang membahas tentang karpenter secara lengkap, tentu pada artikel kali ini saya juga tidak akan membahas secara terperinci, namun saya akan coba berikan point point apa saja yang perlu di lakukan sebelum implementasi karpenter itu sendiri.
- hpa: hal ini berguna untuk memastikan pods service kalian dapat melakukan horizontal autoscale, pastikan replica pods kalian lebih dari satu ya jika ingin implementasi karpenter, salah satu metode pengatur replica nya bisa dengan hpa
- podAntiAffinity: memastikan replica pods kalian tidak berkumpul pada 1 node, saya menyarankan kalian menggunakan mode “required” dibanding “prefered” hal ini untuk memastikan pods replica benar-benar berada di node yang berbeda
- pdb: hal ini berguna untuk memastikan tidak semua pods kalian terdelete berdasarkan config yang kalian terapkan pada saat rolling node karpenter terjadi
- preStop: hal ini berguna jika service yang kalian miliki belum memiliki gracefull shutdown yang proper, yang mana ini berguna jika terjadi rolling node
- resource request/limit: hal ini berguna untuk memastikan hpa dan juga perhitungan monitoring bisa ditampilkan
jika 5 point diatas sudah di terapkan selanjutnya kita masuk ke setup karpenter itu sendiri, untuk step-step install karpenternya kalian bisa mengunjungin official doc nya dibawah ini, oh iya pada saat saya membuat artikel ini saya menulis nya untuk karpenter v1.x
Nodeclass
berikut ini adalah manfest nodeclass yang akan kita gunakan
apiVersion: karpenter.k8s.aws/v1 kind: EC2NodeClass metadata: name: sekolahlinux spec: kubelet: #maxPods: 20 systemReserved: cpu: 100m memory: 100Mi ephemeral-storage: 1Gi kubeReserved: cpu: 200m memory: 100Mi ephemeral-storage: 3Gi evictionSoft: memory.available: 250Mi nodefs.available: 10% nodefs.inodesFree: 10% imagefs.available: 10% imagefs.inodesFree: 10% pid.available: 10% evictionSoftGracePeriod: memory.available: 20s nodefs.available: 20s nodefs.inodesFree: 20s imagefs.available: 20s imagefs.inodesFree: 20s pid.available: 20s evictionMaxPodGracePeriod: 40 tags: env: production organization: sekolahlinux Name: nodepool-sekolahlinux-devstaging metadataOptions: httpTokens: optional httpPutResponseHopLimit: 2 httpEndpoint: enabled httpProtocolIPv6: disabled amiFamily: AL2 # Amazon Linux 2 userData: | #!/bin/bash echo "$(jq '.kubeAPIQPS=60|.shutdownGracePeriod="600s"' /etc/kubernetes/kubelet/kubelet-config.json)" > /etc/kubernetes/kubelet/kubelet-config.json role: "KarpenterNodeRole-sekolahlinux-DevStaging" # replace with your cluster name subnetSelectorTerms: - tags: karpenter.sh/discovery: "sekolahlinux-DevStaging" # replace with your cluster name securityGroupSelectorTerms: - tags: karpenter.sh/discovery: "sekolahlinux-DevStaging" # replace with your cluster name amiSelectorTerms: - id: "ami-0a0004f2412eb6547" - id: "ami-075fdaa4bc68dcc34" # - id: "ami-05e98588f28646469" # <- GPU Optimized AMD AMI # - name: "amazon-eks-node-1.29-*" # <- automatically upgrade when a new AL2 EKS Optimized AMI is released. This is unsafe for production workloads. Validate AMIs in lower environments before deploying them to production.
pada paramater diatas penting untuk kita perhatikan perhitungan berikut ini
- maxPods > max jumlah pods yang dapat berjalan didalam sebuah node karpenter, *sekedar catatan untuk paramater ini better di hapus saja, karena jika value nya tidak cocok dengan size type instance nya maka akan terkena issue allocate ip seperti pada case disini https://karpenter.sh/docs/troubleshooting/#maxpods-is-greater-than-the-nodes-supported-pod-density
- evictionSoftGracePeriod > waktu tunggu untuk memastikan sebuah pod dapat menyelesaikan proses yang sedang berjalan setelah perintah sigTerm dikirim ke pod, jika waktunya melebihi jumlah yang ditentukan maka selanjutnya system akan mengirimkan sigKill atau di force stop
- shutdownGracePeriod > waktu tunggu sebuah node untuk memastikan semua pods di stop, jika sampai waktu yang ditentukan pods2 tersebut belum pindah semua, maka node akan matikan paksa node nya, untuk memastikan angka yang tepat kamu perlu menghitung (evictionSoftGracePeriod x Estimasi_Jumlah_Pods = shutdownGracePeriod)
- tags > ini berguna untuk menambahkan tag pada setiap ec2/node yang mana nantinya berguna untuk cost tracking
Nodepool
berikut ini adalah manfest nodepool yang akan kita gunakan
apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: sekolahlinux spec: template: metadata: labels: type: spot services: sekolahlinux spec: terminationGracePeriod: 1h expireAfter: 720h requirements: - key: kubernetes.io/arch operator: In values: ["amd64"] - key: kubernetes.io/os operator: In values: ["linux"] - key: karpenter.sh/capacity-type operator: In values: ["spot"] - key: "karpenter.k8s.aws/instance-category" operator: In values: ["t", "m", "c", "r"] minValues: 2 - key: "karpenter.k8s.aws/instance-cpu" operator: In values: ["2", "4"] - key: "karpenter.k8s.aws/instance-generation" operator: Gt values: ["2"] - key: node.kubernetes.io/instance-type operator: Exists minValues: 10 #operator: In #values: #- t3.xlarge #- m5.xlarge #- m4.xlarge #- m6a.xlarge #- m6i.xlarge #- m5a.xlarge #- t3a.xlarge nodeClassRef: group: karpenter.k8s.aws kind: EC2NodeClass name: sekolahlinux taints: - key: services effect: NoSchedule value: sekolahlinux limits: cpu: 1000 disruption: consolidationPolicy: WhenEmptyOrUnderutilized #consolidationPolicy: WhenEmpty consolidateAfter: 15m budgets: - nodes: "1" reasons: - "Empty" - "Drifted" - "Underutilized"
selanjutnya untuk nodepool perlu kita perhatikan paramater berikut, oh iya di case kali ini saya menggunakan spot instance, maka kita wajib menentukan banyak instance type, supaya agar ketika 1 instance type tidak tersedia maka bisa mengambil dari instance type yang lain
- requirements
- key: karpenter.sh/capacity-type > paramater ini untuk menentukan apakah node yang akan di pakai adalah ondemand atau spot
- key: node.kubernetes.io/instance-type > untuk menentukan type instance yang akan di create, ada baiknnya jika kita menggunakan spot maka type yang di set harus lebih dari satu, lebih banyak lebih baik
- consolidationPolicy > untuk menentukan kondisi seperti apa delete/rolling node akan dilakukan, apakah pada saat node kosong atau pada saat node underutilize
- consolidateAfter > untuk menentukan berapa lama sekali karpenter akan menjalankan consolidationPolicy untuk menentukan apakah node tersebut akan di rolling/delete atau tidak sesuai dengan policy yang di set
- budgets
- nodes > jumlah max node yang akan di rolling/delete jika ditemukan kecocokan terhadap policy yang di set
- reasons > disini juga perlu di masukan budget nodes diatas berlaku untuk policy yang mana saja
- Empty > jika tidak ada pods yang berjalan didalam node, untuk pods daemon set tidak dihitung dalam case ini
- Drifted > jika ada perubahan pada config nodepool ataupun nodeclass
- Underutilized > jika node tersebut underutilize
Conclusion:
- apakah karpenter dapat menghemat cost? jawaban saya “depends” bisa jadi penggunaan karpenter justru bisa mmebuat lebih boros karena ada kondisi2 yang harus di penuhi, maka dari itu perlu perhitungan dan persiapan yang matang terhadap service config di k8s, selain itu memahami behaviour dari resource usage pada service yang berjalan di k8s juga perlu dilakukan untuk menghindari kondisi dimana karpenter sering melakukan rolling node yang menyebabkan node bisa saja malah rolling didalam waktu bersamaan
- apakah karpenter dapat meningkatkan reliability? jawaban saya juga “depends” balik lagi ke persiapan dan perhitungan serta pemahaman kita dalam behaviour service yang berjalan di atas k8s, dalam hal ini service yang kita develop sendiri ya, tapi yang pasti waktu scaling up dan down yang dibutuhkan karpenter bisa 40-50% lebih cepat dibandingkan cluster autoscaller
- pastikan monitoring yang kamu miliki paling tidak sudah mengcover untuk “4 Golden Signal” karena jika ada anomali kita bisa cepat tahu dan lekas melakukan penanganan yang tepat
QnA:
- Q: apakah karpenter dapat mempengaruhi pods yang berada di node yang bukan nodeclass, dalam hal ini nodegroup
- A: berdasarkan apa yang saya alami, “YA” karpenter dapat mempengaruhi behaviour sebuah nodegroup untuk melakukan restart, dalam case ini saya memiliki service “prometheus server” yang hidup di nodegroup, entah kenapa karpenter membuat nodegroup lebih agresif dalam rolling node
- Q: apakah karpenter dan cluster autoscaler bisa hidup bersamaan?
- A: berdasarkan pengelaman saya, “YA” selain itu karpenter entah bagaimana di case saya berdasarkan event pods bisa memilihkan node dari nodegroup untuk pods saya, padahal pods tersebut hidup di nodegroup karena saya sudah set nodeSelector
- Q: apakah setiap nodepool harus memiliki nodeclass dedicated
- A: sebenernya 1 nodeclass bisa untuk banyak nodepool, namun dalam case saya, disini saya membuat 1 nodepool punya 1 nodeclass, hal ini dikarenakan saya ingin tiap nodepool memliki tag yg uniq, hal ini saya gunakan untuk cost tracking