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
| 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
-
requestscó đủ trên mọi container — thiếu làBestEffort, bị đuổi đầu tiên (12) -
readinessProbecó — đâ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) -
preStopchờ vài giây — bịt khe hở giữaSIGTERMvà 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
allocatablekháccapacitybao nhiêu trên cụm của bạn (55) -
--dry-run=serverchodraintừ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/pkicũng được sao lưu — nó không nằm trong snapshot (49)
Quan sát
- Log được gom ra ngoài —
kubectl logsmấ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ùngusage(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: falsecho 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ằngwarn(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 có 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.