Karpenter - Opensource ที่เพิ่มประสิทธิภาพของ Kubernetes Cluster Auto Scal
Tags: kubernetes, beginners, opensource, aws
Published: 2022-06-03 07:37:02

Karpenter คือโอเพ่นซอร์สทำหน้าที่เป็นตัวปรับขนาดคลัสเตอร์บน Kubernetes ที่มีความยืดหยุ่นและมีประสิทธิภาพสูงใช้งานได้บน AWS หน้าที่ของ Karpenter จะช่วยปรับปรุงความพร้อมใช้งานของแอปพลิเคชั่นและประสิทธิภาพของคลัสเตอร์ครับ โดย Karpenter จะเรียกใช้ทรัพยากรที่มีขนาดเหมาะสมเพื่อตอบสนองความต้องการของแอปพลิเคชั่นให้มากที่สุดเพื่อเพิ่มความเร็วในการ Launch ทรัพยากรต่างๆให้ทันท่วงทีและเพื่อลดค่าใช้จ่ายและเพิ่มประสิทธิภาพในการทำ Auto scaling

ก่อนการมาของ Karpenter หากผู้ใช้ต้องการที่จะปรับความสามารถในการทำ scaling บน Kubernetes คลัสเตอร์จำเป็นต้องใช้ Amazon EC2 Autoscaling ควบคู่กันกับ Kubernetes Cluster Autoscaler เพื่อรองรับการทำ dynamic scaling ของคลัสเตอร์โดยลูกค้าที่ใช้งาน Kubernetes เกือบครึ่งบน AWS รายงานว่าการกำหนดค่าการปรับขนาดคลัสเตอร์โดยใช้ Kubernetes Cluster Autoscaler (CA) นั้นทำได้ยากและมีข้อจำกัดเยอะ

การที่จะเริ่มต้นใช้งาน Karpenter ได้ ผู้ใช้จำเป็นต้องติดตั้ง Karpenter ไปที่คลัสเตอร์และหลังจากนั้น Karpenter จะทำการสังเกต request ของ Unschedule pod ผ่าน event ภายในคลัสเตอร์และทำการตัดสินใจที่จะ launch หรือ terminate ตัว compute node ในที่นี้หมายถึง Amazon EC2 เพื่อลด scheduling latency และลดราคาระบบโครงสร้างพื้นฐาน


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jbgk8tfc4zkg180l15v.png)

Karpenter เป็นโปรเจคโอเพ่นซอร์สภายใต้ Apache License 2.0 ได้รับการออกแบบมาเพื่อทำงานร่วมกับ Kubernetes ในทุกสภาพแวดล้อมรวมไปถึงผู้ให้บริการคลาวด์รายใหญ่ทั้งและดาต้าเซนเตอร์ภายในองค์กร หากผู้ใช้ต้องการใช้งาน Karpenter และ contribute ไปที่โปรเจคหรือมีคำถามหรือข้อแนะนำ สามารถติดต่อแล้วพูดคุยกับเราได้ที่ Github

**<u>เริ่มต้นใช้งาน Karpenter บน AWS</u>**
การเริ่มต้นใช้งาน Karpenter บน Kubernetes คลัสเตอร์ใดๆก็ตามจะเริ่มต้นจากการติดตั้ง Karpenter บนคลัสเตอร์ก่อนเป็นอันดับแรก แต่เมื่อจะทำการติดตั้งควรตรวจสอบให้มั่นใจก่อนว่ามีทรัพยากรของเครื่องเหลือให้ติดตั้งหรือไม่ โดยผู้ใช้สามารถติดตั้งผ่าน Helm chart ภายใน repository สาธารณะและเพิ่มสิทธิในการอนุญาตให้ Karpenter สามารถสร้างทรัพยากรอยู่บนคลาวด์ของคุณได้

เมื่อติดตั้ง Karpenter ในคลัสเตอร์ของคุณแล้ว Default Karpenter Provisioner จะทำการเริ่มมอนิเตอร์ Kubernetes พ็อทที่กำลังจะถูกสร้างขึ้นมาแต่ไม่สามารถ schedule ได้เนื่องจากทรัพยากรในเครื่องในคลัสเตอร์มีไม่เพียงพอ และหลังจากนั้น Karpenter จะทำการเปิดใช้ทรัพยากรใหม่และทำการเลือกเครื่องที่เหมาะกับพ็อตที่คลัสเตอร์กำลังจะสร้างให้มากที่สุดโดยอัตโนมัติ

หลังจากที่ได้ทำความรู้จักกับ Karpenter กันแล้วถัดไปเราจะลองใช้งาน Karpenter ใน Amazon EKS คลัสเตอร์โดยอ้างอิงจากไกด์ไลน์ในเอกสาร [Getting Started with Karpenter on AWS](https://karpenter.sh/v0.8.1/getting-started/) ซึ่งในไกด์ไลน์นี้เราจำเป็นต้องมี  [AWS Command Line Interface](https://aws.amazon.com/cli/) (AWS CLI), kubectl, eksctl และ Helm (แพ็คเกจเมเนเจอร์สำหรับ Kubernetes) หลังจากนั้นทำการสร้างคลัสเตอร์โดยใช้ eksctlโดยไฟล์คอนฟิกูเรชัน ตามตัวอย่างนี้มีการระบุค่าพื้นฐานตั้งต้นของคลัสเตอร์และทำการสร้างโหนดขึ้นมา 1 โหนด

```
cat <<EOF > cluster.yaml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: eks-karpenter-demo
  region: us-east-1
  version: "1.20"
managedNodeGroups:
  - instanceType: m5.large
    amiFamily: AmazonLinux2
    name: eks-kapenter-demo-ng
    desiredCapacity: 1
    minSize: 1
    maxSize: 5
EOF
$ eksctl create cluster -f cluster.yaml
```
 
โดยพื้นฐานแล้ว Karpenter สามารถรันได้ทุกที่ เช่น [self-managed node groups](https://docs.aws.amazon.com/eks/latest/userguide/worker.html), [managed node groups](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html) หรือ [AWS Fargate](https://aws.amazon.com/fargate/) เพราะว่า Karpenter จะสามารถสร้าง EC2 instace ขึ้นมาใน AWS แอคเคาท์ของคุณ

เมื่อได้ EKS คลัสเตอร์แล้วถัดไปทำการสร้าง สิทธิ์การใช้การและการเข้าถึง [AWS Identity and Access Management](https://aws.amazon.com/iam/) (IAM) ผ่าน [AWS CloudFormation template](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) และ [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) (IRSA) สำหรับ Karpenter controller เพื่อส่งผ่านสิทธิ์การใช้งานและการเข้าถึงไปให้ Karpenter ใช้ในการสร้าง EC2 instance [ตามเอกสารนี้](https://karpenter.sh/v0.10.1/getting-started/) โดยขั้นต้นเราจะทำการติดตั้ง Helm chart เพื่อที่จะติดตั้ง Karpenter ในคลัสเตอร์ตามลำดับ

```
$ helm repo add karpenter https://charts.karpenter.sh
$ helm repo update
$ helm upgrade --install --skip-crds karpenter karpenter/karpenter --namespace karpenter \
  --create-namespace --set serviceAccount.create=false --version 0.5.0 \
  --set controller.clusterName=eks-karpenter-demo \
  --set controller.clusterEndpoint=$(aws eks describe-cluster --name eks-karpenter-demo --query "cluster.endpoint" --output json) \
  --wait # for the defaulting webhook to install before creating a Provisioner
```

Karpenter ใช้ provisioner ในการกำหนดพฤติกรรมในการเพิ่มหรือลดจำนวนของโหนดภายในคลัสเตอร์ โดยผู้ใช้สามารถกำหนดคอนฟิกูเรชันของ provisioner ได้ผ่าน Kubernetes แต่โดยทั่วไป provisioner ที่ถูกสร้างขึ้นมาด้วยค่าตั้งต้นสามารถถูกนำไปใช้งานได้เลย โดยการทำงานของ Karpenter จะเริ่มจากการค้นหาคุณสมบัติของโหนดอัตโนมัติอ้างอิงจาก ประเภทอินสแตนซ์ โซน สถาปัตยกรรม ระบบปฏิบัติการ และหลังจากนั้น Karpenter จะทำการสร้างโหนดตามความต้องการของเวิร์คโหลด

```
cat <<EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
#Requirements that constrain the parameters of provisioned nodes. 
#Operators { In, NotIn } are supported to enable including or excluding values
  requirements:
    - key: "node.kubernetes.io/instance-type" #If not included, all instance types are considered
      operator: In
      values: ["m5.large", "m5.2xlarge"]
    - key: "topology.kubernetes.io/zone" #If not included, all zones are considered
      operator: In
      values: ["us-east-1a", "us-east-1b"]
    - key: "kubernetes.io/arch" #If not included, all architectures are considered
	  operator: In
      values: ["arm64", "amd64"]
    - key: " karpenter.sh/capacity-type" #If not included, the webhook for the AWS cloud provider will default to on-demand
      operator: In
      values: ["spot", "on-demand"]
  provider:
    instanceProfile: KarpenterNodeInstanceProfile-eks-karpenter-demo
  ttlSecondsAfterEmpty: 30  
EOF
```
ภายในตัวอย่างคอนฟิกูเรชันของ Karperter provisioner ค่าที่ _ttlSecondsAfterEmpty_ จะเป็นกำหนดเวลาและบอกให้ Karpenter ทำการลบโหนดที่ว่างอยู่ทิ้งออกไป แต่ในทางกลับกันถ้าค่า _ttlSecondsAfterEmpty_ ไม่ได้ถูกกำหนดขึ้นมาตัวโหนดเองจะไม่สามารถ scale-down ลงไปแม้ utilization จะต่ำก็ตามถ้าหากท่านใดสนใจเกี่ยวกับ Provisioner สามารถอ่านต่อได้ที่[ลิงค์นี้](https://karpenter.sh/v0.10.1/provisioner/)

หลังจากที่ Karpenter ทำงานและพร้อมใช้งานในคลัสเตอร์แล้ว เราจะเริ่มทำการสร้างพ็อตผ่านไฟล์ deployment ซึ่งหลักจากที่ Karpenter ทำการสร้างโหนดขึ้นมา ลองสังเกตุการทำงานของ Karpenter ในการสร้างโหนดครับ

```
$ kubectl create deployment inflate \
          --image=public.ecr.aws/eks-distro/kubernetes/pause:3.2 \
		  --requests.cpu=1
```

ถัดไปเราจะมาลองทำการ scale ผ่าน Karpenter และทำการสังเกต Log ของ Karpenter controller

```
$ kubectl scale deployment inflate --replicas 10
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:11.280Z        INFO    controller.allocation.provisioner/default       Starting provisioning loop      {"commit": "abc12345"}
2021-11-23T04:46:11.280Z        INFO    controller.allocation.provisioner/default       Waiting to batch additional pods        {"commit": "abc123456"}
2021-11-23T04:46:12.452Z        INFO    controller.allocation.provisioner/default       Found 9 provisionable pods      {"commit": "abc12345"}
2021-11-23T04:46:13.689Z        INFO    controller.allocation.provisioner/default       Computed packing for 10 pod(s) with instance type option(s) [m5.large]  {"commit": " abc123456"}
2021-11-23T04:46:16.228Z        INFO    controller.allocation.provisioner/default       Launched instance: i-01234abcdef, type: m5.large, zone: us-east-1a, hostname: ip-192-168-0-0.ec2.internal    {"commit": "abc12345"}
2021-11-23T04:46:16.265Z        INFO    controller.allocation.provisioner/default       Bound 9 pod(s) to node ip-192-168-0-0.ec2.internal  {"commit": "abc12345"}
2021-11-23T04:46:16.265Z        INFO    controller.allocation.provisioner/default       Watching for pod events {"commit": "abc12345"}

```

จะเห็นว่า controller ของ Karpenter provisioner จะทำการสังเกตการเปลี่ยนแปลงของพ็อตแล้วหลังจากนั้นจะทำการสร้างอินสแตนซ์ขึ้นมาและทำการผูกพ็อตเข้ากับโหนดที่ถูกสร้างขึ้นมา

ถัดไปเราจะลองทำการลบผ่าน deployment และหลังจาก 30วินาที (โดยการตั้งค่า _ttlSecondsAfterEmpty = 30_
 ) Karpenter ควรที่จะเริ่มทำการลบโหนดที่ไม่มีพ็อตทำงานอยู่ออกไปได้

```
$ kubectl delete deployment inflate
$ kubectl logs -f -n karpenter $(kubectl get pods -n karpenter -l karpenter=controller -o name)
2021-11-23T04:46:18.953Z        INFO    controller.allocation.provisioner/default       Watching for pod events {"commit": "abc12345"}
2021-11-23T04:49:05.805Z        INFO    controller.Node Added TTL to empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.823Z        INFO    controller.Node Triggering termination after 30s for empty node ip-192-168-0-0.ec2.internal {"commit": "abc12345"}
2021-11-23T04:49:35.849Z        INFO    controller.Termination  Cordoned node ip-192-168-116-109.ec2.internal   {"commit": "abc12345"}
2021-11-23T04:49:36.521Z        INFO    controller.Termination  Deleted node ip-192-168-0-0.ec2.internal    {"commit": "abc12345"}
```

แต่อย่างไรก็ดี ในกรณีที่ผู้ใช้เข้าไปลบโหนดด้วยตนเองผ่าน kubectl ตัว Karpenter เองก็จะเริ่มทำการ drain และลบอินสแตนส์ให้อัตโนมัติเช่นเดียวกัน โดย Karpenter จะทำการส่ง event เพื่อส่ง finalizer ไปยัง object ภายในโหนดที่ต้องการจะลบเพื่อป้องกันการลบอินสแตน์ก่อนที่พ็อตทุกตัวจะถูกการ drain ออกก่อนและท้ายที่สุด Karpenter ถึงจะเข้ากระบวนการ การลบอินสแตนส์ออกไป

**<u>สาระน่ารู้</u>**

Karpenter ยังมีฟีเจอร์ที่หลากหลาย สำหรับลูกค้าที่สนใจสามารถเรียนรู้เกี่ยวกับ ฟีเจอร์อื่นๆได้ครับ แต่ในบล็อคนี้เราจะทำการยกฟีเจอร์ที่น่าสนใจอย่างเช่น:

**Accelerated Computing:** Karpenter สามารถทำงานได้กับแอปพลิเคชั่นทุกประเภท แต่จะทำงานได้ดีเป็นพิเศษกับกรณีการใช้งานกับ workload ที่ต้องความรวดเร็วในการเพิ่มหรือลดจำนวนทรัพยากรคอมพิวเตอร์ที่มีขนาดใหญ่และมีความหลากหลาย ตัวอย่างเช่นการทำ batch job เพื่อเทรน machine learning โมเดล การรันsimulation ไปจนถึงการคำนวณทางการเงินที่มีความซับซ้อนและจำเป็นต้องใช้ทรัพยากรหลายๆประเภทในการทำงาน และท้ายที่สุดคุณสามารถเลือกใช้ทรัพยากรอื่นๆที่มีให้เลือกนอกเหนือจาก AWS ยกตัวอย่างเช่น Nvidia, AMD เป็นต้น

**Provisioners Compatibility:** Karpenter provisoner ได้รับการออกแบบมาเพื่อทำงานร่วมกับโซลูชั่นหลายประเภท ยกตัวอย่างเช่น Amazon EKS managed node groups และ EC2 Auto Scaling group แต่ที่นอกเหนือไปจากนั้นคือคุณสามารถ รวบรวมการทำงานของทั้ง 2 โซลูชั่นให้ทำงานร่วมกันเอที่จะรองรับการทำ scaling ได้ทั้งแบบ dynamic และ static ภายใต้คลัสเตอร์เดียวกัน

**<u>มาร่วมคอมมิวนี้ตี้กับเรา</u>**
คอมมิวนิตี้ของ Karpenter เปิดรับทุกคนที่สนใจเข้ามาเรียนรู้และ contribute ร่วมกันครับ สำหรับท่านที่สนใจสามารถเข้าร่วมคอมมิวนิตี้ของ Karpenter ได้ผ่าน[ลิงค์นี้](https://github.com/aws/karpenter/blob/main/WORKING_GROUP.md) โดยเราจะมีการจัดตั้งกลุ่มขึ้นมาสำหรับท่านที่สนใจเกี่ยวกับ Karpenter และฟีเจอร์ที่จะมีการปล่อยออกมาในอนาคต

ท้ายที่สุดนี้สำหรับลูกค้าที่สนใจและต้องการที่จะเรียนรู้เพิ่มเติมเกี่ยวกับ Karpenter สามารถเข้าไปดู [เอกสาร](https://karpenter.sh/v0.10.1/) และ [วิดีโอ](https://www.youtube.com/watch?t=19028&v=3f0Tv7IiQQw&feature=youtu.be) จาก AWS Container Day ได้ครับ