Phần trước đo chi phí của một cụm thêm vào. Bài này đo chi phí bên trong một cụm: bao nhiêu tài nguyên biến mất trước khi ứng dụng đầu tiên chạy.

Chi phí cố định mỗi node, trần 110 pod, và con số capacity sai trên kind

Chi phí cố định của mỗi node

kubelet       108 MB
containerd     99 MB
              ------
              207 MB mỗi node

Hai tiến trình này chạy trên mọi node và không bao giờ tắt. Cụm 50 node là 10 GB RAM cho riêng hai thứ đó.

Cộng thêm phần chạy trong pod:

23 pod hệ thống toàn cụm    1.473 Mi
ảnh container trên 1 node    2,4 GB  (28 ảnh)

Con số 2,4 GB đáng để ý riêng, vì nó là đĩa, và nó chỉ tăng. kubelet tự dọn ảnh khi đĩa đầy tới ngưỡng, nhưng ngưỡng đó là 85% — nghĩa là bình thường bạn cứ tích ảnh cho tới lúc gần hết chỗ.

Một pod rỗng tốn gì

memory.current: 462.848 byte
pids.current:   2

Nửa megabyte và hai tiến trình cho một pod không chạy gì cả. Đó là container pause giữ chỗ các namespace của Linux.

Nhỏ, nhưng nhân với 110 pod thì thành 48 MB mỗi node chỉ để giữ chỗ. Và mỗi pod còn kéo theo vài chục quy tắc iptables, một mục trong danh sách của kubelet, một đối tượng trong etcd.

Trần thật không phải RAM mà là số pod

allocatable.pods = 110 trên MỌI node

Cả bốn node đều 110, dù mỗi node có 16 CPU và 16 GB.

Đây là mặc định của kubelet (--max-pods), không liên quan gì tới kích thước node. Hệ quả:

15.971 Mi / 110 pod = 145 Mi mỗi pod nếu xếp đầy

Nếu pod của bạn nhỏ hơn 145 MB thì bạn chạm trần số lượng trước khi chạm trần bộ nhớ, và phần RAM còn lại không dùng được vào việc gì.

Điều này đảo ngược một trực giác phổ biến: node to gấp đôi không cho gấp đôi số pod. Nó chỉ cho mỗi pod nhiều chỗ hơn. Với khối lượng công việc gồm nhiều pod nhỏ — hàng đợi, cron, microservice nhẹ — nhiều node nhỏ tận dụng tốt hơn ít node to.

Con số 110 nâng được, nhưng phải nâng có cân nhắc: mỗi pod thêm vào là thêm việc cho kubelet và thêm quy tắc iptables, và kube-proxy chậm dần khi số quy tắc lớn.

Con số hoàn toàn bịa, nếu bạn đo trên kind

cụm báo    62,4 GiB RAM, 64 CPU
máy thật   15,6 GiB RAM, 16 CPU

Cả bốn node đều báo 15971 Mi. Đó là cùng một 15,6 GB đếm bốn lần.

Nguyên nhân: mỗi node kind là một container, và một container nhìn thấy tài nguyên của cả máy chủ. Không có gì ngăn bốn node cùng khai rằng chúng có 16 GB.

Hậu quả thực tế: mọi kết quả xếp lịch đo trên kind đều lạc quan gấp bốn lần. Scheduler tin những con số đó, chấp nhận pod xin tổng cộng 60 GB, rồi máy thật bắt đầu tráo đổi trang nhớ. Phép thử "cụm chịu được bao nhiêu" chạy trên kind không nói lên gì về cụm thật.

Nó cũng giải thích một chuyện tôi gặp ở phần trước: pod xin 900 Gi bị từ chối với Insufficient memory, nhưng ranh giới bị từ chối nằm ở 16 GB mỗi node chứ không phải ở 15,6 GB toàn máy.

allocatable bằng capacity — và đó là bất thường

sc-worker   CPU 16 -> 16   RAM 15971 Mi -> 15971 Mi   (mất 0 Mi)

kind không đặt --kube-reserved hay --system-reserved, nên không giữ lại gì cho hệ thống. Toàn bộ RAM của node được coi là dùng được cho pod.

Cụm quản lý thật thì ngược lại: chúng giữ lại một phần đáng kể theo công thức bậc thang của nhà cung cấp, và phần đó không nhỏ. Đó là con số của nhà cung cấp, không phải con số tôi đo được ở đây — hãy đọc trên chính cụm của bạn:

kubectl get node <ten> -o jsonpath='{.status.capacity}{"\n"}{.status.allocatable}{"\n"}'

Chênh lệch giữa hai dòng là phần bạn trả tiền mà không dùng được. Trên cụm quản lý, con số đó thường làm người ta ngạc nhiên.

Gộp lại: tiền đi đâu

Khoản Đo được Ghi chú
kubelet + containerd 207 MB/node Cố định, không bao giờ tắt
Pod hệ thống 1.473 Mi Tăng theo số node (DaemonSet)
Ảnh container 2,4 GB/node Chỉ tăng cho tới ngưỡng dọn
Sandbox mỗi pod 0,44 MB × số pod
capacityallocatable 0 ở đây Đáng kể trên cụm quản lý
Trần 110 pod/node Chặn trước RAM với pod nhỏ

Bốn khoản đầu cộng lại là vài phần trăm của một node lớn, và một phần đáng kể của một node nhỏ. Đó là lý do node quá nhỏ không kinh tế: 207 MB trên node 2 GB là 10%, trên node 32 GB là 0,6%.

Còn hai dòng cuối thì không phải chi phí tài nguyên mà là chi phí quy hoạch — chúng làm cho con số bạn tưởng mình có khác con số bạn thật sự dùng được.

Chi phí không đo bằng byte

Ba khoản lớn nhất không hiện trong bất kỳ lệnh nào:

  • Người. Ai nâng cấp cụm, ai trực khi nó hỏng, ai đọc ghi chú phát hành của mỗi phiên bản.
  • Độ trễ chẩn đoán. Loạt bài này có bốn phần chỉ nói về việc tìm ra cái gì đang hỏng. Với một tiến trình chạy trên máy chủ thì pstail là đủ.
  • Số thứ phải học. Requests, limits, probe, PDB, RBAC, NetworkPolicy — mỗi cái là một chỗ để cấu hình sai theo cách im lặng.

Với ba dịch vụ và một cơ sở dữ liệu, ba khoản đó lớn hơn mọi lợi ích. Ranh giới thực dụng vẫn như ở các phần trước: Kubernetes đáng giá khi bạn có nhiều thứ giống nhau cần vận hành theo cùng một cách.

Thử ba mươi giây

Xem cụm của bạn còn thật sự bao nhiêu chỗ, tính cả trần số pod:

kubectl get nodes -o json | python3 -c '
import sys, json
def mi(s):
    return int(s[:-2]) / 1024 if s.endswith("Ki") else int(s[:-2])
for n in json.load(sys.stdin)["items"]:
    a = n["status"]["allocatable"]; c = n["status"]["capacity"]
    ram, pods = mi(a["memory"]), int(a["pods"])
    print("%-22s %6.0f Mi cho %3d pod  = %4.0f Mi/pod   (giu lai %.0f Mi)" % (
        n["metadata"]["name"], ram, pods, ram / pods, mi(c["memory"]) - ram))
'

Cột Mi/pod là con số quan trọng nhất và ít người biết. Nếu pod trung bình của bạn nhỏ hơn nó nhiều thì bạn đang trả tiền cho RAM sẽ không bao giờ dùng tới, và nên cân nhắc node nhỏ hơn hoặc nâng --max-pods.

Phần sau: bảo mật image và chuỗi cung ứng — đo việc quét và ký.