Vấn đề của việc mở rộng quy mô truyền thống
Vận hành Kubernetes ở quy mô lớn thường là một cuộc chiến chống lại sự lãng phí. Bạn muốn ứng dụng luôn phản hồi nhanh, nhưng việc cấp dư tài nguyên (over-provisioning) lại dẫn đến hóa đơn AWS khổng lồ. Trong nhiều năm, Kubernetes Cluster Autoscaler (CA) là công cụ duy nhất cho công việc này. Nó giúp chúng ta duy trì hệ thống, nhưng chưa bao giờ thực sự nhanh hay thông minh.
Tôi đã trải qua nhiều ca trực căng thẳng, nhìn tỉ lệ lỗi tăng cao trong khi chờ Cluster Autoscaler phản ứng. Nó phải kích hoạt một AWS Auto Scaling Group (ASG), chờ instance EC2 khởi động, và cuối cùng là đăng ký node. Trong môi trường production bận rộn, bốn hoặc năm phút đó có thể dài như cả thế kỷ khi các pod vẫn ở trạng thái Pending.
Karpenter thay đổi cuộc chơi bằng cách loại bỏ khâu trung gian. Nó bỏ qua hoàn toàn Auto Scaling Groups và giao tiếp trực tiếp với EC2 Fleet API. Cách tiếp cận này giúp quản lý node nhanh hơn, linh hoạt hơn và rẻ hơn đáng kể.
Tại sao Karpenter vượt trội hơn Cluster Autoscaler
Để hiểu tại sao các đội ngũ kỹ thuật đang chuyển sang Karpenter, chúng ta phải xem xét sự thay đổi căn bản trong cách nó xử lý hạ tầng.
Bản chất phản ứng của CA
Cluster Autoscaler hoạt động thuần túy theo kiểu phản ứng. Khi phát hiện một pod “không thể lập lịch” (unschedulable), nó sẽ quét các Node Group hiện có. Nếu tìm thấy nhóm phù hợp, nó sẽ tăng “desired capacity” của ASG đó. Quy trình này rất cứng nhắc. Nếu pod của bạn cần một GPU cụ thể hoặc một instance bộ nhớ cao không nằm trong các nhóm đã xác định trước, CA đơn giản là không thể giúp gì được.
Cơ chế Just-in-Time của Karpenter
Karpenter mang tính chủ động và không theo nhóm (“group-less”). Nó đánh giá chính xác yêu cầu của các pod đang chờ—như CPU, RAM, kiến trúc (ARM64 so với x86), và Availability Zones. Sau đó, nó yêu cầu AWS cung cấp một instance duy nhất có chi phí tối ưu nhất phù hợp với các nhu cầu đó. Nếu một pod cần 2 vCPU, Karpenter sẽ không khởi chạy một instance m5.4xlarge 16 vCPU chỉ vì nó thuộc một nhóm có sẵn. Thay vào đó, nó có thể chọn một t3.medium, giúp bạn tiết kiệm khoảng 70% chi phí tính toán cho workload cụ thể đó.
Những sự đánh đổi: Liệu nó có phù hợp với bạn?
Lợi ích
- Tốc độ cực nhanh: Các node thường gia nhập cluster trong vòng 45-60 giây. CA thường mất 3-5 phút để hoàn thành cùng một tác vụ.
- Gom cụm (Bin-packing) quyết liệt: Karpenter liên tục tìm cách hợp nhất tài nguyên. Nó sẽ chuyển các pod sang một node nhỏ hơn và hủy node cũ nếu việc đó giúp tiết kiệm tiền.
- Cấu hình đơn giản hóa: Bạn có thể thay thế hàng chục Auto Scaling Group chuyên biệt bằng một cấu hình Karpenter duy nhất.
- Xử lý Spot thông minh hơn: Nó chủ động thay thế các Spot instance khi AWS gửi thông báo thu hồi (termination notice), thường là trước khi instance thực sự bị tắt.
Thách thức
- Tập trung vào AWS: Mặc dù dự án hướng tới mục tiêu đa nền tảng, nhưng các tính năng hoàn thiện nhất hiện tại chỉ dành riêng cho AWS.
- Thiết lập ban đầu: Việc cấu hình IAM roles và OIDC provider yêu cầu độ chính xác cao hơn là chỉ việc nhấn nút “Create Managed Node Group” trên console.
- API thay đổi nhanh: Karpenter đang phát triển rất nhanh. Bạn cần chú ý đến các bản cập nhật phiên bản vì một số cấu trúc (schema) cấu hình đã thay đổi gần đây.
Điều kiện tiên quyết
Trước khi bắt đầu di chuyển, hãy đảm bảo môi trường của bạn đáp ứng các yêu cầu sau:
- Kubernetes: Khuyến nghị phiên bản 1.25 trở lên.
- Môi trường: Một cluster Amazon EKS hiện có.
- Công cụ cục bộ:
helm,kubectl, vàaws-clibản mới nhất. - Quyền truy cập: Quyền Admin để tạo IAM roles và quản lý OpenID Connect (OIDC) providers.
Hướng dẫn cài đặt từng bước
Chúng ta sẽ tập trung vào việc triển khai Karpenter controller và thiết lập các quyền cần thiết. Hướng dẫn này giả định rằng bạn đang làm việc với một cluster EKS hiện có.
1. Cấp phát IAM Roles
Karpenter cần quyền để thay mặt bạn cấp phát các instance EC2. Bạn cần hai role riêng biệt: một cho các node mà Karpenter tạo ra và một cho chính controller.
# Tạo IAM Role cho các node
aws iam create-role --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--assume-role-policy-document file://node-trust-policy.json
# Gán các policy thiết yếu
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy --role-name "KarpenterNodeRole-${CLUSTER_NAME}" \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
2. Triển khai Controller bằng Helm
Sau khi các IAM role đã được ánh xạ, hãy sử dụng Helm để cài đặt controller. Thành phần này sẽ theo dõi API server để tìm các pod mà scheduler không thể lập lịch.
helm upgrade --install karpenter oci://public.ecr.aws/karpenter/karpenter \
--version v0.32.1 \
--namespace karpenter --create-namespace \
--set serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=${KARPENTER_IAM_ROLE_ARN} \
--set settings.aws.clusterName=${CLUSTER_NAME} \
--set settings.aws.defaultInstanceProfile=KarpenterNodeInstanceProfile-${CLUSTER_NAME} \
--wait
3. Định nghĩa NodePool
Đây là cốt lõi trong logic mở rộng của bạn. Trong phiên bản 0.32 trở lên, Karpenter sử dụng NodePool và EC2NodeClass. NodePool định nghĩa các ràng buộc cho các instance, trong khi EC2NodeClass xử lý các thiết lập mạng đặc thù của AWS.
Tạo file nodepool.yaml:
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: kubernetes.io/arch
operator: In
values: ["amd64", "arm64"]
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
nodeClassRef:
name: default
disruption:
consolidationPolicy: WhenUnderutilized
expireAfter: 720h
Và EC2NodeClass để liên kết các subnet của bạn:
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
name: default
spec:
amiFamily: AL2
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: ${CLUSTER_NAME}
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: ${CLUSTER_NAME}
4. Kiểm tra thiết lập
Để thấy Karpenter hoạt động, hãy thử mở rộng một deployment giả lập. Tôi khuyên bạn nên sử dụng image “pause”, loại image này tiêu tốn tài nguyên mà không thực hiện bất kỳ tác vụ nào.
kubectl create deployment inflate --image=public.ecr.aws/eks-distro/kubernetes/pause:3.7
kubectl scale deployment inflate --replicas=15
Theo dõi log: kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter. Bạn sẽ thấy Karpenter ngay lập tức tính toán khoảng trống tài nguyên và cấp phát một instance mới. Trong các thử nghiệm của tôi, node mới thường hiển thị trạng thái Ready trong lệnh kubectl get nodes trong vòng 40 giây.
Lời kết
Chuyển từ Cluster Autoscaler sang Karpenter giống như việc nâng cấp từ bản đồ giấy lên GPS thời gian thực. Bạn không còn phải quản lý từng nhóm server riêng lẻ mà bắt đầu định nghĩa nhu cầu của ứng dụng. Mặc dù việc thiết lập IAM ban đầu hơi phức tạp, nhưng thành quả nhận được là một cluster mở rộng nhanh hơn và tốn ít chi phí hơn. Đối với bất kỳ ai đang vận hành các workload production quan trọng trên EKS, Karpenter không còn chỉ là một lựa chọn thay thế—nó đã trở thành tiêu chuẩn hiện đại.

