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 khai requests, LimitRange khai hộ, và bốn loại giới hạn

Quota bắt buộc mọi pod phải khai requests

Namespace có ResourceQuota với requests.cpurequests.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"}}

ResourceQuotaLimitRange đ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: 5scale --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: 1p1 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 RoleRoleBinding (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õ.