Di lingkungan cloud, ekspansi (scale-out) dan pengurangan (scale-in) worker node (instans VM) jauh lebih mudah dilakukan dibandingkan di lingkungan on-premise. Sama seperti saat sebelum menggunakan Kubernetes di mana lingkungan VM memanfaatkan Auto Scaling dari AWS untuk menggunakan sumber daya EC2 secara fleksibel sesuai beban sistem, di lingkungan Kubernetes pun worker node dapat diperluas dan diperkecil secara bebas.

Autoscaling node di lingkungan Kubernetes umumnya menggunakan Cluster Autoscaler (CAS) dan Karpenter. Dibandingkan dengan CAS konvensional, Karpenter memiliki struktur yang lebih ringkas sehingga jauh lebih cepat dan fleksibel. Biaya node juga dapat ditekan dibandingkan menggunakan CAS. Mari kita pelajari Karpenter secara mendalam melalui praktik langsung.

Topik Utama

  • Perbandingan CAS (Cluster Autoscaler) vs Karpenter
  • Keunggulan Karpenter

Tugas Praktik

  • Instalasi Karpenter dan eks-node-viewer
  • Pengujian Scale-Out/In Node EKS menggunakan Karpenter

Alamat repositori GitHub untuk sumber kode yang digunakan pada bab ini: https://github.com/junghoon2/k8s-class/tree/main/karpenter

1. Keunggulan Karpenter Dibandingkan Cluster Autoscaler

Karpenter adalah open-source tool yang dirancang untuk mengoptimalkan manajemen node dan penjadwalan (scheduling) di klaster Kubernetes. Sebelumnya, Cluster Autoscaler digunakan untuk melakukan scaling node Kubernetes secara dinamis. CAS memanfaatkan API terpisah yang disesuaikan untuk masing-masing penyedia layanan cloud (AWS, Azure, GCP).

Cluster Autoscaler mengelola node EKS dengan memanfaatkan Auto Scaling Group (ASG) milik AWS. Karena ASG merupakan resource AWS terpisah yang tidak berhubungan langsung dengan EKS, proses sinkronisasi data antara ASG dan node EKS membutuhkan waktu tambahan. Berdasarkan pengujian langsung, penambahan node dengan CAS memerlukan waktu sekitar 2 menit, sedangkan Karpenter hanya membutuhkan waktu sekitar 40 detik.

AWS CON405_How-to-monitor-and-reduce-your-compute-costs.pdf

Node group pada ASG hanya dapat menggunakan tipe instans tunggal, sehingga pemborosan sumber daya (resource) dapat terjadi. Misalnya, hanya untuk menjalankan satu Pod yang membutuhkan 0.1 Core / 128Mi resource, node berkapasitas 4 Core / 32Gi tetap harus dialokasikan sehingga menyebabkan pemborosan biaya.

Karena CAS merupakan teknologi yang lebih lama dibandingkan Karpenter, tingkat kematangan teknologinya memang lebih tinggi. Namun, dari segi biaya dan kecepatan, Karpenter jauh lebih unggul sehingga saat ini banyak perusahaan beralih mengadopsi Karpenter. Penulis sendiri berhasil menghemat biaya lebih dari 30% setelah menerapkan Karpenter dibandingkan metode sebelumnya.

AWS CON405_How-to-monitor-and-reduce-your-compute-costs.pdf

Karpenter menambah dan mengurangi node EKS secara langsung tanpa menggunakan Auto Scaling Group. Selain itu, Karpenter secara otomatis mengalokasikan tipe node paling hemat biaya berdasarkan kebutuhan resource Pod. Ketika Pod yang berjalan telah selesai/berhenti, Karpenter akan kembali memeriksa kebutuhan resource yang diperlukan dan secara otomatis menghapus node lama lalu mengalokasikan node baru yang paling optimal demi efisiensi biaya.

Namun, saat menggunakan Karpenter untuk optimasi node, node baru akan dijalankan dan node lama akan diterminasi sehingga Pod yang sedang berjalan akan dihentikan dan dijalankan kembali di node baru. Oleh karena itu, konfigurasi dasar untuk stabilitas layanan seperti replikasi Pod (redundansi), PodDisruptionBudget, dan Graceful Shutdown mutlak diperlukan. Langkah-langkah ini sebenarnya bukan hanya ditujukan khusus untuk Karpenter saja, melainkan praktik dasar yang memang wajib dilakukan demi meningkatkan stabilitas sistem secara keseluruhan.

2. Instalasi Karpenter Menggunakan Helm

Mari kita pasang Karpenter secara langsung untuk mempelajari fitur-fiturnya secara detail. Karena Karpenter mengontrol instans EC2 di luar EKS, maka diperlukan IRSA (IAM Roles for Service Accounts). Pemasangan akan jauh lebih mudah jika menggunakan modul Karpenter pada Terraform. Tambahkan modul Karpenter ke dalam kode Terraform EKS yang sebelumnya telah digunakan seperti berikut ini:

Modul Terraform karpenter

module "karpenter" {
  source = "terraform-aws-modules/eks/aws//modules/karpenter"

  cluster_name           = module.eks.cluster_name
  irsa_oidc_provider_arn = module.eks.oidc_provider_arn

  policies = {
    AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
  }

  tags = local.tags
}

Lakukan proses deployment menggunakan Terraform:

$ (⎈ |switch-singapore-test:default) tf init
$ (⎈ |switch-singapore-test:default) tf plan -out planfile
$ (⎈ |switch-singapore-test:default) tf apply planfile

Hal penting yang perlu diperhatikan adalah mencatat bagian output Karpenter yang dihasilkan setelah mengeksekusi kode Terraform. Catat informasi karpenter_instance_profile_name dan karpenter_queue_name yang dibutuhkan untuk instalasi Helm Karpenter:

karpenter_instance_profile_name = "Karpenter-jerry-test-2023082121003044240000001d"
karpenter_queue_name = "Karpenter-jerry-test"

Setelah konfigurasi IRSA selesai, sekarang saatnya memasang Karpenter. Kita akan menggunakan Helm:

$ (⎈ |sent-seoul-stage:mongodb) helm pull oci://public.ecr.aws/karpenter/karpenter --version v0.27.5
Pulled: public.ecr.aws/karpenter/karpenter:v0.27.5
Digest: sha256:9491ba645592ab9485ca8ce13f53193826044522981d75975897d229b877d4c2
$ (⎈ |sent-seoul-stage:mongodb) rm -rf karpenter-v0.27.5.tgz
$ (⎈ |sent-seoul-stage:mongodb) mv karpenter karpenter-v0.27.5
$ (⎈ |switch-singapore-test:echoserver) cd karpenter-v0.27.5
$ (⎈ |switch-singapore-test:echoserver) cp values.yaml my-values.yaml

Ubah file default Helm Value (my-values.yaml) seperti berikut:

my-values.yaml

replicas: 2

controller:
  resources:
    limits:
      memory: 1Gi
    requests:
      cpu: 100m
      memory: 1Gi

serviceAccount:
  annotations:
    eks.amazonaws.com/role-arn: $ROLE_ARN

settings:
  aws:
    clusterEndpoint: $Endpoint
    clusterName: $Name
    defaultInstanceProfile: Karpenter-jerry-test-2023082121003044240000001d
    interruptionQueueName: Karpenter-jerry-test

. [serviceAccount.annotations.eks.amazonaws.com/role-arn](https://serviceAccount.annotations.eks.amazonaws.com/role-arn):$ROLE_ARN

Masukkan informasi ROLE_ARN Karpenter masing-masing yang telah dibuat pada modul Terraform Karpenter sebelumnya.

. settings.aws.clusterEndpoint

Masukkan informasi Endpoint API Server klaster Anda. Informasi EndPoint dapat dilihat melalui AWS EKS Console.

Contoh EKS Endpoint
  • . settings.aws.defaultInstanceProfile, interruptionQueueName

Masukkan nilai dari hasil Output saat pemasangan modul Terraform Karpenter sebelumnya.

Lakukan instalasi ke dalam namespace karpenter:

$ (⎈ |switch-singapore-test:karpenter) helm install karpenter --namespace karpenter --create-namespace -f my-values.yaml .
NAME: karpenter
LAST DEPLOYED: Fri Sep 22 05:51:10 2023
NAMESPACE: karpenter
STATUS: deployed
REVISION: 1
TEST SUITE: None

Setelah instalasi selesai, Anda dapat memverifikasi pod Karpenter Controller di dalam namespace karpenter:

$ (⎈ |switch-singapore-test:karpenter) k get pod
NAME                        READY   STATUS    RESTARTS   AGE
karpenter-f654d4b8d-v65dk   1/1     Running   0          7d13h

3. Instalasi Karpenter Provisioner & AWS Node Template

Agar Karpenter dapat men-deploy node baru, konfigurasi detail mengenai node tersebut sangat diperlukan. Karpenter menggunakan dua CRD (Custom Resource Definition) yaitu Provisioner dan AWSNodeTemplate untuk mendefinisikan spesifikasi detailnya.

Istilah Provisioning di lingkungan IT pada dasarnya mengacu pada proses pengalokasian, konfigurasi, dan pengelolaan sumber daya komputasi virtual. Pada Karpenter, hal ini juga mencakup penentuan kebutuhan fisik worker node Kubernetes; termasuk kebijakan resource apa yang harus dipenuhi dan batasan (constraints) apa yang harus dipertimbangkan.

Mari kita pelajari melalui contoh file manifes berikut:

provisioner.yaml

apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: spot
  namespace: karpenter
spec:
  # References cloud provider-specific custom resource, see your cloud provider specific documentation
  providerRef:
    name: default

  # Labels are arbitrary key-values that are applied to all nodes
  labels:
    env: test

  # Requirements that constrain the parameters of provisioned nodes.
  # These requirements are combined with pod.spec.affinity.nodeAffinity rules.
  # Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: "karpenter.k8s.aws/instance-family"
      operator: In
      values: ["t3"]
    - key: "karpenter.sh/capacity-type" # If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: ["spot"]
  limits:
    resources:
      cpu: "100"
      memory: "200Gi"

  # Enables consolidation which attempts to reduce cluster cost by both removing un-needed nodes and down-sizing those
  # that can't be removed. Mutually exclusive with the ttlSecondsAfterEmpty parameter.
  consolidation:
    enabled: true
  • . metadata.name: spot

Tipe node dapat dibedakan berdasarkan penamaan. Sebagai contoh, Anda dapat memisahkan jenis node menjadi Spot node dan On-Demand node. Pod yang dialokasikan untuk berjalan di Spot node dapat dijadwalkan agar di-deploy khusus ke kelompok Spot node tersebut.

  • . spec.requirements.key: “karpenter.k8s.aws/instance-family”

Menentukan kelompok tipe instans (instance family) dari node yang akan disediakan oleh Karpenter. Tergantung pada karakteristik Pod, Anda dapat memilih tipe c6i (fokus komputasi), g5 (node GPU), r6i (fokus memori), atau multi-tipe instans lainnya. Karena ini merupakan lingkungan pengujian, penulis menentukan tipe t3 yang biayanya murah.Sebagai informasi tambahan, penggunaan instans kelompok t4g yang menggunakan prosesor berbasis Arm dapat meningkatkan efisiensi rasio harga terhadap performa (price-performance) sekitar 20%.

  • . spec.requirements.key: “karpenter.sh/capacity-type”

Menentukan instans On-Demand atau Spot. Nilai bawaannya adalah on-demand, dan dapat diubah menjadi spot. Pada aplikasi umum berbasis web atau stateless Pod yang tidak menggunakan persistent volume besar dan dapat membuat koneksi ulang secara mandiri ketika node dimatikan kapan saja, penggunaan Spot instance sangat disarankan. Kubernetes dirancang dengan arsitektur berorientasi ketersediaan tinggi (High Availability), sehingga sangat cocok menggunakan Spot instance. Banyak perusahaan kini telah aktif menerapkan Spot instance pada lingkungan operasional produksi mereka. Secara pribadi, fleksibilitas dalam memaksimalkan Spot instance ini merupakan salah satu keunggulan terbesar dari EKS.

  • . spec.requirements.consolidation.enabled: true

Ketika jumlah Pod yang berjalan di suatu node berkurang, Karpenter secara otomatis melakukan konsolidasi (consolidation) atau memindahkan Pod ke node lain untuk memangkas biaya. Berbeda dengan CAS, Karpenter bahkan dapat menyesuaikan tipe instans yang baru diluncurkan dan menempatkan Pod baru ke node yang paling hemat biaya.

Selanjutnya adalah manifes AWSNodeTemplate. Bagian ini menetapkan konfigurasi AWS yang diperlukan untuk menjalankan node di luar tipe hardware, seperti konfigurasi volume storage, Security Group, dan Subnet.

AWSNodeTemplate

apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    karpenter.sh/discovery: jerry-test
  securityGroupSelector:
    karpenter.sh/discovery: jerry-test
  tags:
    karpenter.sh/discovery: jerry-test
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 100Gi
        volumeType: gp3
        encrypted: true
        deleteOnTermination: true
  • . spec.subnetSelector, securityGroupSelector

AWSNodeTemplate mewajibkan penentuan informasi Subnet dan Security Group. Ini mendefinisikan informasi dasar di lingkungan mana node akan diluncurkan.

Karpenter mengalokasikan resource berdasarkan informasi tag pada Subnet dan Security Group. Saat modul Karpenter diinstal, tag akan secara otomatis ditambahkan ke Subnet dan Security Group sesuai nama klaster.

Informasi tag ini dapat dipastikan melalui AWS Console seperti di bawah ini:

Pencarian Karpenter

Ketik “karpenter” pada kolom pencarian Security Group seperti gambar di atas untuk melihat resource terkait. Saat memeriksa tag, datanya sama persis dengan yang diisikan pada AWSNodeTemplate di atas.

Tag Karpenter pada Security Group

Sama halnya dengan Security Group, Anda juga dapat menemukan tag identik pada Subnet.

Tag Karpenter pada Subnet

Node yang diluncurkan oleh Karpenter akan diberikan alokasi Security Group dan Subnet yang memiliki tag karpenter seperti di atas.

  • . spec.subnetSelector.Name: “jerry-test-private-ap-northeast-2*”

Node EKS sangat disarankan untuk di-deploy ke dalam Private Subnet demi alasan keamanan dan biaya. Anda dapat menentukan nama tag Private agar node berjalan di Private Subnet. Sintaks wildcard * juga didukung, sehingga Anda tidak perlu menuliskan ap-northeast-2a/2b/2c satu per satu secara manual.

  • . spec.blockDeviceMappings

Anda dapat memodifikasi konfigurasi disk node. Penulis menetapkan ukuran disk default sebesar 100Gi guna menjaga kestabilan operasional.

Buat CRD Karpenter berdasarkan manifes yang telah disiapkan:

$ (⎈ |switch-singapore-test:karpenter) k apply -f provisioner.yaml -f awsNodeTemplate.yaml
provisioner.karpenter.sh/spot created
awsnodetemplate.karpenter.k8s.aws/default created

$ (⎈ |switch-singapore-test:karpenter) k get provisioners.karpenter.sh
NAME   AGE
spot   85s

$ (⎈ |switch-singapore-test:karpenter) k get awsnodetemplates.karpenter.k8s.aws
NAME      AGE
default   94s

Dua CRD baru, yaitu provisioner dan awsnodetemplate, telah berhasil dibuat dan diverifikasi.

4. Praktik Node Autoscaling Menggunakan Karpenter

Untuk memantau node yang diluncurkan oleh Karpenter secara mudah, kita akan memasang eks-node-viewer. eks-node-viewer adalah tool berbasis CLI yang dikembangkan oleh AWS untuk memvisualisasikan perubahan dan alokasi resource node secara dinamis. Tool ini dapat diinstal dengan mudah menggunakan brew:

brew tap aws/tap
brew install eks-node-viewer

Selanjutnya, jalankan eks-node-viewer.

Satu node t3a.large sedang berjalan menggunakan spot instance

Seperti terlihat pada tangkapan layar, eks-node-viewer menampilkan status node klaster secara intuitif. Informasi tipe instans, status spot/on-demand, hingga estimasi biaya dapat dipantau langsung. Selain itu, rasio kapasitas alokasi node (Capacity) dibandingkan dengan total permintaan resource Pod yang sedang berjalan (Request) disajikan dalam persentase (%). Dengan begitu, efektivitas alokasi resource dapat dinilai dengan cepat.

Satu hal yang perlu diperhatikan adalah adanya tiga metrik resource yang dihitung berdasarkan alokasi request Pod, bukan pemakaian riil (Usage). Pertama, Capacity adalah total kapasitas fisik resource yang dapat digunakan oleh node. Kedua, Request adalah total jumlah resource request dari seluruh Pod yang dialokasikan di node tersebut. Ketiga, Usage adalah konsumsi riil resource yang sedang digunakan oleh Pod saat itu, yang bisa saja lebih rendah atau lebih tinggi daripada nilai request (meski tetap tidak bisa melampaui limit). Meningkatkan rasio request terhadap capacity berarti memanfaatkan resource node secara jauh lebih efisien.

Selain itu, eks-node-viewer juga memungkinkan Anda melihat waktu yang dibutuhkan saat proses provisi node berlangsung secara aktual.

Sekarang, mari kita deploy node baru menggunakan Karpenter dan pantau perubahannya melalui eks-node-viewer. Praktik ini bertujuan untuk memverifikasi bagaimana Karpenter secara otomatis melakukan penambahan node berdasarkan resource request dari Pod. Berikut adalah manifes Pod yang digunakan:

busybox deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox
  namespace: default
spec:
  replicas: 4
  selector:
    matchLabels:
      app: busybox # Cocokkan dengan label POD
  template:
    metadata:
      labels:
        app: busybox # Cocokkan dengan selector label
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["sh"]
        args: ["-c", "sleep inf"]
        resources:
          requests:
            cpu: 400m
            memory: 128Mi
  • . spec.template.spec.resources.requests

Karpenter menjalankan node baru dengan mengacu pada batas permintaan (requests) CPU dan Memori dari Pod. Karpenter akan memilih instans dengan biaya termurah di antara opsi node yang mampu memenuhi kebutuhan request tersebut. Pada contoh di atas, node yang diluncurkan harus mencukupi total resource (400m * 4 = 1600m CPU, 128Mi * 4 = 512Mi Memori).

Bagi jendela terminal menjadi dua: jalankan deploy Pod busybox di terminal atas, dan jalankan eks-node-viewer di terminal bawah.

$ (⎈ |switch-singapore-test:default) k apply -f busybox-deploy.yaml
deployment.apps/busybox created

Anda dapat melihat durasi kesiapan node secara real-time seperti yang tampak di bawah ini. Waktu yang dibutuhkan hingga node baru berhasil ditambahkan adalah 40 detik. Jika menggunakan Cluster Autoscaler (CAS) konvensional, proses ini memakan waktu lebih dari 2 menit; ini berarti Karpenter sekitar 70% lebih cepat.

Node t3.small selesai disiapkan dalam waktu 38 detik

Ketika tipe node diperiksa, tipe yang dipilih adalah t3.small. Karena kebutuhan resource Pod adalah gabungan dari CPU 400m * 4 dan Memori 128Mi * 4, Karpenter secara otomatis memilih tipe EC2 paling hemat biaya dari daftar node group yang ditentukan pada Karpenter Provisioner.

Jika menggunakan Cluster Autoscaler versi lama, sistem akan mengalokasikan tipe instans tunggal tetap yang sudah ditentukan pada node group (misalnya c6i.large) tanpa memedulikan seberapa kecil resource request dari Pod, yang akhirnya berujung pada pemborosan biaya.

Selanjutnya, kita lakukan pengujian sebaliknya yaitu pengurangan jumlah node (Scale-In). Buka dua jendela terminal dan hapus Pod deployment pada salah satu jendela:

$ (⎈ |switch-singapore-test:default) k delete deployments.apps busybox

Ketika Pod dihapus, node ikut terhapus dalam waktu sekitar 10 detik seperti yang terlihat pada tangkapan layar. Kecepatan ini pun jauh melampaui performa CAS. Karpenter beroperasi sangat cepat karena mengelola node secara langsung tanpa melalui perantara Auto Scaling Group (ASG).

Log penambahan dan pengurangan node dapat dipantau langsung pada pod Karpenter:

$ (⎈ |switch-singapore-test:default) k logs -n karpenter karpenter-f654d4b8d-v65dk
2023-05-24T00:50:00.733Z INFO controller.provisioner.cloudprovider launched instance {"commit": "698f22f-dirty", "provisioner": "default", "id": "i-0f7c4e1e1e28aea85", "hostname": "ip-10-110-25-141.ap-southeast-1.compute.internal", "instance-type": "t3.micro", "zone": "ap-southeast-1b", "capacity-type": "spot", "capacity": {"cpu":"2","ephemeral-storage":"100Gi","memory":"947Mi","pods":"4"}}

(dilewati / disingkat)

2023-05-24T01:00:13.982Z INFO controller.deprovisioning deprovisioning via consolidation delete, terminating 8 machines ip-10-110-24-178.ap-southeast-1.compute.internal/t3.micro/spot, ip-10-110-27-116.ap-southeast-1.compute.internal/t3.2xlarge/spot, ip-10-110-1-0.ap-southeast-1.compute.internal/t3.2xlarge/spot, ip-10-110-22-211.ap-southeast-1.compute.internal/t3.micro/spot, ip-10-110-17-156.ap-southeast-1.compute.internal/t3.micro/spot, ip-10-110-25-158.ap-southeast-1.compute.internal/t3.micro/spot, ip-10-110-12-187.ap-southeast-1.compute.internal/t3.2xlarge/spot, ip-10-110-25-141.ap-southeast-1.compute.internal/t3.micro/spot {"commit": "698f22f-dirty"}
2023-05-24T01:00:14.052Z INFO controller.termination cordoned node {"commit": "698f22f-dirty", "node": "ip-10-110-24-178.ap-southeast-1.compute.internal"}

(dilewati / disingkat)

Proses penambahan dan pengurangan node dapat dipantau secara transparan melalui log. Jika menemui kendala terkait penambahan atau pengurangan node di lapangan, Anda dapat meninjau log pada pod Karpenter untuk mengidentifikasi akar penyebabnya.

Demikian pembahasan mengenai Karpenter. Pada artikel berikutnya, kita akan membahas opsi terminationGracePeriodSeconds dan PodDisruptionBudget agar deployment Pod menggunakan Karpenter dapat berlangsung dengan lebih aman.

0 CommentsClose Comments

Leave a comment

Newsletter Subscribe

Get the Latest Posts & Articles in Your Email

We Promise Not to Send Spam:)