Sáu mươi phần, mỗi phần một phép đo chạy trên cụm dựng bằng kind rồi xoá đi. Bài này gom lại thành thứ dùng được.

Mười con số đáng nhớ nhất, ba điều lặp lại nhiều nhất, và ba lần đo sai

Mười con số đáng nhớ nhất

Con số Ý nghĩa Phần
110 pod mỗi node, dù node to cỡ nào 55
145 Mi RAM mỗi pod nếu xếp đầy node 16 GB 55
1 MB trần một đối tượng; 262 KB nếu dùng apply 57
1 giờ hạn giữ sự kiện, không có bản sao ở đâu 41
0,26% phần dữ liệu volume nằm trong snapshot etcd 49
+31 giây activeDeadlineSeconds cộng thêm, không nhân 30
2,8 lần DNS nhanh lên khi thêm dấu chấm cuối 17
48% thông lượng mất khi bật Calico IPIP 20
8,6 lần HPA mở rộng nhanh hơn thu hẹp 26
159 giây commit → cụm đổi, nếu không có webhook 58

Con số hữu ích nhất trong bảng là 145 Mi: nó là thứ quyết định bạn nên mua node to hay node nhỏ, và gần như không ai tính nó.

Ba điều lặp lại ở nhiều phần nhất

1. Cột STATUS mô tả triệu chứng, không mô tả nguyên nhân.

CrashLoopBackOff có thể là container thoát mã 1, hoặc là container chưa từng chạy (phần 43). ContainerCreating trông như đang tiến triển nhưng có thể đứng vĩnh viễn. Running không có nghĩa là Ready.

Quy tắc rút ra: đừng bao giờ dừng ở cột STATUS. describe để xem sự kiện, lastState để xem lần chạy trước.

2. Đồ thị CPU và RAM mặc định đo nhầm thứ.

container_memory_usage_bytes gấp 30 lần working_set khi có bộ đệm tệp (phần 40). Đồ thị CPU không thấy pod bị bóp, vì pod bị bóp đúng là dùng ít CPU (phần 44).

Hai chỉ số đáng thay ngay: container_memory_working_set_bytes cho cảnh báo bộ nhớ, và tỷ lệ cfs_throttled_periods cho hiệu năng.

3. Cài một công cụ không tự nó bật bảo vệ.

Service mesh không chặn lưu lượng chưa tiêm (phần 53). Pod Security Standards phải gắn nhãn từng namespace (phần 34). NetworkPolicy không làm gì cho tới khi có pod khớp podSelector (phần 19).

Cả ba đều có cùng một dạng lỗi: cài xong, báo cáo "đã bảo vệ", và không có gì được bảo vệ cả.

Danh sách kiểm trước khi đưa lên chạy thật

Mỗi dòng đều dẫn về một phép đo trong sê-ri, không phải một lời khuyên chung chung.

Khối lượng công việc

  • requests có đủ trên mọi container — thiếu là BestEffort, bị đuổi đầu tiên (12)
  • readinessProbe có — đây mới là thứ cho triển khai không đứt quãng, không phải chiến lược cuộn (10)
  • preStop chờ vài giây — bịt khe hở giữa SIGTERM và lúc iptables cập nhật (37)
  • PID 1 không phải shell — kiểm bằng cat /proc/1/cmdline (37)
  • Không dùng latest; tốt nhất là ghim theo digest (56)

Node và cụm

  • Biết allocatable khác capacity bao nhiêu trên cụm của bạn (55)
  • --dry-run=server cho drain từng node — biết trước node nào làm bạn kẹt (51)
  • Snapshot etcd chạy được, và đã khôi phục thử một lần (49, 50)
  • /etc/kubernetes/pki cũng được sao lưu — nó không nằm trong snapshot (49)

Quan sát

  • Log được gom ra ngoài — kubectl logs mất sạch phần đã xoay vòng (39)
  • Sự kiện được gom ra ngoài, hoặc ít nhất có thói quen chụp lại khi có sự cố (41)
  • Cảnh báo dùng working_set, không dùng usage (40)
  • Có cảnh báo cho tỷ lệ bị bóp CPU, không chỉ cho mức CPU (44)

Bảo mật

  • automountServiceAccountToken: false cho pod không gọi API (33)
  • Mỗi ứng dụng có ServiceAccount riêng, không dùng default (33)
  • Namespace có nhãn pod-security.kubernetes.io/* — bắt đầu bằng warn (34)
  • readOnlyRootFilesystem: true ở nơi làm được (35)

Ba lần tôi công bố sai rồi phải sửa

Phần 2 — thời gian Kubernetes dựng lại pod sau khi node chết. Tôi suy ra từ dấu thời gian của một lần chạy đã bị nhiễm, viết "khoảng 360 giây", rồi vòng lặp chạy nền kết thúc và cho thấy sau 593 giây vẫn không có pod thay thế nào. Nguyên nhân thật: pod ma vẫn được tính là Ready nên ReplicaSet không làm gì.

Phần 19 — tôi viết rằng kindnet không thi hành NetworkPolicy và các phép đo chạy trên Calico. Cả hai đều sai: chúng chạy trên kindnet, và kindnet thi hành.

Phần 39 — tôi viết usedBytes của log là dung lượng tệp hiện tại. Nó là tổng cả tệp đã xoay vòng; một pod có 0.log rỗng vẫn báo 55,4 MB.

Cả ba đều lộ ra vì tôi chạy lại phép đo vài giờ sau, không phải vì có ai chỉ ra. Đó là lý do tôi giữ thói quen lặp lại mọi kết quả đi ngược trực giác ít nhất ba lần trước khi tin — và ba lần đó vẫn chưa đủ.

Điều còn lại sau sáu mươi phần

Không phải sáu mươi mẹo. Là một thói quen: đo trước khi tin, kể cả khi thứ bạn định tin là tài liệu chính thức, và đặc biệt khi nó là điều "ai cũng biết".

Ba phép đo trong sê-ri này bác bỏ những điều tôi tưởng là hiển nhiên: NET_BIND_SERVICE không cần thiết trong container (35), Kustomize không gọn hơn Helm (47), và restart: always của Docker không dựng lại container sau docker kill (59).

Cụm của bạn khác cụm của tôi: khác CNI, khác trình chạy container, khác phiên bản, khác quy mô. Mọi con số ở đây nên coi là giả thuyết cần kiểm lại. Mỗi phần đều kết thúc bằng một lệnh chạy được — đó mới là phần quan trọng.

Thử ba mươi giây

Lệnh cuối cùng của sê-ri, gộp bốn thứ hay sai nhất:

kubectl get pods -A -o json | python3 -c '
import sys, json
for p in json.load(sys.stdin)["items"]:
    m, s = p["metadata"], p["spec"]
    if m["namespace"].startswith("kube-"): continue
    thieu = []
    for c in s["containers"]:
        if not (c.get("resources") or {}).get("requests"): thieu.append("requests")
        if not c.get("readinessProbe"): thieu.append("readinessProbe")
        if not (c.get("lifecycle") or {}).get("preStop"): thieu.append("preStop")
        if ":" not in c["image"].rsplit("/", 1)[-1] or c["image"].endswith(":latest"):
            thieu.append("the-troi-noi")
    if thieu:
        print("%-40s thieu: %s" % (m["namespace"] + "/" + m["name"], ", ".join(sorted(set(thieu)))))
'

Chạy nó trên cụm của bạn ngay bây giờ. Danh sách in ra là những chỗ sê-ri này đã đo được hậu quả cụ thể — và với mỗi dòng, bạn biết chính xác nó sẽ hỏng thế nào.

Cảm ơn bạn đã theo hết sáu mươi phần.