implementasi karpenter pada aws eks

0
110

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