Перейти до вмісту

Модуль 5.7: Логування та моніторинг

Hands-On Lab Available
K8s Cluster intermediate 35 min
Launch Lab ↗

Opens in Killercoda in a new tab

Складність: [СЕРЕДНЯ] — базові навички спостережуваності.

Час на проходження: 40–50 хвилин.

Передумови: Модуль 5.1 (Методологія), Модулі 5.2–5.6 (конкретні випадки усунення несправностей).


Що ви зможете зробити

Розділ «Що ви зможете зробити»

Після цього модуля ви зможете:

  • Діагностувати журнали контейнерів за допомогою kubectl logs, використовуючи вибір контейнера, попередні журнали, режим стеження, мітки часу та селектори за лейблами.
  • Оцінювати події Kubernetes, щоб діагностувати збої планування, монтування, проб, перезапусків та витіснення, перш ніж сплине час зберігання подій.
  • Впроваджувати логування на основі sidecar для застосунків, які пишуть у файли замість stdout та stderr.
  • Спостерігати за використанням ресурсів через kubectl top, пояснюючи, як Metrics Server переносить метрики kubelet до API metrics.k8s.io.
  • Співвідносити журнали на рівні ноди, журнали контейнерів, події та метрики, щоб обрати наступну діагностичну дію під час сесії усунення несправностей у Kubernetes 1.35.

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

Hypothetical scenario: Деплоймент розгортається під час релізного вікна, нові Pod’и чергують між станами Running та CrashLoopBackOff, команда застосунку каже, що їхній endpoint справності пройшов перевірку в staging, а команда платформи не бачить очевидного збою ноди. У цей момент корисне питання — не «де журнали?», а «яке джерело доказів усе ще може відповісти на поточне питання?». Журнали контейнера можуть показати виняток, попередні журнали контейнера можуть показати рядок безпосередньо перед перезапуском, події можуть показати збій завантаження образу або проби, а метрики ресурсів можуть показати, що Pod дроселюється (throttling) або вбивається під тиском.

Логування та моніторинг у Kubernetes навмисно розділені на шари, тому що жоден окремий API не може розповісти всю історію. Kubelet захоплює stdout та stderr контейнера, API server зберігає короткочасні події, Metrics Server відкриває нещодавні вимірювання CPU та пам’яті, а служби ноди, такі як kubelet та containerd, ведуть власні журнали. Сильний фахівець з усунення несправностей рухається крізь ці шари послідовністю гіпотез, а не вдивляється в один шумний потік журналів, сподіваючись, що важливий рядок з’явиться.

Цей модуль перетворює швидкі команди з попередніх уроків з усунення несправностей на операційний робочий процес. Ви попрактикуєтеся читати поточні та попередні журнали контейнерів, інтерпретувати події, перевіряти метрики ресурсів, використовувати sidecar для файлових журналів та повертатися до журналів ноди, коли API Kubernetes недоступний або неповний. Суть не в тому, щоб запам’ятати кожен прапорець; суть у тому, щоб знати, який спостережуваний об’єкт усе ще може містити докази, чого кожен інструмент показати не може, і як звузити збій, не вигадуючи історію.

Журнали контейнерів: поточні, попередні та докази з кількох контейнерів

Розділ «Журнали контейнерів: поточні, попередні та докази з кількох контейнерів»

Логування в Kubernetes починається з простого контракту: застосунки мають писати корисний діагностичний вивід у stdout та stderr, а нода зробить цей вивід доступним через kubelet. Середовище виконання контейнерів записує потік у файли журналів на ноді, kubelet відкриває ці файли через свій API, а kubectl logs отримує вміст через шлях API Kubernetes. Такий дизайн тримає контейнери застосунків простими, але це також означає, що рядок журналу прив’язаний до екземпляра контейнера, а не до Деплойменту, Сервісу чи довготривалого бізнес-процесу.

┌──────────────────────────────────────────────────────────────┐
│ CONTAINER LOGGING FLOW │
│ │
│ Container │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Application │ │
│ │ │ │ │
│ │ ├── stdout ──────┐ │ │
│ │ │ │ │ │
│ │ └── stderr ──────┼────▶ Container runtime │ │
│ │ │ captures output │ │
│ └────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Node filesystem │
│ /var/log/containers/<pod>_<ns>_<container>-<id>.log │
│ │ │
│ ▼ │
│ kubectl logs (reads these files via kubelet API) │
│ │
└──────────────────────────────────────────────────────────────┘

Практичний наслідок полягає в тому, що перша команда журналів, яку ви запускаєте, має відповідати режиму збою, який ви перевіряєте. Стабільний Pod з одним контейнером зазвичай можна оглянути напряму, тоді як перезапущений контейнер часто потребує --previous, а Pod з кількома контейнерами потребує явного вибору контейнера. Якщо ви пропустите цей вибір, ви можете оглянути не той потік і побудувати хибну діагностику, особливо коли sidecar, init-контейнер чи пересилач журналів є компонентом, який насправді відмовляє.

Terminal window
# View logs from a pod (single container)
kubectl logs <pod>
# View logs from specific container (multi-container pod)
kubectl logs <pod> -c <container>
# Follow logs in real-time
kubectl logs <pod> -f
# Show last N lines
kubectl logs <pod> --tail=50
# Show logs since time
kubectl logs <pod> --since=1h
kubectl logs <pod> --since=30m
# Show logs with timestamps
kubectl logs <pod> --timestamps
# Combine options
kubectl logs <pod> --tail=100 --timestamps -f

Зробіть паузу й передбачте: якщо Pod має два контейнери, а ви запускаєте kubectl logs <pod> без -c, який вивід ви очікуєте від Kubernetes отримати, і який ризик це створює для вашого розслідування? Важлива звичка — питати, з якої межі об’єкта читає команда. Pod є одиницею планування, але журнали належать контейнерам усередині цього Pod’а, тож команда, яка не називає контейнер, може бути неоднозначною, коли існує більше одного потоку.

Pod’и з кількома контейнерами поширені у production навіть тоді, коли сам застосунок здається простим. Проксі service mesh, процес, що відстежує файли, помічник автентифікації чи експортер метрик — усі можуть жити поряд з основним застосунком і відмовляти незалежно. Коли симптом стосується трафіку, логування, порядку запуску чи спільних томів, огляньте перелік контейнерів, перш ніж припускати, що контейнер застосунку є єдиним корисним джерелом доказів.

Terminal window
# List containers in a pod
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].name}'
# Get logs from specific container
kubectl logs <pod> -c <container>
# Get logs from all containers
kubectl logs <pod> --all-containers=true
# Get logs from init containers
kubectl logs <pod> -c <init-container>

Попередні журнали контейнера є необхідними для CrashLoopBackOff, тому що поточний екземпляр контейнера може ще не дійти до проблемного шляху коду. kubectl logs <pod> за замовчуванням читає активний екземпляр, тож він може показати лише банер запуску, тоді як корисне трасування стека прив’язане до екземпляра, який помер мить тому. Прапорець --previous змінює ціль з поточного контейнера на останній завершений екземпляр, що часто є різницею між тим, щоб побачити «starting application», і тим, щоб побачити виняток, який спричинив перезапуск.

Terminal window
# Get logs from previous container instance (after crash)
kubectl logs <pod> --previous
kubectl logs <pod> -c <container> --previous
# This shows what was logged before the container died
# Essential for understanding why it crashed

Файлове логування — незручний випадок, тому що Kubernetes автоматично не збирає довільні файли всередині файлової системи контейнера. Застарілий процес, який пише лише в /var/log/app.log, може бути цілком балакучим з погляду застосунку й цілковито мовчазним з погляду kubectl logs. Звичним містком є sidecar-контейнер, який ділить том із застосунком, відстежує файл командою tail і пише той самий вміст у власний stdout, де kubelet може захопити його у звичайний спосіб.

apiVersion: v1
kind: Pod
metadata:
name: legacy-app
spec:
containers:
- name: main-app
image: legacy-app:1.0
volumeMounts:
- name: shared-logs
mountPath: /var/log
- name: log-tailer
image: busybox:1.36
command: ["/bin/sh", "-c", "touch /var/log/app.log 2>/dev/null; tail -n+1 -F /var/log/app.log"]
volumeMounts:
- name: shared-logs
mountPath: /var/log
volumes:
- name: shared-logs
emptyDir: {}

Потім ви можете переглянути журнали, запитавши sidecar командою kubectl logs legacy-app -c log-tailer. Цей патерн корисний, коли ви не можете швидко змінити застосунок, але він має компроміси: sidecar споживає ресурси, спільний emptyDir є локальним для ноди й ефемерним, а наївний tail -f може пропустити поведінку ротації, якщо застосунок і sidecar не узгодять обробку файлів. Ставтеся до нього як до патерну сумісності, а не як до приводу ігнорувати сучасні практики stdout та структурованого логування.

Вибір журналів за лейблами та контролером допомагає, коли проблемна поведінка існує в усіх репліках. Звичайна kubectl logs deployment/<name> слідує за зв’язком з контролером, але стрімить журнали лише з одного представницького Pod’а в цьому Деплойменті; додайте --all-pods=true, коли вам потрібна кожна репліка. kubectl logs -l app=nginx обирає Pod’и за лейблами, що корисно, коли Деплоймент, StatefulSet чи Job створили кілька Pod’ів зі спільним симптомом. Ці команди зручні, але вони також можуть давати переплетений вивід, тож поєднуйте їх із мітками часу, іменами контейнерів і невеликим --tail, коли намагаєтеся відтворити хронологію.

Terminal window
# Logs from all pods with a label
kubectl logs -l app=nginx
# Logs from all pods in a deployment (--all-pods=true required)
kubectl logs deployment/my-deployment --all-pods=true
# Follow logs from all matching pods
kubectl logs -l app=nginx -f
# With container name for multi-container pods
kubectl logs -l app=nginx -c <container>

Перш ніж запускати це, який вивід ви очікуєте, якщо один обраний Pod усе ще pending, а інший уже running? Команда може повернути журнали лише для контейнерів, які виробили журнали, тож відсутність виводу не завжди є доказом того, що застосунок мовчить. Це може означати, що контейнер так і не запустився, було обрано не той Простір імен, лейбл відповідав меншій кількості Pod’ів, ніж очікувалося, або корисні докази живуть у подіях, а не в журналах.

Події Kubernetes: короткочасні підказки з площини управління

Розділ «Події Kubernetes: короткочасні підказки з площини управління»

Події — це об’єкти Kubernetes, які фіксують помітні зміни стану та операційні попередження. Вони не є журналами застосунку й не є постійним аудиторським слідом; це короткочасні підказки, які виробляють такі компоненти, як планувальник, kubelet, контролери та API server. Під час усунення несправностей події зазвичай є першим місцем для перегляду, коли Pod перебуває у стані pending, не може змонтувати том, провалює пробу, повільно завантажує образ, витісняється чи перезапускається до того, як застосунок встигне записати корисні журнали.

┌──────────────────────────────────────────────────────────────┐
│ KUBERNETES EVENTS │
│ │
│ Events are generated by: │
│ • Scheduler (scheduling decisions) │
│ • kubelet (container lifecycle) │
│ • Controllers (resource management) │
│ • API server (API operations) │
│ │
│ Event Types: │
│ • Normal: Informational, things working as expected │
│ • Warning: Something unexpected, might need attention │
│ │
│ Important: Events expire after ~1 hour by default! │
│ │
└──────────────────────────────────────────────────────────────┘

Найважливіше обмеження — це час зберігання. Стандартний TTL подій API server становить одну годину (--event-ttl на kube-apiserver), що означає, що події призначені для діагностики майже в реальному часі, а не для розслідувань вихідного дня. Якщо пакетне завдання провалилося два дні тому й конвеєра експорту подій не існує, kubectl get events може правдиво нічого не повернути, навіть якщо Kubernetes свого часу видавав корисні попередження. Саме тому production-стеки спостережуваності часто відправляють події до журнальної платформи чи спеціалізованого збирача подій, перш ніж API server збере їх як сміття.

Terminal window
# All events in current namespace
kubectl get events
# All events cluster-wide
kubectl get events -A
# Sort by time (most recent last)
kubectl get events --sort-by='.lastTimestamp'
# Sort by time (most recent first)
kubectl get events --sort-by='.lastTimestamp' | tac
# Filter by type
kubectl get events --field-selector type=Warning
# Events for specific object
kubectl get events --field-selector involvedObject.name=<pod-name>
# Watch events in real-time
kubectl get events -w

Зробіть паузу й передбачте: якщо Pod було створено три дні тому й він перезапускається відтоді, які події ще можуть бути присутніми, а які ранні події, ймовірно, зникли? Вам слід очікувати, що нещодавні події перезапуску, backoff, проб чи образу будуть доступні, якщо вони все ще видаються, але початкові події планування та створення можуть застаріти. Стовпець віку — теж доказ; він каже вам, чи дивитеся ви на початок інциденту, чи лише на найновіше повторення.

ReasonTypeЩо це означає
ScheduledNormalPod призначено ноді
PulledNormalОбраз успішно завантажено
CreatedNormalКонтейнер створено
StartedNormalКонтейнер запущено
KillingNormalКонтейнер завершується
FailedSchedulingWarningНе вдалося знайти придатну ноду
FailedMountWarningМонтування тому провалилося
UnhealthyWarningПроба провалилася
BackOffWarningКонтейнер падає, відкладається
FailedCreateWarningКонтролер не зміг створити Pod
EvictedWarningPod витіснено з ноди
OOMKillingWarningКонтейнер убито через OOM

kubectl describe залишається цінним, тому що він розміщує стан об’єкта, конфігурацію та пов’язані події в одному вигляді. Для Pod’а у стані pending розділ Events часто каже вам, чи бракувало планувальнику CPU, пам’яті, відповідних лейблів ноди, толерантностей чи прив’язаного тому. Для running, але нездорового Pod’а вивід describe може пов’язати налаштування проб з подіями Unhealthy, показуючи, чи спричинений цикл перезапусків падіннями застосунку, чи тим, що kubelet убиває контейнер, який провалює перевірки liveness.

Terminal window
# Events appear in describe output
kubectl describe pod <pod>
# Look for the Events section at the bottom
kubectl describe node <node>
# Shows node-level events
kubectl describe pvc <pvc>
# Shows volume binding events

Події та журнали відповідають на різні питання. Журнали кажуть вам, що процес записав зсередини контейнера, тоді як події кажуть вам, що компоненти Kubernetes спостерегли ззовні цього процесу. Pod у стані pending не має корисних журналів застосунку, тому що контейнер не запустився, але він може мати багаті події планування. Pod, що падає, може мати обидва: події можуть показати поведінку перезапуску та backoff, тоді як попередні журнали пояснюють, що процес робив до завершення.

Метрики ресурсів: kubectl top, Metrics Server та сигнали тиску

Розділ «Метрики ресурсів: kubectl top, Metrics Server та сигнали тиску»

Метрики ресурсів — це нещодавні вимірювання використання CPU та пам’яті, а не історичні графіки й не планування ємності саме по собі. У кластері Kubernetes 1.35 kubectl top спілкується з API metrics.k8s.io, який зазвичай обслуговує Metrics Server. Metrics Server опитує endpoint ресурсів kubelet на кожній ноді, агрегує поточне використання та відкриває легкий API, який підтримує швидкі операційні перевірки та вхідні дані для автомасштабування, але це не повноцінна база даних моніторингу.

┌──────────────────────────────────────────────────────────────┐
│ METRICS SERVER │
│ │
│ Nodes Metrics Server │
│ ┌───────────────────┐ ┌──────────────┐ │
│ │ kubelet │───│ Collects │ │
│ │ /metrics/resource │ │ aggregates │ │
│ └───────────────────┘ │ exposes │ │
│ └──────┬───────┘ │
│ │ │
│ metrics.k8s.io API │
│ │ │
│ ▼ │
│ kubectl top │
│ │
│ Without Metrics Server → kubectl top fails │
│ │
└──────────────────────────────────────────────────────────────┘

Оскільки kubectl top залежить від агрегованого API, його збій не означає автоматично, що нода перестала вимірювати ресурси. Це може означати, що Metrics Server не встановлено, реєстрація APIService недоступна, автентифікація TLS чи kubelet відмовляє, або RBAC блокує запит. Найшвидша перевірка — оглянути Pod Metrics Server та реєстрацію APIService, перш ніж ганятися за лімітами ресурсів застосунку.

Terminal window
# Check if Metrics Server is installed
kubectl -n kube-system get pods | grep metrics-server
# Check metrics API
kubectl get apiservices | grep metrics
# If not installed, top commands will fail
kubectl top nodes # Error: Metrics API not available

kubectl top навмисно малий та миттєвий. Він допомагає вам визначити гарячі Pod’и, порівняти ноди та вирішити, чи може збій бути спричинений тиском пам’яті, дроселюванням CPU чи екстремальним дисбалансом. Він не каже вам, що сталося минулої ночі, і не замінює Prometheus, OpenTelemetry чи вендорну платформу моніторингу для довгострокового аналізу трендів. Використовуйте його як швидкий інструмент поточного стану під час діагностики, особливо на іспиті CKA, де вбудовані інструменти мають значення.

Terminal window
# Node resource usage
kubectl top nodes
# Pod resource usage (current namespace)
kubectl top pods
# Pod resource usage (all namespaces)
kubectl top pods -A
# Sort by CPU
kubectl top pods --sort-by=cpu
# Sort by memory
kubectl top pods --sort-by=memory
# Per-container usage
kubectl top pods --containers
# Specific pod
kubectl top pod <pod-name>

Одиниці в kubectl top компактні, але точні. CPU зазвичай показано в тисячних частках ядра (мілікорах), де 100m — це одна десята ядра, а 1000m — одне повне ядро. Пам’ять часто показано в двійкових одиницях, таких як Mi та Gi. Вимірювання стає осмисленим лише тоді, коли ви порівнюєте його із запитами, лімітами, доступною ємністю ноди та симптомом, який ви розслідуєте.

┌────────────────────────────────────────────────────────────────────────────────────────────┐
│ METRIC INTERPRETATION │
│ │
│ NAME CPU(cores) MEMORY(bytes) │
│ my-pod 100m 256Mi │
│ │
│ CPU: 100m = 100 millicores = 0.1 CPU core │
│ 1000m = 1 core │
│ │
│ Memory: Mi = mebibytes (1024 * 1024 bytes) │
│ Gi = gibibytes │
│ │
│ Compare against requests/limits: │
│ usage above requests: under-requested; scheduling/QoS + eviction risk under node pressure│
│ memory near/above limit: OOMKilled │
│ CPU at limit: throttled (not killed) │
│ │
└────────────────────────────────────────────────────────────────────────────────────────────┘

Перш ніж запускати це, який вивід ви очікуєте, коли Pod використовує більше CPU, ніж його запит, але менше за його ліміт? Запити CPU впливають на планування, тоді як ліміти CPU впливають на дроселювання (throttling), тож Pod може законно використовувати більше за свій запит після запуску, якщо доступний вільний CPU. Пам’ять поводиться інакше, тому що перевищення ліміту пам’яті може завершити контейнер, ось чому стрибки пам’яті часто потребують співвіднесення з лічильниками перезапусків, статусом OOMKilled та попередніми журналами.

Terminal window
# Compare actual usage vs requests
# Step 1: Get requests
kubectl get pod <pod> -o jsonpath='{.spec.containers[0].resources.requests}'
# Step 2: Get actual usage
kubectl top pod <pod>
# If actual >> requests, pod is under-requested
# If actual << requests, pod is over-requested

Метрики стають особливо корисними, коли ви поєднуєте їх з подіями. Pod у стані pending з FailedScheduling може взагалі не потребувати журналів; йому може знадобитися налаштування запитів чи додаткова ємність ноди. Running Pod з високою пам’яттю та причиною перезапуску OOMKilled потребує попередніх журналів та перегляду лімітів. Pod з високим CPU та повільними відповідями може дроселюватися, навіть якщо процес не падає, що змінює наступну дію з «прочитати трасування стека» на «порівняти ліміти CPU, затримку та метрики дроселювання».

Журнали на рівні ноди та площини управління

Розділ «Журнали на рівні ноди та площини управління»

Більшість повсякденного усунення несправностей слід починати з API Kubernetes, тому що вони зберігають контекст об’єкта й уникають непотрібного доступу до ноди. Журнали на рівні ноди мають значення, коли API server недоступний, поведінка kubelet є підозрюваним збоєм, операції середовища виконання контейнерів порушені, або потрібні вам докази розташовані нижче абстракції Pod’а. На Linux-нодах журнали контейнерів зазвичай доступні через /var/log/containers, тоді як журнали kubelet та середовища виконання контейнерів зазвичай доступні через journalctl, коли systemd керує цими службами.

┌──────────────────────────────────────────────────────────────┐
│ NODE LOG LOCATIONS │
│ │
│ Container logs (symlinks): │
│ /var/log/containers/<pod>_<ns>_<container>-<id>.log │
│ │
│ Pod logs (actual files): │
│ /var/log/pods/<ns>_<pod>_<uid>/ │
│ │
│ kubelet logs: │
│ journalctl -u kubelet │
│ │
│ Container runtime logs: │
│ journalctl -u containerd │
│ journalctl -u docker (if using docker) │
│ │
│ System logs: │
│ /var/log/syslog or /var/log/messages │
│ journalctl │
│ │
└──────────────────────────────────────────────────────────────┘

Пряме обстеження ноди має вищий операційний ризик, ніж kubectl, тому що ви залишаєте звичайний робочий процес API. Вам потрібен доступ до ноди, вам потрібно знати структуру операційної системи, і ви маєте уникати зміни файлів під час розслідування. Усе ж це законний запасний варіант, коли kubectl logs не може дістатися kubelet, коли API server лежить, або коли специфічна для ноди проблема — як-от тиск диску, збій сертифіката kubelet чи помилки середовища виконання контейнерів — заважає звичайній діагностиці на рівні об’єкта.

Terminal window
# SSH to node first
ssh <node>
# Container logs directly
ls /var/log/containers/
tail -f /var/log/containers/<pod>*.log
# kubelet logs
journalctl -u kubelet -f
journalctl -u kubelet --since "10 minutes ago"
journalctl -u kubelet | grep -i error
# Container runtime logs
journalctl -u containerd -f
# System messages
dmesg | tail -50
journalctl -xe

Журнали компонентів площини управління залежать від того, як було встановлено кластер. У кластерах у стилі kubeadm основні компоненти площини управління часто працюють як статичні Pod’и в kube-system, що робить їхні журнали видимими через kubectl logs, коли API server достатньо здоровий, щоб відповідати. В інших дистрибутивах компоненти можуть бути службами systemd, керованими контейнерами чи хостованими процесами площини управління, які потребують специфічного для провайдера доступу. Діагностичний принцип залишається тим самим: спочатку знайдіть межу компонента, потім використовуйте механізм логування для цієї межі.

Terminal window
# If using static pods (kubeadm)
# Logs available via kubectl
kubectl -n kube-system logs kube-apiserver-<node>
kubectl -n kube-system logs kube-scheduler-<node>
kubectl -n kube-system logs kube-controller-manager-<node>
kubectl -n kube-system logs etcd-<node>
# Or directly on node via journalctl (if systemd services)
journalctl -u kube-apiserver
journalctl -u kube-scheduler
journalctl -u kube-controller-manager
journalctl -u etcd

Журнали ноди також пояснюють, чому має значення ротація журналів. Kubelet керує файлами журналів контейнерів відповідно до своєї конфігурації, що захищає ноди від необмеженого зростання диску, але також означає, що старий вміст журналу може зникнути локально. Якщо шумний застосунок швидко заповнює журнали, ваше вікно kubectl logs --previous може бути коротшим, ніж ви очікуєте. Для production-систем локальне для ноди зберігання журналів слід трактувати як буфер, доки журнали не відправлено в надійне сховище, а не як систему обліку.

Співвіднесення журналів, подій та метрик у робочий процес

Розділ «Співвіднесення журналів, подій та метрик у робочий процес»

Усунення несправностей стає швидшим, коли ви ставите по одному питанню про докази за раз. Почніть зі стану об’єкта та нещодавніх подій, тому що вони кажуть вам, чи зміг Kubernetes запланувати, завантажити, змонтувати, запустити й тримати контейнер живим. Потім огляньте поточні чи попередні журнали контейнера залежно від поведінки перезапуску. Використовуйте метрики, коли симптом може бути тиском, дроселюванням чи дисбалансом. Нарешті, переходьте до журналів на рівні ноди лише тоді, коли вигляд API відсутній, суперечливий чи нижчий за шар, де живе проблема.

┌──────────────────────────────────────────────────────────────┐
│ LOG ANALYSIS WORKFLOW │
│ │
│ 1. Start with events │
│ kubectl describe <resource> | grep -A 20 Events │
│ │
│ 2. Check recent events cluster-wide │
│ kubectl get events --sort-by='.lastTimestamp' | tail │
│ │
│ 3. Get container logs │
│ kubectl logs <pod> │
│ kubectl logs <pod> --previous (if crashed) │
│ │
│ 4. Filter for errors │
│ kubectl logs <pod> | grep -i error │
│ kubectl logs <pod> | grep -i exception │
│ │
│ 5. Check timing │
│ kubectl logs <pod> --timestamps --since=10m │
│ │
│ 6. Check related components │
│ If pod issues: check node │
│ If network issues: check CNI, kube-proxy │
│ If DNS issues: check CoreDNS │
│ │
└──────────────────────────────────────────────────────────────┘

Фільтрація корисна лише після того, як ви розумієте потік, який фільтруєте. Команда grep -i error може виявити важливі рядки, але вона також може приховати рядок контексту перед помилкою чи пропустити застосунки, які логують збої як fatal, exception, panic чи структуровані поля JSON. Використовуйте фільтрацію, щоб зменшити шум, а не щоб делегувати судження. Коли час має значення, додайте --timestamps та звужуйте за допомогою --since чи --since-time перед пошуком.

Terminal window
# Search for errors
kubectl logs <pod> | grep -i error
kubectl logs <pod> | grep -i exception
kubectl logs <pod> | grep -i fatal
# Exclude noise
kubectl logs <pod> | grep -v "INFO"
kubectl logs <pod> | grep -v "health check"
# Complex filters
kubectl logs <pod> | grep -E "error|warning|failed"
# With timestamps and filtering
kubectl logs <pod> --timestamps | grep "2024-01-15T10:3"
# Count error occurrences
kubectl logs <pod> | grep -c error

Аналіз кількох Pod’ів — це проблема співвіднесення, а не просто більший текстовий потік. Коли кілька реплік відмовляють, ви хочете знати, чи всі Pod’и відмовляють однаково, чи зачеплено лише одну ноду, чи задіяна одна версія чи набір лейблів, і чи sidecar’и повідомляють про іншу послідовність, ніж контейнери застосунку. Використовуйте вибір за контролером і лейблами для широти, потім звужуйте до представницького Pod’а для точних міток часу та попередніх журналів.

Terminal window
# Logs from all pods in deployment (--all-pods=true required)
kubectl logs deployment/<name> --all-pods=true --all-containers=true
# Aggregate logs from multiple pods with labels
kubectl logs -l app=frontend --all-containers
# Using stern (not built-in, but useful)
# stern <pod-name-pattern>
# Workaround: loop through pods
for pod in $(kubectl get pods -l app=nginx -o name); do
echo "=== $pod ==="
kubectl logs $pod --tail=5
done

Співвіднесення подій та журналів — це місце, де багато розслідувань стають вирішальними. Якщо подія каже, що проба liveness провалилася в певний час, журнали навколо цієї мітки часу можуть показати, чи застосунок усе ще завантажувався, чекав на базу даних, відхиляв трафік чи був у взаємному блокуванні. Якщо подія каже, що контейнер було вбито, попередні журнали можуть показати, що сталося до завершення, тоді як метрики можуть показати, чи зробив тиск пам’яті це вбивство передбачуваним.

Terminal window
# Get event time
kubectl get events --field-selector involvedObject.name=my-pod
# Note the timestamp, then check logs around that time
kubectl logs my-pod --since-time="2024-01-15T10:30:00Z"
# Or use relative time
kubectl logs my-pod --since=5m

Який підхід ви оберете тут і чому: почати зі стеження за живими журналами чи спочатку відсортувати нещодавні події Warning у Просторі імен? Якщо симптом — «новий Pod так і не стає Ready», події зазвичай мають вищий сигнал, тому що вони виявляють збої завантаження, монтування, планування та проб, які трапляються поза процесом застосунку. Якщо симптом — «Ready Pod повертає помилки під трафіком», живі журнали плюс мітки часу можуть бути кращим першим кроком.

Патерни моніторингу для іспиту та операцій

Розділ «Патерни моніторингу для іспиту та операцій»

Швидкий прохід здоров’я кластера має бути достатньо малим, щоб виконати його під тиском, і достатньо широким, щоб вловити очевидні збої. Почніть з нод, не-running Pod’ів, поточних метрик та подій Warning. Це не замінює глибшу спостережуваність, але дає вам послідовну базову лінію, перш ніж ви станете ганятися за окремим компонентом. На іспиті CKA ця звичка також запобігає марнуванню часу всередині журналів застосунку, коли справжній збій — це стан ноди чи обмеження планування.

Terminal window
# Quick cluster health check
kubectl get nodes
kubectl get pods -A | grep -v Running
kubectl top nodes
kubectl get events -A --field-selector type=Warning
# Create a simple monitoring script
watch -n 5 'kubectl get pods -A | grep -v Running | grep -v Completed'

Виявлення тиску на ресурси потребує і статусу об’єкта, і поточних вимірювань. Умови ноди, такі як MemoryPressure, DiskPressure та PIDPressure, пояснюють, чому kubelet може витісняти Pod’и чи відхиляти роботу. Команди top показують поточних споживачів, тоді як pending Pod’и можуть виявити запити, які жодна нода не може задовольнити. Мета — відокремити несправність застосунку від несправності ємності кластера чи здоров’я ноди, перш ніж ви зміните не той маніфест.

Terminal window
# Check for node pressure
kubectl describe nodes | grep -E "MemoryPressure|DiskPressure|PIDPressure"
# Check for pods using excessive resources
kubectl top pods -A --sort-by=memory | head -10
kubectl top pods -A --sort-by=cpu | head -10
# Check for pending pods (might indicate resource shortage)
kubectl get pods -A --field-selector=status.phase=Pending

Тимчасові діагностичні Pod’и корисні, коли вам потрібні інструменти всередині мережі кластера, але їх слід створювати усвідомлено. Використовуйте --rm, щоб Pod видалявся, коли оболонка завершується, і використовуйте --restart=Never, щоб ви створювали голий Pod, а не кероване контролером робоче навантаження. Ретельно обирайте Простір імен та сервісний акаунт, тому що діагностичний Pod, що працює з не тією ідентичністю, може довести лише те, що не та ідентичність має доступ.

Terminal window
# Create debug pod with networking tools
kubectl run debug --image=nicolaka/netshoot --rm -it --restart=Never -- bash
# Simple debug pod
kubectl run debug --image=busybox:1.36 --rm -it --restart=Never -- sh
# Debug with specific service account
kubectl run debug --image=busybox:1.36 --rm -it --restart=Never --overrides='{"spec":{"serviceAccountName":"<sa>"}}' -- sh
# Debug in specific namespace
kubectl run debug -n <namespace> --image=busybox:1.36 --rm -it --restart=Never -- sh

Найкращий патерн моніторингу — це цикл прийняття рішень: спостерігайте, формуйте гіпотезу, запускайте найменшу команду, яка може її спростувати, потім оновлюйте свій шлях. Якщо гіпотеза — «застосунок упав», попередні журнали мають високу цінність. Якщо це — «Pod так і не запланувався», події та вивід describe важать більше. Якщо це — «нода нездорова», умови ноди та журнали kubelet релевантніші за вивід застосунку.

Розбір прикладу: побудова хронології доказів

Розділ «Розбір прикладу: побудова хронології доказів»

Сценарій вправи: Простір імен на ім’я payments містить Деплоймент, чиї нові Pod’и не стають здоровими після зміни конфігурації. Сервіс усе ще частково доступний, тому що старіші репліки залишаються ready, але розгортання застрягло, і черговому інженеру треба вирішити, чи робити відкат, виправляти конфігурацію чи змінювати налаштування ресурсів. Вам не сказано наперед першопричину, тому що навичка, яку відпрацьовують, — це послідовність доказів, а не запам’ятовування команд.

Перше спостереження — це стан контролера, а не журнал застосунку. Застрягле розгортання каже вам, що частина бажаних реплік недоступна, але воно не пояснює, чи Pod’и провалили планування, завантаження образу, запуск, готовність чи виконання в усталеному режимі. Початок з kubectl describe deployment та kubectl get pods -n payments -o wide дає вам імена об’єктів, розміщення на нодах, лічильники перезапусків та фази статусу. Це запобігає поширеній помилці: прочитати журнал одного Pod’а й припустити, що він представляє все розгортання.

Припустимо, таблиця Pod’ів показує два нові Pod’и у стані Running з лічильниками перезапусків, що зростають, і один старіший Pod, усе ще Running з нульовими перезапусками. Це одразу звужує проблему до нового ReplicaSet чи конфігурації, а не до універсального простою ноди. Наступний корисний крок — оглянути один проблемний Pod за допомогою kubectl describe pod, тому що розділ Events може виявити, чи kubelet убиває контейнер через проби, чи контейнер виходить сам, чи задіяне примусове виконання ресурсів.

Вивід describe показує повторювані події BackOff та стан контейнера Waiting з причиною CrashLoopBackOff. У цей момент поточні журнали менш корисні, ніж попередні журнали, тому що контейнер уже помер щонайменше раз. Ви запускаєте kubectl logs -n payments <pod> --previous і бачите помилку валідації конфігурації біля запуску. Цей єдиний рядок корисний, але це ще не повна хронологія, тому що вам усе ще треба пов’язати його з розгортанням і підтвердити, що та сама помилка з’являється на всіх нових репліках.

Наступний крок — запитати журнали з Деплойменту чи селектора за лейблами з невеликим tail та мітками часу. Якщо всі нові Pod’и показують ту саму помилку валідації невдовзі після запуску, ви можете трактувати збій як проблему конфігурації релізу, а не як специфічну для ноди проблему середовища виконання. Якщо лише один Pod показує помилку, а інші відмовляють інакше, розслідування розгалужується. Ось чому широкий вибір та вузький огляд мають чергуватися: широта каже вам патерн, тоді як деталь каже вам механізм.

Тепер уявіть, що попередні журнали не показують помилки застосунку, але describe pod показує події Unhealthy від проби liveness. Це змінює діагностику. Застосунок може повільно запускатися, шлях проби може бути хибним, або залежність, яку перевіряє проба, може бути недоступною. У цій гілці ви оглядаєте налаштування readiness та liveness, порівнюєте мітки часу з журналами запуску застосунку й вирішуєте, чи виявляє проба справжній збій, чи вбиває процес, який став би здоровим за довшого вікна запуску.

Метрики ресурсів створюють третю гілку. Якщо Pod перезапускається й події показують OOMKilling, kubectl top pod може й не вловити стрибок, тому що контейнер швидко помирає, а метрики вибираються вибірково. Ви все одно порівнюєте запити та ліміти, але не покладаєтеся лише на kubectl top. Попередні журнали, причина завершення та події несуть найсильніші докази вбивства через пам’ять, тоді як Metrics Server надає поточний контекст для Pod’ів, що вижили, та тиску на рівні ноди.

Розміщення на нодах також може змінити шлях. Якщо кожен проблемний Pod потрапляє на ту саму ноду, перевірте умови ноди, події kubelet та журнали середовища виконання контейнерів, перш ніж звинувачувати застосунок. Поганий кеш образів, тиск диску, зламаний стан CNI чи проблема kubelet можуть породити симптоми, які з погляду Деплойменту виглядають як нестабільність застосунку. Стовпець NODE таблиці Pod’ів — тому не оздоблення; це поле співвіднесення, яке допомагає відокремити проблеми робочих навантажень від проблем інфраструктури.

Час — це нитка, яка зв’язує ці спостереження разом. Корисна хронологія могла б казати: новий ReplicaSet створив Pod’и о 10:12, kubelet запустив контейнери о 10:13, застосунок залогував помилку конфігурації о 10:13, kubelet зафіксував BackOff о 10:14, і Деплоймент залишався недоступним після цього. Така послідовність підтримує відкат конфігурації. Інша хронологія, де планування провалилося до того, як запустився будь-який контейнер, підтримувала б натомість виправлення розміщення чи ємності.

Зробіть паузу й передбачте: якщо команда застосунку просить «журнали з провального розгортання», які саме потоки ви зібрали б, і як ви позначили б їх, щоб команда могла міркувати про час? Якісна відповідь включає попередні журнали для кожного проблемного контейнера, поточні журнали для будь-яких реплік, що вижили, релевантні події, відсортовані за міткою часу, та статус Деплойменту чи ReplicaSet, який показує, до якої ревізії належать Pod’и. Сирий текст без міток важко використовувати під час передавання.

Цей приклад також пояснює, чому агрегація журналів не усуває навичок kubectl. Центральна система журналів може зберігати історію та покращувати пошук, але стан об’єкта Kubernetes усе ще є найшвидшим способом зіставити симптом з Pod’ами, контейнерами, нодами, причинами перезапуску та подіями. І навпаки, kubectl може показати лише нещодавні чи локальні для ноди докази, тож надійне логування залишається необхідним для відкладених розслідувань. Ефективні оператори розуміють обидва вигляди й рухаються між ними усвідомлено.

Коли докази вказують на конфігурацію, ви все одно перевіряєте виправлення спостережуваністю, а не припускаєте, що розгортання вилікувано. Після застосування виправленого ConfigMap, Secret чи змінної середовища Деплойменту слідкуйте за подіями на предмет нових збоїв, читайте перші журнали запуску з нових Pod’ів та підтверджуйте готовність. Якщо метрики були частиною симптому, порівняйте використання ресурсів знову після виправлення. Закриття — це не «команда повернула нуль»; закриття — це «попередній режим збою більше не з’являється, і робоче навантаження досягає очікуваного стану».

Коли докази вказують на ресурси, найбезпечніший наступний крок залежить від того, чи проблема в плануванні, в пам’яті середовища виконання чи в насиченні CPU. Pod у стані Pending з FailedScheduling через недостатню пам’ять потребує змін запитів чи ємності, тоді як running Pod, убитий з OOMKilled, потребує перегляду лімітів та поведінки пам’яті. Pod з інтенсивним CPU без перезапусків може потребувати коригування лімітів, горизонтального масштабування чи профілювання застосунку. Усі ці випадки залучають «ресурси», але кожен має іншу першу команду та інший відповідальний шар.

Коли докази вказують на здоров’я ноди, збережіть вигляд Kubernetes, перш ніж заглиблюватися. Зафіксуйте розміщення Pod’ів, умови ноди, події Warning та імена зачеплених робочих навантажень, потім огляньте журнали kubelet чи середовища виконання контейнерів, якщо потрібно. Журнали ноди можуть бути шумними, і без контексту об’єкта ви можете не знати, які помилки мають значення. Послідовність важлива, тому що вона дозволяє вам повернутися від доказів на рівні ноди до конкретного Pod’а, Простору імен та робочого навантаження замість збирання непов’язаних системних повідомлень.

Та сама звичка до хронології застосовна на іспиті CKA, навіть якщо середовище менше. Вас часто винагороджують за вибір найкоротшого валідного шляху доказів: події для планування та монтувань, попередні журнали для падінь, kubectl top для поточного тиску та журнали ноди для проблем kubelet чи середовища виконання. Іспит не вимагає production-платформи спостережуваності, але він вимагає, щоб ви знали, чому команда релевантна, перш ніж її запускати. Це тримає вас швидкими, не будучи випадковими.

Останній урок зі сценарію — що дані спостережуваності мають свіжість та область охоплення. Події свіжі, але короткочасні, журнали контейнерів прив’язані до екземпляра контейнера, метрики нещодавні та вибіркові, а журнали ноди локальні для машини. Діагностика сильніша, коли вона називає ці обмеження прямо. Замість того щоб казати «журнали доводять, що деплоймент зламано», скажіть «попередні журнали для всіх нових контейнерів застосунку показують ту саму помилку валідації запуску після того, як було створено новий ReplicaSet». Це твердження достатньо конкретне, щоб діяти.

Вам також слід думати про аудиторію, збираючи докази. Розробнику застосунку часто потрібен точний виняток, змінна середовища чи збій запиту з міткою часу. Інженеру платформи може знадобитися розміщення Pod’ів, умови ноди, події kubelet та чи з’являється той самий симптом у різних Просторах імен. Менеджеру релізів може знадобитися чітка рекомендація «так чи ні» щодо відкату. Ті самі сирі дані спостережуваності можуть підтримати всі три розмови, але лише якщо ви зберігаєте достатньо контексту, щоб пов’язати докази з дією.

Хороші нотатки про докази компактні й відтворювані. Запишіть Простір імен, ім’я Pod’а, ім’я контейнера, використану команду та часове вікно, яке ви оглянули. Якщо ви використали --previous, скажіть про це явно, тому що це відрізняє завершений екземпляр від поточного. Якщо ви фільтрували журнали, тримайте нефільтровану команду доступною також, тому що іншому рецензенту можуть знадобитися навколишні рядки. Ця дисципліна має значення під час передавання, коли товариш по команді має довіряти вашому висновку, не перезапускаючи кожну команду з пам’яті.

Існує тонка різниця між «моніторингом» та «діагностикою» в цьому модулі. Моніторинг питає, чи система здорова зараз і чи виглядає використання ресурсів аномальним. Діагностика питає, чому стався конкретний симптом. kubectl top nodes може підтримати моніторинг, показуючи поточний тиск, тоді як попередні журнали підтримують діагностику, пояснюючи завершений контейнер. Сильні фахівці з усунення несправностей поєднують їх, але не плутають поточне вимірювання з історичною причиною.

Робочий процес також захищає від переобладнання під знайомі збої. Якщо ви нещодавно виправили проблему завантаження образу, у вас може виникнути спокуса припустити, що наступний збій розгортання має ту саму причину. Цикл доказів змушує вас перевірити стан, події, журнали, метрики та розміщення, перш ніж зобов’язатися до виправлення. Це повільніше за вгадування для першої хвилини, але швидше за відкат здорового образу, коли справжня проблема — це відсутній Secret, провалене монтування чи занадто сувора проба.

Нарешті, трактуйте прибирання як частину практики спостережуваності. Тимчасові діагностичні Pod’и, лабораторні Простори імен та ситуативні скрипти можуть створювати шум, який заплутує пізніші розслідування, якщо вони залишаються в кластері. Видалення лабораторного Простору імен після цієї вправи — це не просто охайність; це тримає майбутній вивід kubectl get pods -A, подій та метрик сфокусованим на справжніх робочих навантаженнях. Чисті середовища роблять сигнал легшим для знаходження, що саме й мають надавати логування та моніторинг.

Патерни та антипатерни

Розділ «Патерни та антипатерни»

Наведені нижче патерни розраховані на операційне використання, де швидкість має значення, але передчасна впевненість небезпечна. Кожен патерн працює, тому що він робить межу доказів явною. Журнали, події, метрики та журнали ноди описують різні шари, тож правильний патерн зазвичай той, який звужує шар перед тим, як звузити команду.

ПатернКоли використовуватиЧому це працюєМіркування щодо масштабування
Тріаж «події передусім»Pod’и у стані Pending, ContainerCreating, провалюють проби чи нещодавно перезапустилисяКомпоненти Kubernetes пояснюють збої життєвого циклу, перш ніж застосунок зможе залогуватиЕкспортуйте події для зберігання, бо TTL подій API server короткий
Аналіз падіння за попередніми журналамиКонтейнери швидко перезапускаються чи показують CrashLoopBackOffОстанній завершений екземпляр містить збій, до якого поточний екземпляр може не дійтиВключайте -c <container> у Pod’ах з кількома контейнерами, щоб не прочитати не той перезапуск
Співвіднесення за мітками часуПодії, журнали та метрики показують симптоми приблизно в один періодЗбіг часових вікон відділяє причину від подальшого шумуВикористовуйте узгоджені часові зони та централізовано відправляйте журнали для довгих розслідувань
Відстеження файлів через sidecarЗастарілі застосунки пишуть у файли й не можуть бути швидко зміненіСпільний том плюс sidecar перетворюють записи у файли на захоплений kubelet stdoutПлануйте міграцію на прямий структурований stdout, щоб зменшити накладні витрати sidecar

Антипатерни зазвичай походять від трактування одного спостережуваного об’єкта як цілої правди. Потік журналів може бути порожнім, тому що контейнер так і не запустився, а не тому, що нічого не відмовило. Помилка kubectl top може означати, що Metrics Server лежить, а не що кластер не має використання ресурсів. Відсутність подій може означати, що сплинув час зберігання, а не що Kubernetes нічого не побачив. Безпечніша альтернатива — назвати, що інструмент може й не може довести, перш ніж діяти на його основі.

АнтипатернЩо йде не такКраща альтернатива
Стеження за живими журналами до перевірки стану об’єктаВи пропускаєте збої планування, завантаження образу, монтування чи проб поза процесомСпочатку запустіть kubectl describe та нещодавні події Warning для проблем життєвого циклу
Читання лише першого контейнера в Pod’іЗбої sidecar, init чи проксі залишаються невидимимиПерелічіть контейнери й усвідомлено використовуйте -c чи --all-containers=true
Трактування подій як постійної історіїАналіз вихідного дня чи відкладеного інциденту втрачає початкові підказкиЕкспортуйте події в надійну систему журналів і фіксуйте хронології під час інцидентів
Використання SSH на ноду як першого діагностичного крокуВи втрачаєте контекст об’єкта й підвищуєте операційний ризикПочинайте з API Kubernetes, потім повертайтеся до журналів ноди, коли шару API недостатньо

Рамка прийняття рішень

Розділ «Рамка прийняття рішень»

Використовуйте цю рамку, коли симптом зрозумілий, але наступна команда — ні. Перше рішення — чи запустився контейнер. Якщо ні, журнали вторинні, тому що немає осмисленого виводу процесу. Друге рішення — чи перезапустився контейнер. Якщо так, попередні журнали корисніші за поточні журнали. Третє рішення — чи може симптом бути спричинений тиском на ресурси. Якщо може, метрики та умови ноди слід перевірити, перш ніж змінювати код застосунку.

СимптомПерше джерело доказівНаступне джерело доказівЗагальний напрям виправлення
Pod у стані PendingПодії kubectl describe podДоступні ресурси ноди, статус PVC, taint’и, affinityСкоригувати запити, прив’язку сховища, толерантності чи правила розміщення
Pod у стані CrashLoopBackOffkubectl logs --previousПодії, причина перезапуску, проби, ліміти ресурсівВиправити запуск застосунку, конфігурацію, доступ до залежностей чи ліміти
Pod Running, але не ReadyПодії та вивід пробПоточні журнали з мітками часуВиправити endpoint readiness, час запуску, перевірки залежностей чи конфігурацію проб
kubectl top відмовляєAPIService та Pod Metrics ServerЖурнали Metrics Server та доступ до kubeletВстановити, відремонтувати чи переналаштувати Metrics Server
Нода показує тискУмови node describeTop Pod’и, відсортовані за CPU чи пам’яттю, журнали kubeletНалаштувати запити та ліміти, витіснити шумні робочі навантаження чи додати ємність
┌───────────────────────────┐
│ What is the visible state? │
└──────────────┬────────────┘
┌─────────▼─────────┐
│ Container started? │
└───────┬─────┬─────┘
│yes │no
│ ▼
│ Check Events, scheduling, image pull, mounts
┌─────────────────────┐
│ Restarted recently? │
└───────┬─────┬───────┘
│yes │no
│ ▼
│ Check current logs with timestamps
Check previous logs, restart reason, Events
If pressure is plausible, compare top metrics with requests and limits

Рамка навмисно консервативна. Вона уникає «читати журнали» як універсального першого кроку, тому що збої Kubernetes часто трапляються до того, як застосунок отримує контроль. Вона також уникає трактування метрик як остаточної відповіді, тому що гарячий Pod може бути симптомом повторних спроб, спричинених збоєм залежності. Найкраща наступна команда — та, яка може усунути гілку дерева рішень з найменшим шумом.

  • Kubernetes захоплює stdout та stderr за домовленістю: kubelet відкриває потоки контейнера з файлів журналів ноди, ось чому застосунки, які пишуть лише в приватні файли, потребують містка, як-от sidecar.
  • Події мають короткий стандартний час зберігання: TTL подій API server за замовчуванням становить одну годину, тож події кластера слід експортувати, якщо вашій команді потрібні хронології інцидентів після безпосереднього вікна усунення несправностей.
  • kubectl top залежить від агрегованого API: команда потребує Metrics Server та API metrics.k8s.io, тож збій може бути проблемою конвеєра спостережуваності, а не проблемою застосунку.
  • Ротація журналів локальна для ноди: налаштування kubelet, такі як максимальний розмір журналу та кількість файлів, захищають дисковий простір, але вони також означають, що локальні для ноди журнали не є надійними архівами інцидентів.
ПомилкаЧому це трапляєтьсяЯк це виправити
Забути --previous під час CrashLoopBackOffПоточний екземпляр контейнера запускається чисто й приховує рядок, який убив попередній екземплярВикористовуйте kubectl logs <pod> --previous та додавайте -c <container> для Pod’ів з кількома контейнерами
Трактувати порожній журнал як доказ того, що нічого не сталосяPending Pod’и, збої завантаження образу та збої монтування можуть статися до того, як запуститься код застосункуПеревіряйте kubectl describe pod та події Warning, перш ніж покладатися на журнали
Читати не той контейнер у Pod’іSidecar’и, init-контейнери та проксі створюють кілька потоків журналів під одним іменем Pod’аПерелічіть імена контейнерів і усвідомлено обирайте -c <container> чи --all-containers=true
Ігнорувати час зберігання подійПодії короткочасні й можуть зникнути до початку відкладеного аналізу інцидентуЕкспортуйте події в надійне логування й фіксуйте вивід подій під час інциденту
Припускати, що kubectl top вбудований усюдиMetrics Server є окремим компонентом і може бути відсутнім чи нездоровимПеревіряйте Pod Metrics Server та APIService metrics.k8s.io, перш ніж діагностувати використання застосунку
Порівнювати метрики лише з лімітамиЗапити впливають на планування, ліміти впливають на примусове виконання, і кожен відповідає на інше питанняПорівнюйте поточне використання із запитами, лімітами, ємністю ноди та причинами перезапуску
Починати з SSH на ноду для звичайних збоїв Pod’аПрямий доступ до ноди втрачає контекст об’єкта Kubernetes і може відволікти від простих підказок життєвого циклуПочинайте з подій, виводу describe та журналів; використовуйте журнали ноди, коли вигляду API недостатньо
Фільтрувати журнали занадто раноgrep може видалити контекст часу чи пропустити інакше названі повідомлення про збійСпершу звужуйте за часом, потім шукайте сімейства помилок, такі як exception, fatal, failed та panic
Питання 1: Ваша команда розгортає новий образ, і Pod входить у `CrashLoopBackOff`. `kubectl logs my-app` показує лише банер запуску. Що ви перевіряєте далі й чому?

Використайте kubectl logs my-app --previous, додаючи -c <container>, якщо Pod має більше одного контейнера. Звичайна команда журналів читає поточний екземпляр контейнера, який, можливо, лише запустився й ще не дійшов до проблемного рядка. --previous запитує в kubelet останній завершений екземпляр, де зазвичай присутні трасування стека, повідомлення про відсутню конфігурацію чи фатальна помилка запуску. Прочитавши його, співвіднесіть мітку часу з подіями, щоб ви могли відокремити збій застосунку від проби чи примусового виконання ресурсів.

Питання 2: Pod застряг у стані `Pending`, і молодший адміністратор хоче запустити `kubectl logs`, щоб знайти скаргу застосунку. Що вам слід зробити натомість?

Почніть з kubectl describe pod <pod> та нещодавніх подій Warning для Простору імен. Pending Pod зазвичай не запустив контейнер, тож може не бути виводу застосунку для отримання. Події можуть показати FailedScheduling, неприв’язані PVC, taint’и, невідповідності affinity чи недостатній CPU та пам’ять. Щойно Pod досягне стану контейнера, журнали стануть корисними, але до того площина управління є джерелом доказів.

Питання 3: `kubectl top pods -n production` повертає помилку, що метрики недоступні. Ваш kubeconfig та RBAC коректні. Який компонент є ймовірним фокусом?

Огляньте Metrics Server та APIService metrics.k8s.io, перш ніж змінювати маніфести застосунку. kubectl top не читає cgroup’и Pod’а напряму; він запитує агрегований API метрик, який обслуговує Metrics Server. Metrics Server має працювати, бути здатним опитувати endpoint’и ресурсів kubelet та бути зареєстрованим як доступний APIService. Якщо цей конвеєр зламано, kubectl top відмовляє, навіть якщо робочі навантаження споживають CPU та пам’ять.

Питання 4: Pod має основний контейнер застосунку та sidecar-пересилач журналів. Ви підозрюєте, що обидва задіяні в збої. Як уникнути читання лише половини доказів?

Спершу перелічіть контейнери за допомогою kubectl get pod <pod> -o jsonpath='{.spec.containers[*].name}', потім прочитайте релевантні потоки за допомогою kubectl logs <pod> -c <container> чи використайте --all-containers=true, коли співвіднесення має значення. Саме лише ім’я Pod’а не гарантує, що потік, який ви бачите, належить проблемному компоненту. Sidecar’и можуть провалити автентифікацію, проксі можуть відхиляти трафік, а init-контейнери можуть залишити підказки про налаштування, які основний контейнер ніколи не повторює. Вибір контейнера тримає розслідування прив’язаним до межі компонента.

Питання 5: Пакетне завдання провалилося два дні тому, але `kubectl get events` не повертає корисних записів. Чи доводить це, що Kubernetes не видавав подій?

Ні. Події — це короткочасні об’єкти Kubernetes, і стандартний TTL подій становить одну годину, якщо API server не налаштований інакше. До моменту, коли ви розслідуєте дводенний збій, початкові події планування, завантаження, монтування чи проб могли бути зібрані як сміття. Для довгих хронологій інцидентів відправляйте події в надійне логування чи сховище спостережуваності, поки вони свіжі. Для поточного розслідування покладайтеся на збережені журнали застосунку, статус завдання, стан завершення Pod’а та зовнішній моніторинг.

Питання 6: Pod працює, але повільно, `kubectl top pod` показує високий CPU, і перезапусків немає. Який наступний діагностичний напрям?

Порівняйте поточне використання CPU із запитами та лімітами Pod’а, потім перевірте, чи дроселювання, чи насичення пояснюють симптом. Високий CPU без перезапусків указує менше на падіння й більше на продуктивність, ліміти, повторні спроби залежностей чи дисбаланс навантаження. Події все ще можуть мати значення, якщо проби провалюються, але попередні журнали навряд чи допоможуть, якщо контейнер не перезапустився. Корисний шлях — пов’язати метрики, затримку, ліміти та журнали застосунку для одного й того ж часового вікна.

Питання 7: API server тимчасово недосяжний, але у вас є SSH-доступ до ноди, що запускає критичний Pod. Де ви можете шукати журнали контейнерів, і яка пересторога застосовується?

На ноді огляньте /var/log/containers/ на предмет символьних посилань, названих за Pod’ом, Простором імен, контейнером та ID контейнера, потім обережно слідуйте за відповідним файлом. Цими файлами керують kubelet та середовище виконання контейнерів, тож вони корисні, коли звичайний шлях API недоступний. Уникайте редагування чи видалення файлів журналів ноди під час діагностики, тому що ви можете знищити докази чи завадити ротації. Коли доступ до API повернеться, узгодьте докази ноди зі станом об’єкта Kubernetes.

Практична вправа: аналіз журналів та метрик

Розділ «Практична вправа: аналіз журналів та метрик»

Сценарій вправи: ви створите Простір імен з одним Pod’ом, що безперервно видає змішані інформаційні повідомлення та повідомлення про помилки, одним Pod’ом, що повторно падає, та необов’язковим логером файлів у застарілому стилі. Вправа змушує вас використати поточні журнали, попередні журнали, фільтрацію, події та метрики в контрольованому середовищі, перш ніж вони знадобляться вам під час іспиту чи production-інциденту. Запускайте ці команди в одноразовому кластері Kubernetes 1.35+, де дозволено створювати Простір імен та тимчасові Pod’и.

Terminal window
# Create test namespace
kubectl create ns logging-lab
# Create a pod that generates logs
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: log-generator
namespace: logging-lab
spec:
containers:
- name: logger
image: busybox:1.36
command:
- sh
- -c
- |
i=0
while true; do
echo "$(date '+%Y-%m-%d %H:%M:%S') INFO: Log message $i"
if [ $((i % 5)) -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Something went wrong at iteration $i" >&2
fi
i=$((i+1))
sleep 2
done
EOF
# Create a crashy pod for --previous demo
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: crashy-pod
namespace: logging-lab
spec:
containers:
- name: crasher
image: busybox:1.36
command:
- sh
- -c
- |
echo "Starting up..."
sleep 5
echo "About to crash!"
exit 1
EOF
# Wait for log-generator to be ready before proceeding
kubectl wait --for=condition=Ready pod/log-generator -n logging-lab --timeout=60s

Завдання 1: базові операції з журналами

Розділ «Завдання 1: базові операції з журналами»

Використайте це завдання, щоб довести, що ви можете прочитати поточний потік, недовго слідкувати за ним, обмежити вивід та додати мітки часу. Зупиніть стеження за допомогою Ctrl+C після того, як побачите кілька рядків; мета — підтвердити потік і потім перейти до цілеспрямованого збору доказів, а не дивитися журнали нескінченно.

Terminal window
# View logs
kubectl logs -n logging-lab log-generator
# Follow logs
kubectl logs -n logging-lab log-generator -f
# (Ctrl+C to stop)
# Last 10 lines
kubectl logs -n logging-lab log-generator --tail=10
# With timestamps
kubectl logs -n logging-lab log-generator --tail=10 --timestamps
Нотатки до розв'язку Завдання 1

Ви маєте побачити повторювану суміш повідомлень INFO та зрідка повідомлень ERROR від того самого контейнера. Прапорець --tail має зменшити вивід до невеликого нещодавнього вікна, а --timestamps має додати мітки часу журналу Kubernetes перед кожним рядком. Якщо Pod ще не ready, зачекайте кілька секунд та перевірте kubectl describe pod -n logging-lab log-generator, перш ніж припускати, що команда журналів зламана.

Завдання 2: фільтрація журналів

Розділ «Завдання 2: фільтрація журналів»

Фільтрація вчить вас зменшувати шум після того, як ви підтвердили потік. Запустіть пошуки помилок, підрахуйте відповідні рядки, а потім виключіть інформаційні рядки. Зауважте, що кожен конвеєр відповідає на інше питання: один знаходить приклади, один вимірює приблизну частоту, а один показує все, що не є рутинним інформаційним виводом.

Terminal window
# Find errors only
kubectl logs -n logging-lab log-generator | grep ERROR
# Count errors
kubectl logs -n logging-lab log-generator | grep -c ERROR
# Exclude INFO messages
kubectl logs -n logging-lab log-generator | grep -v INFO
Нотатки до розв'язку Завдання 2

Лічильник помилок має зростати з часом, тому що Pod видає помилку кожні кілька ітерацій. Якщо лічильник дорівнює нулю, Pod, можливо, лише запустився, або ваша команда читає не той Простір імен. У реальному інциденті ви зазвичай поєднували б фільтрацію з --since чи --since-time, щоб лічильник відображав вікно інциденту замість усього часу життя Pod’а.

Завдання 3: попередні журнали контейнера

Розділ «Завдання 3: попередні журнали контейнера»

Pod, що падає, розроблений, щоб показати, чому поточний потік та попередній потік різні. Спостерігайте за Pod’ом, доки не побачите перезапуски чи CrashLoopBackOff, потім отримайте попередній екземпляр. Це той самий крок, який ви використовуєте, коли застосунок запускається, друкує банер, виходить і перезапускається занадто швидко, щоб поточний потік журналів виявив фатальний рядок.

Terminal window
# Wait for crashy-pod to crash and restart
kubectl get pod -n logging-lab crashy-pod -w
# (Press Ctrl+C to stop once you see CrashLoopBackOff)
# When it shows CrashLoopBackOff or restarts, check previous logs
kubectl logs -n logging-lab crashy-pod --previous
Нотатки до розв'язку Завдання 3

Попередні журнали мають включати Starting up..., за яким іде About to crash!. Якщо --previous повертає, що попереднього завершеного контейнера не існує, зачекайте на перший перезапуск і спробуйте знову. Ключова звичка — використовувати статус Pod’а та лічильник перезапусків, щоб вирішити, чи поточні чи попередні журнали відповідають екземпляру збою.

Завдання 4: аналіз подій

Розділ «Завдання 4: аналіз подій»

Події мають показати життєвий цикл навколо Pod’а, що падає, включно зі створенням, запуском, завершенням та поведінкою backoff. Сортуйте за міткою часу, щоб ви могли прочитати послідовність, а не таблицю, що виглядає випадковою. Потім використайте describe, щоб побачити розділ Events у контексті зі статусом Pod’а та станом контейнера.

Terminal window
# All events in namespace
kubectl get events -n logging-lab --sort-by='.lastTimestamp'
# Describe pod for events
kubectl describe pod -n logging-lab crashy-pod | grep -A 10 Events
# Watch for new events
kubectl get events -n logging-lab -w
Нотатки до розв'язку Завдання 4

Ви маєте побачити події, які відповідають життєвому циклу Pod’а та поведінці backoff. Повідомлення подій не є заміною журналів застосунку, але вони пояснюють, що kubelet робить ззовні. Якщо події не з’являються, підтвердьте, що ви в правильному Просторі імен, і пам’ятайте, що старі події застарівають, тож нещодавню активність легше спостерігати, ніж історичну.

Завдання 5: метрики (якщо встановлено Metrics Server)

Розділ «Завдання 5: метрики (якщо встановлено Metrics Server)»

Запускайте команди метрик лише якщо ваш лабораторний кластер має встановлений та здоровий Metrics Server. Якщо вони відмовляють, трактуйте збій як валідну діагностичну гілку: перевірте, чи існує Metrics Server, чи зареєстрований API метрик і чи підтримує його середовище кластера. Не переписуйте запити застосунку на основі відсутніх метрик, доки не дізнаєтеся, що конвеєр метрик працює.

Terminal window
# Node metrics
kubectl top nodes
# Pod metrics
kubectl top pods -n logging-lab
# All pods by memory
kubectl top pods -A --sort-by=memory | head
Нотатки до розв'язку Завдання 5

Якщо Metrics Server присутній, ви маєте побачити поточне використання CPU та пам’яті для нод і Pod’ів. Числа можуть бути малими, тому що лабораторні Pod’и легкі. Якщо команда відмовляє з помилкою API метрик, огляньте kubectl -n kube-system get pods | grep metrics-server та kubectl get apiservices | grep metrics замість того, щоб припускати, що робоче навантаження не має використання ресурсів.

Завдання 6: виклик з sidecar-логуванням файлів

Розділ «Завдання 6: виклик з sidecar-логуванням файлів»

Цей необов’язковий виклик реалізує місток «файл-до-stdout» з основного уроку. Основний контейнер пише у файл на спільному emptyDir, а sidecar відстежує цей файл командою tail до власного стандартного виводу. Запитайте журнали sidecar, потім поясніть, чому журнали основного контейнера менш корисні для застосунків, що пишуть лише у файли.

Terminal window
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: file-logger
namespace: logging-lab
spec:
containers:
- name: main-app
image: busybox:1.36
command:
- sh
- -c
- |
i=0
while true; do
echo "$(date '+%Y-%m-%d %H:%M:%S') file log $i" >> /var/log/app.log
i=$((i+1))
sleep 2
done
volumeMounts:
- name: shared-logs
mountPath: /var/log
- name: log-tailer
image: busybox:1.36
command: ["sh", "-c", "touch /var/log/app.log 2>/dev/null; tail -n+1 -F /var/log/app.log"]
volumeMounts:
- name: shared-logs
mountPath: /var/log
volumes:
- name: shared-logs
emptyDir: {}
EOF
kubectl wait --for=condition=Ready pod/file-logger -n logging-lab --timeout=60s
kubectl logs -n logging-lab file-logger -c log-tailer --tail=10
Нотатки до розв'язку Завдання 6

Корисні рядки журналу файлу мають з’явитися з контейнера log-tailer, а не з основного контейнера застосунку. Це демонструє, чому власне для Kubernetes логування віддає перевагу прямому stdout та stderr, і чому sidecar є лише містком для застарілої поведінки. У production ви також подумали б про ротацію, запити ресурсів для sidecar та надійне відправлення журналів за межі ноди.

Наведені нижче вправи зберігають швидкі патерни команд з оригінального модуля. Запускайте їх після основних завдань, доки не зможете обрати правильну команду за симптомом без паузи. Вони навмисно короткі, але міркування за ними тепер мають бути зрозумілими з розділів робочого процесу вище.

Вправа 1: переглянути останні N журналів (30 сек)

Розділ «Вправа 1: переглянути останні N журналів (30 сек)»
Terminal window
# Task: Show last 20 log lines
kubectl logs <pod> --tail=20

Вправа 2: журнали з мітками часу (30 сек)

Розділ «Вправа 2: журнали з мітками часу (30 сек)»
Terminal window
# Task: Show logs with timestamps
kubectl logs <pod> --timestamps

Вправа 3: попередні журнали контейнера (30 сек)

Розділ «Вправа 3: попередні журнали контейнера (30 сек)»
Terminal window
# Task: Get logs from crashed container
kubectl logs <pod> --previous

Вправа 4: журнали з кількох контейнерів (1 хв)

Розділ «Вправа 4: журнали з кількох контейнерів (1 хв)»
Terminal window
# Task: Get logs from specific container
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].name}'
kubectl logs <pod> -c <container-name>

Вправа 5: нещодавні події (30 сек)

Розділ «Вправа 5: нещодавні події (30 сек)»
Terminal window
# Task: Show events sorted by time
kubectl get events --sort-by='.lastTimestamp'

Вправа 6: події Warning (30 сек)

Розділ «Вправа 6: події Warning (30 сек)»
Terminal window
# Task: Show only warning events
kubectl get events --field-selector type=Warning

Вправа 7: метрики нод (30 сек)

Розділ «Вправа 7: метрики нод (30 сек)»
Terminal window
# Task: Show node resource usage
kubectl top nodes

Вправа 8: відсортовані метрики Pod’ів (30 сек)

Розділ «Вправа 8: відсортовані метрики Pod’ів (30 сек)»
Terminal window
# Task: Show top memory-consuming pods
kubectl top pods -A --sort-by=memory | head
  • Переглянуто живі журнали зі стеженням і навмисно зупинено потік.
  • Відфільтровано журнали на предмет помилок і пояснено, що фільтр приховує.
  • Отримано попередні журнали контейнера з Pod’а, що перезапускається.
  • Проаналізовано події на предмет інформації про падіння, життєвий цикл чи backoff.
  • Використано kubectl top, коли Metrics Server був доступний, або діагностовано, чому він був недоступний.
  • Впроваджено логування на основі sidecar для застосунку, що пише у файл.
  • Співвіднесено журнали, події та метрики, щоб обрати наступну діагностичну дію.
Terminal window
kubectl delete ns logging-lab

Перевірка для учня

Розділ «Перевірка для учня»

Звичайна kubectl logs deployment/<name> слідує за зв’язком з контролером, але стрімить журнали лише з одного представницького Pod’а в цьому Деплойменті; додайте --all-pods=true, коли вам потрібна кожна репліка. kubectl logs deployment/my-deployment --all-pods=trueusage above requests: under-requested; scheduling/QoS + eviction risk under node pressurememory near/above limit: OOMKilledCPU at limit: throttled (not killed).

Перейдіть до Частини 6: Пробні іспити, щоб перевірити ці прийоми усунення несправностей під тиском часу в стилі іспиту.