Модуль 17 / 19
Metrics, logs, Events і спостережуваність
Зміст
1. Цілі та результат модуля
Ви навчитеся зіставляти metrics, logs, Events та object status у часі, розуміти джерело кожного сигналу й не вважати kubectl top повноцінною системою моніторингу.
- metrics показують числову поведінку
- logs пояснюють події застосунку
- Events фіксують рішення control plane і kubelet
- status відбиває поточне спостереження controller
- єдина часова шкала перетворює сигнали на evidence
2. Теорія: сигнали спостережуваності
Metrics придатні для trends, rates, saturation та alerts; logs — для контексту виконання; traces пов’язують шлях запиту; Events пояснюють недавні Kubernetes transitions. Один сигнал рідко доводить root cause.
Observability починається з питання та гіпотези, а не з dashboard. Спершу визначають expected behavior, часовий інтервал, об’єкт і межу системи.
3. Metrics API та metrics-server
metrics-server отримує resource metrics від kubelet і публікує aggregated API metrics.k8s.io для autoscaling та kubectl top. Він зберігає лише свіжий зріз CPU/memory і не є Prometheus, TSDB чи системою довгострокової аналітики.
kubectl top показує usage, а describe node — requests/limits. Ці числа відповідають на різні питання й мають різні timestamps/windows.
4. API aggregation і TLS
APIService спрямовує metrics.k8s.io до Service metrics-server. Доступність залежить від aggregation layer, Service endpoints, RBAC і scrape kubelet. На стенді kubelet certificate не має IP SAN, тому сувора TLS-перевірка ламає scrape.
--kubelet-insecure-tls припустимий лише як lab workaround. Production потребує довірених kubelet serving certificates; вимкнення перевірки приховує підміну endpoint.
5. Container logs та їх межі
kubectl logs читає CRI-managed stdout/stderr обраного container. Для multi-container Pod вказують -c або --all-containers; --previous звертається до попереднього container instance; --since, --tail і --timestamps обмежують вибірку.
Logs локальні та підлягають rotation/GC. Після reschedule, видалення Pod чи cleanup runtime previous log може бути відсутнім. Production потребує node-level collector і зовнішнє сховище з retention.
6. Events, status і часова шкала
Events — namespaced API objects із reason, reporting controller, involved object та серіями повторів. Вони корисні для FailedScheduling, image pull, probe, mount і BackOff, але мають обмежений retention і не є audit log.
Сортування за creationTimestamp допомагає, але repeated series і різні годинники Nodes потребують обережності. Для кореляції синхронізуйте час і фіксуйте UTC timestamps.
7. Методичні вказівки
- Починайте з object status і часового вікна
- Порівнюйте usage з requests/limits, не змішуючи їх
- Вказуйте container явно
- Використовуйте timestamps, since та tail
- Читайте Events разом із logs
- Перевіряйте APIService/Service/endpoints при збої top
- Не використовуйте insecure TLS у production
- Не вважайте Events чи kubectl logs архівом
8. Лабораторна робота: Metrics API
Установіть фіксований metrics-server v0.9.0. Спочатку збережіть x509 evidence, потім застосуйте лише лабораторний workaround і дочекайтеся Available APIService.
curl -fsSL https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.9.0/components.yaml \
-o /tmp/metrics-server-v0.9.0.yaml
kubectl apply --dry-run=server -f /tmp/metrics-server-v0.9.0.yaml
kubectl apply -f /tmp/metrics-server-v0.9.0.yaml
kubectl -n kube-system rollout status deployment/metrics-server --timeout=60s || true
kubectl get apiservice v1beta1.metrics.k8s.io
kubectl -n kube-system logs deployment/metrics-server --tail=40
# Только для этой лаборатории: kubelet certificate не содержит IP SAN.
kubectl -n kube-system patch deployment metrics-server --type=json -p='[
{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}
]'
kubectl -n kube-system rollout status deployment/metrics-server --timeout=120s
kubectl wait --for=condition=Available apiservice/v1beta1.metrics.k8s.io --timeout=120s
kubectl top node9. Лабораторна робота: спостережуваний workload
Multi-container Pod пише відмінні stdout/stderr, а crashloop навмисно завершується з 17. Requests/limits дають контекст resource metrics.
mkdir -p /tmp/k8s-m17
cat > /tmp/k8s-m17/workload.yaml <<'EOF'
apiVersion: v1
kind: Namespace
metadata: {name: k8s-m17}
---
apiVersion: v1
kind: Pod
metadata: {name: observable, namespace: k8s-m17, labels: {app: observable}}
spec:
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "i=0; while true; do i=$((i+1)); echo level=info component=app iteration=$i; [ $((i%5)) -eq 0 ] && echo level=warn component=app iteration=$i >&2; sleep 2; done"]
resources: {requests: {cpu: 10m, memory: 8Mi}, limits: {cpu: 100m, memory: 32Mi}}
- name: sidecar
image: busybox:1.37
command: ["sh", "-c", "while true; do echo level=info component=sidecar; sleep 5; done"]
resources: {requests: {cpu: 5m, memory: 4Mi}, limits: {cpu: 50m, memory: 16Mi}}
---
apiVersion: v1
kind: Pod
metadata: {name: crashloop, namespace: k8s-m17, labels: {app: crashloop}}
spec:
containers:
- name: app
image: busybox:1.37
command: ["sh", "-c", "echo start attempt; sleep 3; echo deliberate exit >&2; exit 17"]
EOF
kubectl apply -f /tmp/k8s-m17/workload.yaml || true
kubectl apply --dry-run=server -f /tmp/k8s-m17/workload.yaml
kubectl apply -f /tmp/k8s-m17/workload.yaml
kubectl -n k8s-m17 wait --for=condition=Ready pod/observable --timeout=120s10. Лабораторна робота: metrics і logs
Порівняйте Node, Pod і container usage, потім raw Metrics API з timestamp/window. Дослідіть логи за container та спільною вибіркою.
sleep 20
kubectl top node
kubectl top pod -n k8s-m17
kubectl top pod -n k8s-m17 --containers
kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq '.items[] | {name:.metadata.name, timestamp, window, usage}'
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/k8s-m17/pods | jq '.items[] | {pod:.metadata.name, containers:.containers}'
kubectl describe node | sed -n '/Allocated resources:/,/Events:/p'kubectl -n k8s-m17 logs observable -c app --tail=10 --timestamps
kubectl -n k8s-m17 logs observable --all-containers=true --prefix --tail=20
kubectl -n k8s-m17 logs observable -c app --since=30s
kubectl -n k8s-m17 logs observable -c app -f
# Остановите follow через Ctrl+C.
kubectl -n k8s-m17 get pod crashloop -o jsonpath='phase={.status.phase}{" restarts="}{.status.containerStatuses[0].restartCount}{" waiting="}{.status.containerStatuses[0].state.waiting.reason}{" lastReason="}{.status.containerStatuses[0].lastState.terminated.reason}{" exit="}{.status.containerStatuses[0].lastState.terminated.exitCode}{"\n"}'
kubectl -n k8s-m17 logs crashloop -c app --timestamps
kubectl -n k8s-m17 logs crashloop -c app --previous --timestamps || true11. Events і діагностика розривів сигналу
Зберіть BackOff Events, terminated state, kubelet journal і runtime container list. Previous log може бути недоступним після CRI cleanup — не вигадуйте його вміст.
kubectl -n k8s-m17 get events --sort-by=.metadata.creationTimestamp
kubectl -n k8s-m17 get events --field-selector involvedObject.name=crashloop --sort-by=.metadata.creationTimestamp
kubectl -n k8s-m17 describe pod crashloop
kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -30
sudo journalctl -u kubelet --since '10 minutes ago' --no-pager | tail -80
sudo crictl --runtime-endpoint unix:///run/containerd/containerd.sock ps -a --name crashloop
kubectl -n kube-system logs deployment/metrics-server --since=10m --tail=80Для збою top: APIService condition → metrics-server Pod/logs → Service/EndpointSlice → kubelet reachability/certificate → RBAC. Для CrashLoop: status/exit → Events → current/previous logs → config/resources/dependencies.
kubectl get apiservice v1beta1.metrics.k8s.io -o yaml
kubectl -n kube-system get deployment,pod,service,endpointslice -l k8s-app=metrics-server
kubectl -n kube-system get deployment metrics-server -o jsonpath='{.spec.template.spec.containers[0].args}{"\n"}'
kubectl -n kube-system logs deployment/metrics-server --tail=50
kubectl top pod -n namespace-does-not-exist 2>&1 || true
kubectl -n k8s-m17 get pod crashloop -o yaml
kubectl -n k8s-m17 get events --field-selector involvedObject.name=crashloop --sort-by=.metadata.creationTimestamp
kubectl -n k8s-m17 logs crashloop --previous 2>&1 || true12. Контроль, критерії засвоєння та cleanup
- metrics-server зберігає history?
- Usage дорівнює request?
- Що робить APIService?
- Чому IP SAN важливий?
- Коли потрібен -c?
- Що означає --previous?
- Чому previous log може зникнути?
- Events дорівнюють audit log?
- Навіщо синхронізація часу?
- Як відрізнити відсутність metrics від нульового usage?
kubectl delete namespace k8s-m17 --wait=true
rm -rf /tmp/k8s-m17
# metrics-server остаётся инфраструктурой следующих лабораторий.
kubectl get apiservice v1beta1.metrics.k8s.io
kubectl top nodeМодуль засвоєно, якщо ви будуєте часову шкалу CrashLoop зі status, Events і logs та локалізуєте відмову Metrics API за шарами.