Metrics, Traces và API Priority and Fairness
Bài 65 lo log — sự kiện rời rạc. Quan sát còn cần số liệu liên tục: bao nhiêu request đang chạy, độ trễ ra sao, có pod nào restart. Kubernetes phơi những thứ đó qua endpoint /metrics. Bài này xem metrics ấy, rồi đào sâu một cơ chế vừa là observability vừa là tự vệ: API Priority and Fairness, thứ ta đã thoáng thấy trong log apiserver ở Bài 65.
Endpoint /metrics
apiserver và kubelet đều phơi /metrics ở định dạng Prometheus — text thuần, mỗi dòng một số đo kèm nhãn:
kubectl get --raw /metrics | grep -E "apiserver_current_inflight_requests|apiserver_request_total" | head
apiserver_current_inflight_requests{request_kind="mutating"} 0
apiserver_current_inflight_requests{request_kind="readOnly"} 1
apiserver_request_total{code="0",resource="pods",subresource="exec",verb="CONNECT",version="v1"} 18
apiserver_current_inflight_requests đếm request đang xử lý theo loại, apiserver_request_total là bộ đếm tích lũy chia theo resource/verb/mã trả về. kubelet có bộ riêng:
kubectl get --raw /api/v1/nodes/worker-0/proxy/metrics | grep kubelet_running_containers
kubelet_running_containers{container_state="created"} 1
kubelet_running_containers{container_state="exited"} 6
kubelet_running_containers{container_state="running"} 14
Đây là dữ liệu thô; Prometheus (hoặc tương đương) cào định kỳ rồi lưu chuỗi thời gian để vẽ biểu đồ và cảnh báo. Bản thân Kubernetes không lưu metrics — như log, nó chỉ phơi ra, phần thu thập là hệ thống ngoài. (metrics-server ở Bài 39 là chuyện khác: nó cào một tập nhỏ để phục vụ HPA, không phải kho metrics đầy đủ.)
API Priority and Fairness
apiserver có ngân sách request giới hạn. Nếu một controller lỗi quay vòng gọi API dồn dập, nó có thể chiếm hết ngân sách và làm leader-election, node heartbeat đói theo — cụm mất ổn định. APF (ổn định từ 1.29) chống điều đó: phân loại request vào nhiều mức ưu tiên, mỗi mức có hạn đồng thời riêng, để một luồng hỗn không bóp nghẹt luồng khác.
Hai loại object điều khiển nó. PriorityLevelConfiguration định nghĩa các mức và phần băng thông mỗi mức:
kubectl get prioritylevelconfigurations
NAME TYPE NOMINALCONCURRENCYSHARES QUEUES HANDSIZE QUEUELENGTHLIMIT
catch-all Limited 5 <none> <none> <none>
exempt Exempt <none> <none> <none> <none>
leader-election Limited 10 16 4 50
node-high Limited 40 64 6 50
system Limited 30 64 6 50
workload-high Limited 40 128 6 50
workload-low Limited 100 128 6 50
FlowSchema quyết request nào vào mức nào, theo người gửi/resource, và tách thành các luồng (theo user hoặc namespace):
kubectl get flowschemas
NAME PRIORITYLEVEL MATCHINGPRECEDENCE DISTINGUISHERMETHOD
exempt exempt 1 <none>
probes exempt 2 <none>
system-leader-election leader-election 100 ByUser
system-nodes system 500 ByUser
kube-controller-manager workload-high 800 ByNamespace
kube-scheduler workload-high 800 ByNamespace
Đọc một dòng: request leader-election khớp FlowSchema system-leader-election (precedence 100, ưu tiên hơn precedence cao), vào mức leader-election, tách luồng ByUser. Mức exempt đặc biệt, bỏ qua mọi giới hạn, dành cho health check và request sống còn (probes, exempt). Cụm không cần cấu hình gì: bộ FlowSchema và PriorityLevelConfiguration này dựng sẵn.
Trạng thái sống của APF
apiserver phơi trạng thái APF qua một endpoint debug — thấy ngay mức nào đang bận, có request nào bị từ chối:
kubectl get --raw /debug/api_priority_and_fairness/dump_priority_levels
PriorityLevelName, ..., ExecutingRequests, DispatchedRequests, RejectedRequests, ...
catch-all, ..., 0, 7, 0,
exempt, ..., 1, 15451, 0,
leader-election, ..., 0, 39746, 0,
node-high, ..., 0, 2479, 0,
DispatchedRequests cho thấy phân bổ tải thật: leader-election đã xử lý 39746 request, exempt 15451 (health check liên tục). Cột đáng canh là RejectedRequests, đang 0 ở mọi mức, nghĩa là cụm chưa quá tải. Khi một mức bão hòa và hàng đợi đầy, request mới nhận 429 Too Many Requests và số này tăng ở đúng mức đó — chỉ ra ngay luồng nào đang gây áp lực, thay vì để cả apiserver chậm đều. Đây là chỗ APF vừa bảo vệ vừa quan sát được: không chỉ chặn quá tải mà còn nói cho biết quá tải ở đâu.
Traces
Mảnh thứ ba của observability là tracing — theo một request qua các thành phần để tìm chỗ chậm. apiserver và kubelet hỗ trợ xuất trace theo OpenTelemetry, bật qua --tracing-config-file. Cụm này không bật:
ssh controller-0 'grep -c tracing-config-file /etc/systemd/system/kube-apiserver.service'
0
Khi bật, apiserver gửi span tới một OTel collector, và ta thấy được, ví dụ, một request CREATE pod tốn thời gian ở admission webhook (Bài 58) hay ở etcd. Trace bù cho metrics: metrics nói có chậm, trace nói chậm ở đâu. Cụm tự dựng để mặc định tắt vì nó cần một collector ngoài; bật là thêm --tracing-config-file trỏ tới collector đó.
🧹 Dọn dẹp
Bài này chỉ đọc endpoint /metrics, object APF dựng sẵn, và endpoint debug — không tạo gì. Không có gì để dọn. Lệnh dùng trong bài ở github.com/nghiadaulau/kubernetes-from-scratch, thư mục 66-metrics-apf.
Tổng kết
Observability của Kubernetes ba mảnh. Metrics: apiserver và kubelet phơi /metrics định dạng Prometheus (apiserver_request_total, kubelet_running_containers...), bản thân cụm không lưu — Prometheus ngoài cào và giữ chuỗi thời gian. API Priority and Fairness vừa bảo vệ apiserver vừa quan sát được: PriorityLevelConfiguration chia ngân sách request thành các mức (system, leader-election, workload-high/low, catch-all, exempt), FlowSchema phân request vào mức theo người gửi/resource và tách luồng, và endpoint /debug/api_priority_and_fairness cho thấy DispatchedRequests/RejectedRequests từng mức — 429 ở một mức chỉ thẳng luồng gây tải. Traces (OTel, --tracing-config-file) theo request qua các thành phần để chỉ chỗ chậm, mặc định tắt vì cần collector ngoài. Cả ba đều phơi-tại-cụm, thu-ở-ngoài — đúng triết lý của Kubernetes về observability.
Bài 67 khép Part XIII bằng các cơ chế vận hành còn lại: leader election giữ cho controller-manager và scheduler chỉ có một bản chủ động trong HA, cách quản addon, và node autoscaling — cụm tự thêm/bớt node theo tải.