← К программе курса

Модуль 17 / 19

Metrics, logs, Events и наблюдаемость

KUBERNETES

Содержание
01

1. Цели и результат модуля

Вы научитесь сопоставлять metrics, logs, Events и object status во времени, понимать источник каждого сигнала и не принимать kubectl top за полноценную систему мониторинга.

  • metrics показывают числовое поведение
  • logs объясняют события приложения
  • Events фиксируют решения control plane и kubelet
  • status отражает текущее наблюдение controller
  • единая временная шкала превращает сигналы в evidence
02

2. Теория: сигналы наблюдаемости

Metrics подходят для trends, rates, saturation и alerts; logs — для контекста конкретного выполнения; traces связывают путь запроса между компонентами; Events объясняют недавние Kubernetes transitions. Один сигнал редко доказывает root cause.

Observability начинается с вопроса и гипотезы, а не с установки dashboard. Сначала определяют expected behavior, временной интервал, объект и границу системы.

03

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.

04

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.

05

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 или быстрой очистки runtime previous log может отсутствовать. Production требует node-level collector и внешнее хранилище с retention.

06

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.

07

7. Методические указания

  • Начинайте с object status и временного окна
  • Сравнивайте usage с requests/limits, не смешивая их
  • Указывайте container явно
  • Используйте timestamps, since и tail
  • Читайте Events вместе с logs
  • Проверяйте APIService/Service/endpoints при сбое top
  • Не используйте insecure TLS в production
  • Не считайте Events или kubectl logs долговременным архивом
08

8. Лабораторная работа: Metrics API

Установите фиксированный metrics-server v0.9.0. Сначала сохраните x509 evidence, затем примените только лабораторный workaround и дождитесь Available APIService.

terminal
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 node
09

9. Лабораторная работа: наблюдаемый workload

Multi-container Pod пишет различимые stdout/stderr, а crashloop намеренно завершается с 17. Requests/limits дают контекст для resource metrics.

terminal
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=120s
10

10. Лабораторная работа: metrics и logs

Сравните Node, Pod и container usage, затем посмотрите raw Metrics API с timestamp/window. Исследуйте логи по container и общей выборкой.

terminal
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'
terminal
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 || true
11

11. Events и диагностика разрывов сигнала

Соберите BackOff Events, terminated state, kubelet journal и runtime container list. Previous log может быть недоступен после CRI cleanup — это не повод выдумывать его содержимое.

terminal
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.

terminal
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 || true
12

12. Контроль, критерии освоения и cleanup

  • metrics-server хранит history?
  • Usage равно request?
  • Что делает APIService?
  • Почему IP SAN важен?
  • Когда нужен -c?
  • Что означает --previous?
  • Почему previous log может исчезнуть?
  • Events равны audit log?
  • Зачем синхронизация времени?
  • Как отличить отсутствие metrics от нулевого usage?
terminal
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 по слоям.