Namespace chia không gian tên (phần 59 đã đo: nó không chia không gian mạng). ResourceQuota là thứ biến nó thành ranh giới thật về tài nguyên. Bài này đo xem nó chặn được gì.
Quota bắt buộc mọi pod phải khai requests
Namespace có ResourceQuota với requests.cpu và requests.memory, rồi tạo deployment không khai gì:
deployment.apps/a created <- TẠO ĐƯỢC
số pod: 0 <- KHÔNG có pod nào
Error creating: pods "a-..." is forbidden: failed quota:
must specify requests.cpu for: nginx
Quota chặn ở tầng pod, không chặn ở tầng Deployment.
Đây là chỗ gây bối rối nhất: kubectl create deployment báo thành công, kubectl get deployment hiện 0/1, và không nói vì sao. Lý do nằm trong event của ReplicaSet:
kubectl -n <ns> get events --field-selector reason=FailedCreate
Tác dụng phụ này thực ra rất hữu ích: có quota về CPU hoặc RAM nghĩa là không pod nào trong namespace được phép thiếu requests — tức không còn BestEffort nào (phần 55).
LimitRange khai hộ
apiVersion: v1
kind: LimitRange
spec:
limits:
- type: Container
default: {cpu: 200m, memory: 256Mi}
defaultRequest: {cpu: 100m, memory: 128Mi}
Sau khi thêm, cùng deployment đó chạy được:
{"requests":{"cpu":"100m","memory":"128Mi"},
"limits":{"cpu":"200m","memory":"256Mi"}}
ResourceQuota và LimitRange đi với nhau: quota đòi phải khai, LimitRange khai hộ. Thiếu cái thứ hai là mọi deployment cũ trong namespace đều gãy ngay khi bạn bật quota.
Đây là thứ tự đúng khi áp quota lên namespace đang chạy: LimitRange trước, ResourceQuota sau.
Bốn loại giới hạn, bốn cách chặn
pods: 5 — scale --replicas=8 cho ra đúng 5 pod. Deployment không báo lỗi, chỉ đơn giản không đủ bản.
count/deployments.apps: 2
tạo deployment b -> created
tạo deployment c -> forbidden: exceeded quota
Lỗi hiện ngay trên kubectl, khác hẳn trường hợp pod.
persistentvolumeclaims: 1 — p1 tạo được, p2 bị từ chối ngay.
requests.cpu / requests.memory — cộng dồn của mọi pod:
đã dùng: requests.cpu=500m requests.memory=640Mi pods=5
Nguyên tắc chung rút ra:
Giới hạn trên object báo lỗi ngay cho người gõ lệnh. Giới hạn trên pod báo lỗi trong event của ReplicaSet — chỗ ít ai nhìn.
Nên với namespace dùng chung, đặt cả hai loại: count/deployments.apps cho phản hồi nhanh, và requests.cpu cho giới hạn thật.
Quota tính theo requests, không theo mức dùng
requests.cpu: 2 nghĩa là tổng requests của mọi pod không vượt 2 nhân — không liên quan tới CPU thật sự dùng.
Đây là hệ quả trực tiếp của phần 47: bộ lập lịch cũng cộng requests. Một namespace khai requests thừa sẽ chạm quota trong khi CPU thật gần như rỗi.
Đó là lý do VPA ở chế độ Off (phần 67) rất hữu ích với môi trường có quota: nó cho bạn con số requests gần đúng, và đó là tiền thật.
Xoá quota là bỏ giới hạn ngay lập tức
xoá ResourceQuota -> tạo deployment e -> created
số pod sau khi xoá quota: 7
Không có giai đoạn chuyển tiếp. Pod đang bị chặn được tạo ngay.
Điều đó cũng có nghĩa: ai có quyền xoá ResourceQuota thì quota không giới hạn được họ. Phần sau về RBAC là nửa còn lại của bài toán.
Namespace giới hạn được gì, không giới hạn được gì
Có:
- Tài nguyên tính toán, qua
ResourceQuota - Số lượng object
- Phân quyền, qua
RolevàRoleBinding(phần sau) - Chính sách mạng, qua
NetworkPolicy(phần 59)
Không:
- Mạng — mặc định mọi pod gọi được mọi pod xuyên namespace (phần 59)
- Node — pod của hai namespace nằm chung node và tranh CPU thật
- Tên node, PV, StorageClass, ClusterRole — đây là object cấp cụm, không thuộc namespace nào
Vế thứ hai đáng nhớ: hai đội trong hai namespace vẫn ảnh hưởng lẫn nhau qua tài nguyên node. ResourceQuota chỉ giới hạn requests, còn một pod dùng vượt requests vẫn ăn CPU của hàng xóm (phần 53).
Muốn cách ly thật thì cần node riêng — taint cộng nodeSelector (phần 69).
Ba loại object nên đặt quota
Ngoài CPU và RAM, hai loại hay bị bỏ sót:
spec:
hard:
count/secrets: "50"
services.nodeports: "0"
services.loadbalancers: "2"
services.nodeports: "0" chặn hẳn việc mở cổng trên node — thứ mà một Service NodePort vô tình có thể phơi ra Internet.
services.loadbalancers chặn chi phí: mỗi LoadBalancer trên đám mây là một hoá đơn.
Thử ba mươi giây
Xem namespace nào của bạn không có giới hạn nào:
for ns in $(kubectl get ns -o name | cut -d/ -f2); do
q=$(kubectl -n $ns get resourcequota --no-headers 2>/dev/null | wc -l)
l=$(kubectl -n $ns get limitrange --no-headers 2>/dev/null | wc -l)
[ "$q" = "0" ] && echo "$ns quota=$q limitrange=$l"
done
Mỗi dòng là một namespace mà một deployment gõ nhầm replicas: 1000 sẽ chạy tới khi hết cụm.
Phần sau đo RBAC: quyền đọc Secret nghĩa là đọc được mật khẩu ở dạng rõ.