Chuyện gì đang xảy ra
Pod của bạn đã bị kẹt ở trạng thái Pending một lúc rồi. Khi kiểm tra bằng kubectl describe, bạn thấy nội dung tương tự như sau:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 30s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
Kubernetes scheduler đã kiểm tra toàn bộ 3 node. Không node nào có đủ CPU trống để đáp ứng yêu cầu của pod. Vì vậy nó từ bỏ và để pod tiếp tục chờ.
Lỗi này khác với CrashLoopBackOff (pod khởi động nhưng bị crash) hay ImagePullBackOff (không kéo được image). Ở đây pod chưa bao giờ được khởi động — nó bị kẹt ngay ở bước lên lịch, trước khi bất kỳ container nào chạy.
Tái hiện và chẩn đoán
Bước 1: Xác nhận lỗi
kubectl describe pod <pod-name> -n <namespace>
Cuộn xuống phần Events ở cuối. Bạn sẽ thấy cảnh báo FailedScheduling:
0/3 nodes are available: 3 Insufficient cpu.
Bước 2: Kiểm tra lượng CPU pod đang yêu cầu
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].resources}'
Hoặc xem trực tiếp trong file YAML Deployment của bạn:
resources:
requests:
cpu: "2000m" # ← đây là giá trị scheduler dùng để tìm node phù hợp
limits:
cpu: "4000m"
Scheduler dùng requests, không phải limits, để đưa ra quyết định đặt pod. Một request 2000m nghĩa là mỗi node phải có 2 core trống — đó là yêu cầu khá lớn.
Bước 3: Kiểm tra dung lượng thực tế và CPU có thể phân bổ của node
kubectl describe nodes | grep -A 5 'Allocatable\|Allocated resources'
Để xem gọn hơn:
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEMORY:.status.allocatable.memory
Sau đó đi sâu vào từng node để xem những gì đã được phân bổ:
kubectl describe node <node-name> | grep -A 10 'Allocated resources'
Ví dụ kết quả đầu ra:
Allocated resources:
(Total limits may be over 100 percent, i.e., no guarantee)
Resource Requests Limits
-------- -------- ------
cpu 1850m (92%) 3200m (160%)
memory 1Gi (55%) 2Gi (110%)
Với 92% đã được phân bổ, một pod mới yêu cầu dù chỉ 200m cũng sẽ không vừa. Đơn giản là không còn chỗ nữa.
Giải pháp
Tùy chọn 1: Giảm CPU request của pod (cách sửa nhanh)
Hầu hết các trường hợp, request chỉ đơn giản là được đặt quá cao. Hãy giảm xuống mức thực tế theo mức ứng dụng thực sự dùng khi khởi động.
resources:
requests:
cpu: "100m" # giảm từ 2000m
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
Một lỗi thường gặp: đặt requests.cpu: "2" (2 core đầy đủ) trong khi ứng dụng chỉ đạt đỉnh 200m. Limit có thể giữ cao. Request chỉ cần là ước tính trung thực về mức sử dụng thông thường — không phải trường hợp xấu nhất, không phải kỳ vọng lý tưởng.
Áp dụng thay đổi:
kubectl apply -f your-deployment.yaml
Tùy chọn 2: Scale up cluster (thêm node)
Đôi khi request thực sự đúng và bạn chỉ cần thêm dung lượng. Thêm node là cách sửa trực tiếp nhất.
GKE:
gcloud container clusters resize <cluster-name> \
--node-pool <pool-name> \
--num-nodes 5 \
--region <region>
EKS (managed node group):
aws eks update-nodegroup-config \
--cluster-name <cluster-name> \
--nodegroup-name <nodegroup-name> \
--scaling-config minSize=2,maxSize=10,desiredSize=5
On-premise: cấp phát một VM mới và thêm vào cluster bằng kubeadm join.
Tùy chọn 3: Bật Cluster Autoscaler
Người dùng cloud có một lựa chọn thông minh hơn: Cluster Autoscaler. Nó tự động cấp phát node mới mỗi khi scheduler không thể đặt pod — không cần can thiệp thủ công.
# Kiểm tra xem autoscaler đã chạy chưa
kubectl get pods -n kube-system | grep cluster-autoscaler
Chưa cài đặt? Triển khai nó (ví dụ cho GKE với Workload Identity):
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/gce/examples/cluster-autoscaler-autodiscover.yaml
Sau đó annotate node group của bạn để autoscaler biết nó đủ điều kiện để scale.
Tùy chọn 4: Evict hoặc scale down các workload khác
Tìm hiểu xem cái gì đang chiếm CPU trên toàn cluster:
kubectl top nodes
kubectl top pods --all-namespaces --sort-by=cpu | head -20
Các deployment nhàn rỗi hoặc replica quá mức thường là thủ phạm. Scale chúng xuống để giải phóng tài nguyên:
kubectl scale deployment <other-deployment> --replicas=1 -n <namespace>
Tùy chọn 5: Kiểm tra LimitRange có đang áp dụng giá trị mặc định lớn không
Một pod không có block resources sẽ nhận request bằng không từ Kubernetes — điều đó tự nó không gây ra lỗi này. Nhưng một LimitRange trong namespace có thể tự động inject một giá trị mặc định lớn.
kubectl get limitrange -n <namespace>
kubectl describe limitrange <name> -n <namespace>
Đặt request tường minh trong pod spec để ghi đè bất cứ thứ gì LimitRange đang inject.
Xác minh bản sửa lỗi
Sau khi áp dụng thay đổi, theo dõi pod trực tiếp:
kubectl get pods -n <namespace> -w
Bạn sẽ thấy: Pending → ContainerCreating → Running — thường trong vòng một đến hai phút.
Xác nhận không còn lỗi scheduling nữa:
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 Events
Không có sự kiện FailedScheduling nào nghĩa là bạn đã xong.
Bài học rút ra
- Đặt request thực tế, không phải trường hợp xấu nhất. Scheduler đưa ra quyết định đặt pod thực sự dựa trên
requests. Yêu cầu 4 core trong khi bạn chỉ dùng 200m lãng phí dung lượng được dự trữ trên mỗi node trong cluster. - Requests và limits có vai trò khác nhau.
requests= những gì scheduler dự trữ lúc đặt pod.limits= ngưỡng cứng được áp dụng lúc runtime. Giữ request thấp và thực tế; đặt limit ở mức tối đa thực tế bạn có thể chấp nhận. kubectl top nodeshiển thị mức sử dụng, không phải phân bổ. Một node có thể hiển thị 30% CPU usage nhưng có tới 95% CPU được request. Scheduler làm việc dựa trên requests, không phải mức sử dụng thời gian thực. Luôn kiểm trakubectl describe nodevà xem phần Allocated resources — đó mới là con số quan trọng.- Cluster Autoscaler hoàn vốn rất nhanh. Nếu bạn đang dùng hạ tầng cloud và gặp lỗi này nhiều hơn một lần, autoscaler loại bỏ hoàn toàn nút thắt cổ chai thủ công. Hãy thiết lập nó trước khi cần đến.

