AWS Thai Blog
จัดการค่าใช้จ่ายของ Kubernetes compute ของคุณให้เหมาะสมด้วย Karpenter consolidation
บทนำ
Karpenter ถูกสร้างมาเพื่อช่วยแก้ปัญหาเกี่ยวกับการเลือก node ที่เหมาะสมที่สุดใน Kubernetes รูปแบบของ Karpenter คือ คุณต้องการอะไร เมื่อไหร่ที่คุณต้องการ (what-you-need-when-you-need-it) ช่วยทำให้กระบรวนการจัดการทรัพยากร compute ใน Kubernetes ทำได้ง่ายขึ้น โดยการเพิ่ม Compute capacity ไปที่ Cluster ของคุณตามความต้องการของ Pod จากการออก release ล่าสุดของการรวบรวม workload (workload consolidation) ตอนนี้ Karpenter สามารถเปิดใช้งานการมอนิเตอร์อย่างต่อเนื่องและการกำหนดการสร้าง Pod ได้อย่างเหมาะสม เพื่อที่จะใช้ทรัพยากรได้อย่างเหมาะสมและลดค่าใช้จ่ายของ compute
บทความนี้แปลมาจาก Optimizing your Kubernetes compute costs with Karpenter consolidation โดยคุณ Lukonde Mwila
ในบทความนี้จะบรรยายถึงความสามารถของ Karpenter consolidation และรายละเอียดของ และจัดการค่าใช้จ่ายของ Data plane ใน Kubernetes ให้เหมาะสมและตัวอย่างการใช้งาน
Karpenter’s workload consolidation
ในเวอร์ชันก่อนหน้านี้ Karpenter ทำการลบการติดตั้ง (de-provision) Worker node ที่ไม่มี Pod ที่ไม่ใช่ Daemonset เท่านั้น เมื่อเปิดใช้งานและ Workload ถูก reschedule ไปเรื่อยๆ ทำให้บาง Worker node อาจใช้งานได้ไม่เต็มประสิทธิภาพ ทำให้ Workload consolidation มีเป้าหมายที่จะปรับปรุง vision ของ Karpenter ให้มีประสิทธิภาพดีขึ้น และการทำ Auto scaling ให้มีค่าใช้จ่ายน้อยที่สุดโดยการรวม workload ให้มีจำนวนน้อยที่สุด ค่าใช้จ่ายต่อ instance น้อยที่สุด ในขณะที่ยังคงยึดตามทรัพยากรของ Pod และข้อจำกัดของการ schedule ต่างๆ Workload consolidation สามารถเปิดใช้งานโดยใช้ Provisioner ซึ่งเป็น Custom Resource Definition (CRD) ของ Karpenter หน้าที่ของ Provisioner คือการจัดการออกคำสั่งใน lifecycle ของ Karpenter ที่ควบคุม Node ใน Cluster ทำให้เราสามารถที่จะกำหนดข้อจำกัดของ capacity รวมถึง พฤติกรรม (เช่น expiration และ consolidation) ของ Node ที่ได้ทำการสร้าง
เมื่อเปิดใช้งานใน Provisioner Karpenter จะทำการมอนิเตอร์ workload ของ cluster ของคุณอย่างต่อเนื่อง เพื่อมองหาโอกาสที่จะรวบรวม compute capacity เพื่อที่จะ utilize node ให้ดีขึ้นรวมถึงค่าใช้จ่ายด้วย Karpenter ยังคงคำนึงถึงข้อจำกัดของการทำ scheduling อื่นๆ (any scheduling constraints) ที่คุณได้ระบุไว้ เช่น pod affinity rules หรือ topology spread constraints เป็นต้น) เนื่องจาก Karpenter ทำการสร้าง node จากความต้องการของ Workload ซึ่งมีความสำคัญที่จะต้องระบุสิ่งเหล่านี้ไว้ ในการทำสิ่งนี้ คุณควรระบุทั้งความต้องการใช้งานของ central processing unit (CPU) และ memory ของ pod ของคุณ ซึ่งจะช่วยป้องกันไม่ให้ทรัพยากรขาดแคลน (starvation) หรือใช้งานมากจนเกินไป (hogging) โดยเฉพาะอย่างยิ่งเมื่อมีการใช้งานหลาย ๆ Workload ใน Cluster นอกจากนี้มันคือข้อกำหนดที่สำคัญที่จะทำให้ฟีเจอร์ Workload consolidation ของ Karpenter ทำงานได้อย่างมีประสิทธิภาพ
สิ่งที่ต้องเตรียมก่อนเริ่มต้น (Prerequisites)
ในการที่จะทำตามบทความนี้ คุณจะต้องทำการติดตั้งสิ่งต่างๆเหล่านี้:
- สร้าง Kubernetes cluster ใน AWS
- ติดตั้ง Karpenter สำหรับ Cluster autoscaling
- ติดตั้ง Amazon Elastic Kubernetes Service (Amazon EKS) Node Viewer
ในการที่จะติดตั้งได้อย่างอัตโนมัติ คุณสามารถใช้ Amazon EKS blueprints สำหรับ Terraform ซึ่งมีตัวอย่างในการติดตั้ง Karpenter เป็น add-on สำหรับ Cluster ของคุณ คุณไม่จำเป็นต้องปรับเปลี่ยนซอร์สโค้ด ของ Terraform ในการที่จะทำตามตัวอย่างของบทความนี้
Provisioners
Karpenter ควบคุม Node จาก Provisioner Custom Resource Definition (CRD) ซึ่ง Provisioner คือไฟล์ configuration ที่มีหน้าที่ในการตัดสินใจในเรื่องต่างๆไม่ว่าจะเป็นชนิดของ Computing capacity, ชนิดของ Instance, Configuration เพิ่มเติมของ Kubelet, พารามิเตอร์ของ Resource, และการระบุ lifecycle ต่างๆของ Node คุณสามารถติดตั้ง Provisioner CRDs หลายๆตัวที่ Cluster ของคุณขึ้นอยู่กับการใช้งานของแต่ล่ะ User ตราบเท่าที่ยังไม่เกิดการทับซ้อนกัน
Amazon EKS blueprints มีตัวอย่างของ Provisioners อยู่ในโฟลเดอร์ /karpenter/provisioners ในตัวอย่างเราจะใช้ 1 Provisioner สำหรับ Node.js แอปพลิเคชันชื่อว่า express-test โดย Pod ของแอปพลิเคชันจะไม่ถูก schedule สร้างขึ้นมานอกจาก Provisioner จะถูกติดตั้งแยกไปที่ cluster
ตัวอย่างของไฟล์ของ Provisioner:
Provisioner
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: express-test
spec:
# 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
requirements:
- 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"]
- key: "karpenter.k8s.aws/instance-cpu"
operator: In
values: ["c", "m", "r"]
provider:
instanceProfile: KarpenterNodeInstanceProfile-alpha
subnetSelector:
karpenter.sh/discovery: 'alpha'
securityGroupSelector:
karpenter.sh/discovery/alpha: 'alpha'
labels:
managedBy: carpenter
คุณสามารถบันทึกไฟล์นี้และติดตั้งลงใน Cluster ของคุณโดยใช้คำสั่งนี้
kubectl apply -f provisioner.yaml
อธิบายโดยละเอียด
ตัวอย่างการทำ Workload consolidation
ในหัวข้อนี้ เราจะติดตั้งแอปพลิเคชัน express-test ด้วยหลายๆ replicas ซึ่งในแต่ละ pod จะมี 1 CPU core และมีข้อจำกัดให้กระจายไปแต่ล่ะ Zone (zonal topology spread constraint) ในการทำสิ่งเหล่านี้ workload manifest จะกำหนดเงื่อนไขในการเลือก node (node selector) สำหรับ Pod ที่จะทำการ schedule ตัว Compute ที่ถูกจัดการโดย Provisioner ที่เราสร้างขึ้นมาในขั้นตอนก่อนหน้านี้ หลังจากที่ตรวจดูการทำงานของ Karpenter provision ในการเริ่มต้นสร้างกลุ่มของ node เราจะทำการปรับเปลี่ยน Deployment โดยจะเปลี่ยนจำนวนของ replica และตรวจดูการทำงานของ Karpenter consolidation ที่จะตอบสนองการเปลี่ยนแปลงในครั้งนี้
manifest ของ แอปพลิเคชันถูกระบุตามตัวอย่างโค้ดด้านล่าง
Manifest ของแอปพลิเคชัน
apiVersion: apps/v1
kind: Deployment
metadata:
name: express-test
spec:
replicas: 20
selector:
matchLabels:
app: express-test
template:
metadata:
labels:
app: express-test
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: express-test
nodeSelector:
karpenter.sh/provisioner-name: express-test
containers:
- name: express-test
image: lukondefmwila/express-test:1.1.4
resources:
requests:
cpu: "1"
memory: "64Mi"
คุณสามารถบันทึกไฟล์นี้และติดตั้ง Deployment ลงใน Cluster ของคุณโดยใช้คำสั่งนี้
kubectl apply -f deployment.yaml
หลังจากนั้น คุณสามารถดูการใช้งาน Compute และค่าใช้จ่ายของ Karpenter node โดยใช้ Amazon EKS Node Viewer
Karpenter ได้ทำการเพิ่ม 3 nodes (2 x t3.2xlarge instances และ 1 x c6a.2xlarge) ไปที่ cluster ของเรา เพื่อเติมเต็มตามความต้องการที่ระบุใน Manifest ซึ่งจะบริหารจัดการทั้งความต้องการของ Compute และทำตาม Schedule constrains Spot instance เหล่านี้มี 8 CPU cores และแต่ละ Node ถูกสร้างโดยกระจายไปแต่ละ availability zone (AZ) ทั้ง eu-west-1a, eu-west-1b, และ eu-west-1c Karpenter สร้าง Node ที่ต้องการ 1 CPU core สำหรับ 20 replicas (กระจายระหว่าง AZs) ควบคู่ไปกับการใช้งาน CPU ของ Daemonset และทรัพยากรที่ถูกจองโดย Kubelet
ตามที่เราเห็นในรูปภาพด้านบน เครื่องมือ CLI ของ eks-node-viewer แสดงค่าใช้จ่ายต่อเดือนสำหรับการติดตั้ง Node ในแบบปัจจุบัน
ในขั้นตอนต่อไปจะเป็นการเปลี่ยน Manifest ของ Deployment เริ่มต้น ตามที่แสดงด้านล่าง เราลดจำนวน Replica ของ Pod ลงจาก 20 เป็น 10 ซึ่งทำให้การขอใช้ทรัพยากรลงน้อยลงตามไปด้วย
Manifest ของแอปพลิเคชัน
apiVersion: apps/v1
kind: Deployment
metadata:
name: express-test
spec:
replicas: 10
...
คุณสามารถอัพเดตการเปลี่ยนแปลงนี้ลงใน Cluster ของคุณโดยใช้คำสั่ง kubectl apply -f deployment.yaml อีกครั้ง.
ในขณะนี้ Node ต่าง ๆ ของเราใช้งานได้ไม่เต็มประสิทธิภาพ (underutilized) เพราะก่อนหน้านี้ Karpenter ทำการเพิ่ม 3 nodes โดยการประมาณ 8 CPUs ในแต่ละ Node เพื่อให้เหลือพร้อมใช้งานสำหรับ 20 replicas ในตอนนี้วิธีการเดียวที่จะลดค่าใช้จ่ายของ Cluster คือการลด Node ที่ใช้งานไม่เต็มประสิทธิภาพออก ในขั้นแรก Pod จะถูกให้ทำการ isolate และ drain ถ้าคุณทำการมอนิเตอร์ Node ต่อไปเรื่อย ๆ คุณจะเห็นว่ามีเหตุการณ์เหล่านี้เกิดขึ้นและในท้ายที่สุด Pod ที่ถูก schedule ไปสร้างที่ 2 Spot instances ที่เหลืออยู่ ซึ่งผลลัพทธ์ที่ได้ในการเปลี่ยนแปลงเหล่านี้จะเป็นไปตามรูปภาพที่ปรากฎทางด้านล่าง
ตามที่ผลลัพธ์แสดงถึงการเปิดใช้งาน Consolidation ทำให้ Karpenter สามารถปรับการใช้งาน Compute ของ Cluster ให้เหมาะสม โดยการลดจำนวน Instance ลง 1 จาก 3 Instance ในขณะที่ยังคงสามารถรองรับความต้องการของทรัพยากรได้และทำตามข้อจำกัดในการกระจายสำหรับรองรับ Workload ของแอปพลิเคชันของเราได้ ค่าใช้จ่ายของ Data plane สำหรับ Workload นี้ลดลงตามที่แสดงในรูปภาพด้านบน.
สำหรับใน Production environment นั้น เราแนะนำให้ใช้เครื่องมือ เช่น kubecost ควบคู่ไปกับ Karpenter เพื่อมอนิเตอร์และจัดการค่าใช้จ่ายของ Kubernetes คุณสามารถทำตามวิธีการนี้ในการติดตั้ง kubecost สำหรับการมอนิเตอร์ค่าใช้จ่ายของ Amazon EKS
Cleanup
เพื่อหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติม กรุณาอย่าลืมลบ Infrastructure ที่คุณสร้างในตัวอย่างนี้ ขั้นตอนแรก คุณต้องลบ Node ที่ถูกสร้างโดย Karpenter ซึ่ง Node เหล่านี้ถูกจัดการโดย Provisioner CRD ซึ่งคุณสามารถลบทรัพยากรนี้จาก Kubernetes cluster ของคุณ หลังจากนั้น คุณสามารถลบ infrastructure ที่เหลือโดยใช้ Terraform กรุณาตรวจสอบอีกครั้งว่าคุณอยู่ในโฟลเดอร์ที่ถูกต้องก่อนที่จะใช้คำสั่ง terraform destroy คุณสามารถทำตามวิธีการ clean up สำหรับ Amazon EKS blueprints
บทสรุป
ในบทความนี้ เราได้แสดงให้คุณเห็นถึงวิธีการในการรวมฟีเจอร์ใหม่ของ Karpenter คือ Workload consolidation และทำตาม practices ที่ดีในการใช้งานทรัพยากรตามความต้องการที่จะช่วยให้คุณลดค่าใช้จ่ายของ Data plane ใน Kubernetes ของคุณ
นี้คือตัวอย่างเพิ่มเติมที่เกี่ยวกับหัวข้อนี้:
Karpenter สำหรับ Kubernetes | Karpenter vs Cluster Autoscaler
Karpenter consolidation ใน Kubernetes
เรียนรู้เพิ่มเติมเกี่ยวกับ Karpenter คุณสามารถอ่านบทความและเข้าร่วมกลุ่ม community ของ Kubernetes slack channel ได้ที่ #karpenter.