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

Модуль 1.9: Основи налагодження (теорія)

Складність: [ШВИДКИЙ] — мислення для швидкого сортування проблем у Kubernetes 1.35+

Час на проходження: 35–45 хвилин

Передумови: Модулі 1.1–1.8, базовий доступ через kubectl до тренувального кластера та локальна звичка визначати alias k=kubectl перед використанням коротких команд k у цьому модулі

Результати навчання

Розділ «Результати навчання»

Використовуйте наведені нижче результати як практичні орієнтири для своїх нотаток, лабораторних робіт і відповідей на тест упродовж усього модуля:

  1. Налагодити несправне робоче навантаження, дотримуючись повторюваного шляху сортування проблем у Kubernetes — від симптому до ймовірної першопричини.
  2. Проаналізувати фазу Pod’а, стан контейнера, умови (conditions), події та логи, щоб вирішити, який сигнал є найважливішим у сценарії збою.
  3. Порівняти збої завантаження образу, планування, циклу аварійних перезапусків, нестачі пам’яті та проб (probes) за їхніми спостережуваними доказами, а не за здогадками.
  4. Оцінити, до чого належить проблема — до застосунку, специфікації Pod’а, планувальника, ноди чи розгортання контролера.
  5. Спроєктувати контрольний список першого реагування, який зберігає докази, звужує область пошуку та не дає інциденту погіршитися.

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

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

Пізно ввечері у четвер платіжна компанія викотила невеликий реліз оформлення замовлення, який змінив спосіб завантаження облікових даних бази даних її API. Старі Pod’и продовжували обслуговувати трафік, але новий ReplicaSet породжував Pod’и, що перезапускалися кожні кілька секунд, і Deployment застопорився, поки кошики клієнтів періодично давали збій. Згодом звіт про інцидент оцінив утрату понад $85 000 на покинутих транзакціях упродовж першої години, проте найдорожчою помилкою була не сама хибна конфігурація, а те, що перший фахівець, який реагував, видалив Pod’и та перезапустив розгортання ще до того, як хтось зафіксував логи попереднього контейнера, де було названо відсутню змінну середовища.

Така сцена є поширеною, бо збої Kubernetes надходять як стиснуті симптоми, а не як охайні пояснення. Одне-єдине слово на кшталт Pending, Running, CrashLoopBackOff чи ImagePullBackOff може представляти зовсім різні межі відповідальності, і фахівець, який надто рано вгадує, може півгодини ганятися за хибним компонентом. Основи налагодження дають вам дисциплінований спосіб запитати по черзі: чи зміг Kubernetes розмістити Pod, чи зміг kubelet його підготувати, чи запустився процес контейнера, чи залишився застосунок живим і чи стало робоче навантаження готовим приймати трафік.

KCNA не вимагає від вас розв’язувати кожен виробничий інцидент з пам’яті, але очікує, що ви розпізнаєте, де Kubernetes записує докази і чим рішення площини управління відрізняються від фактів на рівні ноди та застосунку. У цьому модулі ви потренуєтеся читати статус Pod’а як хронологію подій, використовувати describe, логи та події для їхніх окремих завдань і проєктувати контрольний список першого реагування, який звужує проблему ще до зміни кластера. Створіть короткий псевдонім командою alias k=kubectl; відтепер команди використовують k get, k describe та споріднені форми, бо саме таку звичку оператора ви побачите в реальних кластерах.

Частина 1: Налагодження — це збір доказів перед дією

Розділ «Частина 1: Налагодження — це збір доказів перед дією»

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

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

KUBERNETES DEBUGGING WITNESSES
┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐
│ Desired State │ │ Cluster Decisions │ │ Runtime Evidence │
│ Deployment, Pod │────▶│ Scheduler, events │────▶│ Kubelet, logs │
│ spec, probes, env │ │ placement, reasons │ │ exits, restarts │
└────────────────────┘ └────────────────────┘ └────────────────────┘
│ │ │
▼ ▼ ▼
"What did we ask for?" "What did Kubernetes try?" "What actually ran?"

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

THE FIRST RESPONSE LOOP
┌───────────────┐
│ 1. Scope │ k get pods -A -o wide
│ problem size │ One pod, one node, one namespace, or many?
└───────┬───────┘
┌───────────────┐
│ 2. Describe │ k describe pod <pod> -n <namespace>
│ object story │ Conditions, container states, events, mounts, probes
└───────┬───────┘
┌───────────────┐
│ 3. Read logs │ k logs <pod> -n <namespace> [-p] [-c <container>]
│ app witness │ Current or previous container output
└───────┬───────┘
┌───────────────┐
│ 4. Widen view │ k get events -n <namespace> --sort-by=.lastTimestamp
│ timeline │ Related failures from scheduler, kubelet, and controllers
└───────────────┘

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

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

Видалення Pod’а, керованого Deployment, може бути розумним кроком відновлення після того, як докази зібрано, бо контролер створить заміну з того самого шаблону. Це поганий перший крок, коли попередній екземпляр мав єдиний корисний стек викликів, коли важливий порядок подій або коли вам ще потрібно з’ясувати, що зазнало збою першим — планувальник, kubelet чи застосунок. Безпечніша звичка — зафіксувати статус, попередні логи та події, сформулювати гіпотезу, а потім вирішити, чи відповідає доказам перезапуск, відкат, виправлення Secret, зміна ресурсів або коригування проби.

Корисний спосіб тренувати стриманість — описати збій у термінах відповідальності перш ніж щось чіпати. «Планувальник не призначив ноду» спрямовує вас до ресурсів, taint’ів, affinity, топології чи прив’язки сховища. «kubelet не може завантажити образ» спрямовує до тегів, облікових даних реєстру та доступності мережі. «Застосунок запустився та завершився з відсутнім налаштуванням» спрямовує до конфігурації та відповідальності за реліз. Така мова відповідальності запобігає класичній помилці початківця — вважати кожен червоний Pod помилкою застосунку чи кожну помилку застосунку помилкою Kubernetes. Назвавши власника вголос ще до першої команди, ви також полегшуєте собі вибір правильного джерела доказів, бо кожен власник має свого свідка: планувальник, kubelet чи сам процес застосунку.

Частина 2: Читайте стан Pod’а як хронологію

Розділ «Частина 2: Читайте стан Pod’а як хронологію»

Рядок статусу Pod’а — це стиснута хронологія, а не остаточний діагноз. STATUS у k get pods часто показує причину з боку контейнера, вибрану для зручності читання людиною, тоді як фаза Pod’а — це ширша категорія життєвого циклу, як-от Pending, Running, Succeeded, Failed чи Unknown. Ця різниця важлива, бо Pod може бути у фазі Running, поки один контейнер не готовий, і Pod може здаватися Pending тому, що його не заплановано, або тому, що його вже призначено ноді, поки kubelet готує образи й томи.

Terminal window
k get pods -n default -o wide
NAME READY STATUS RESTARTS AGE IP NODE
api-6d8b7c9f5c-f2mzp 0/1 CrashLoopBackOff 9 18m 10.244.1.8 worker-a
web-76bc6c9d7b-9nq5p 1/1 Running 0 42m 10.244.2.4 worker-b
report-5d9c997d8d-xr2hg 0/1 Pending 0 11m <none> <none>

Стовпець READY каже вам, скільки звичайних контейнерів готові порівняно з тим, скільки їх визначає Pod. Стовпець STATUS подає стислу причину, що часто походить від найважливішого поточного чи нещодавнього стану контейнера, тоді як RESTARTS каже вам, чи kubelet неодноразово запускав контейнер після завершення. Стовпець NODE не менш важливий за драматичніший текст статусу, бо відсутня нода означає, що планувальник не розмістив Pod, а названа нода означає, що розслідування перейшло до доказів kubelet, образу, тому, проби, ресурсів чи застосунку.

POD LIFECYCLE STATE DIAGRAM
┌──────────┐
Pod created │ │
────────────▶│ Pending │──── Scheduler cannot place pod
│ │ because resources, taints,
└────┬─────┘ affinity, or volumes block it
│ Scheduled to a node
┌──────────┐
│ Waiting │──── Kubelet is preparing containers,
│ │ pulling images, or mounting volumes
└────┬─────┘
│ Containers started
┌──────────┐ ┌────────────┐
│ Running │────▶│ Terminated │
│ │ │ │
└────┬─────┘ └─────┬──────┘
│ │
│ ▼
│ ┌──────────────┐
│ │ Restarted or │
│ │ stays failed │
│ └──────────────┘
┌───────────┐
│ Succeeded │──── Normal for Jobs when all containers exit 0
└───────────┘
Special: Unknown means the control plane cannot determine pod state from the node.

Перекладіть кожен видимий статус у сфокусоване запитання. Pending запитує, чи призначив планувальник ноду, а якщо ні — яке правило планування заблокувало розміщення. ImagePullBackOff запитує, чи може kubelet дістатися реєстру й автентифікуватися в ньому та чи існує згаданий образ. CrashLoopBackOff запитує, що надрукував чи з яким кодом завершився попередній екземпляр контейнера, тоді як Running із готовністю 0/1 запитує, яка умова чи проба заважає трафіку Сервісу. Такий переклад утримує вас від запуску знайомих команд, що не відповідають стадії збою.

СигналНайкорисніше перше запитанняНайкращі перші докази
Pending без нодиЧому планувальник не зміг розмістити цей Pod?Розділ Events у k describe pod
ImagePullBackOffЯку саме помилку завантаження образу повідомив kubelet?Події Pod’а з k describe pod
CrashLoopBackOffЧому завершився попередній контейнер?k logs <pod> -p та Last State
Running, але не ReadyЯка умова готовності чи проба зазнає збою?Умови Pod’а, ендпоінти та події проб
OOMKilledЧи перевищив контейнер свій ліміт пам’яті?Причина Last State, код виходу, ліміти ресурсів
UnknownЧи нода недосяжна або несправна?Умови ноди та події ноди

Умови Pod’а дають структурованіше подання, ніж однорядковий статус, бо вони показують, які віхи життєвого циклу є істинними чи хибними. PodScheduled означає, що планувальник призначив ноду, Initialized означає, що init-контейнери завершилися, ContainersReady означає, що всі контейнери застосунку звітують про готовність, а Ready означає, що Pod має приймати трафік через Сервіси, які його обирають. Pod може бути живим, але некорисним, якщо Ready хибний, і саме тому Kubernetes відокремлює існування процесу від придатності приймати трафік.

УмоваЩо вона означаєІнтерпретація для налагодження
PodScheduledPod призначено ноді.Якщо хибна, зосередьтеся на подіях планувальника, ресурсах, taint’ах, affinity та томах.
Initializedinit-контейнери успішно завершилися.Якщо хибна, перевірте логи init-контейнерів та налаштування томів чи дозволів.
ContainersReadyУсі контейнери застосунку звітують про готовність.Якщо хибна, перевірте стани контейнерів, проби готовності та помилки залежностей.
ReadyPod має приймати трафік Сервісу.Якщо хибна, трафік не слід маршрутизувати до цього Pod’а, навіть якщо він запущений.

Стани контейнерів конкретніші за умови Pod’а, бо кожен звичайний, init- чи sidecar-контейнер може окремо перебувати у стані очікування, виконання чи завершення. У багатоконтейнерному Pod’і логувальний sidecar може бути справним, поки головний API дає збій, або init-контейнер може блокувати весь Pod ще до запуску образу застосунку. Завжди називайте контейнер через -c <container>, коли логи чи стан неоднозначні, і використовуйте поточний стан разом з останнім станом, щоб зрозуміти і те, що відбувається зараз, і те, що сталося під час попередньої спроби.

Стан контейнераЗначенняЩо перевірити
WaitingКонтейнер не запустився або відкочується перед наступною спробою запуску.Поле reason, як-от ImagePullBackOff, ContainerCreating чи CrashLoopBackOff.
RunningПроцес наразі виконується всередині контейнера.Час запуску, готовність, проби та чи були нещодавно перезапуски.
TerminatedПроцес завершився або був завершений примусово.Код виходу, причина, час завершення та попередні логи з k logs -p.

Що сталося б, якби ви подивилися лише на k get pods, побачили Running і сказали команді, що сервіс справний? Поясніть, чому це може бути хибним, коли стовпець READY показує 0/1.

Зріле прочитання стану Pod’а уникає двох пасток, що трапляються і на іспитах, і на реальних чергуваннях. Перша пастка — вважати стовпець STATUS людським діагнозом, тоді як це лише підказка, згенерована зі стану життєвого циклу в один момент. Друга пастка — припускати, що всі збої є збоями застосунку; Kubernetes може бути не в змозі запланувати Pod, змонтувати том, завантажити образ, задовольнити пробу чи утримати ноду на зв’язку, навіть коли код застосунку правильний. Уникнути обох пасток допомагає одна проста дисципліна: ставтеся до кожного значення статусу як до запитання, на яке ще треба відповісти, а не як до готового вердикту, і завжди звіряйте його з іншим джерелом доказів, перш ніж діяти.

Частина 3: Використовуйте describe, логи та події, не змішуючи їхніх завдань

Розділ «Частина 3: Використовуйте describe, логи та події, не змішуючи їхніх завдань»

k describe pod — найкращий міст між бажаним станом і поведінкою кластера. Він показує ідентичність, мітки, посилання на власників, призначення ноди, IP-адреси, умови, змонтовані томи, посилання на змінні середовища, стани контейнерів, запити й ліміти ресурсів, проби та нещодавні події в одній команді. Така широта корисна, бо реальні інциденти часто містять суперечності — як-от контейнер, що успішно запускається, але провалює готовність, Pod, який заплановано, але заблоковано монтуванням тому, або Deployment, чиї нові Pod’и всі дають збій, поки старий ReplicaSet лишається справним.

Terminal window
k describe pod api-6d8b7c9f5c-f2mzp -n default

Читаючи describe, дотримуйтеся послідовного порядку, щоб ваші очі не стрибали хаотично виводом. Спершу підтвердьте простір імен, ім’я, мітки та власника, бо налагодження не того об’єкта трапляється частіше, ніж люди визнають. Потім перевірте ноду, фазу, умови та стан контейнера, приділяючи пильну увагу останньому стану, лічильнику перезапусків, ресурсам, команді, аргументам і пробам. Нарешті, читайте розділ Events від найстаршого доречного рядка до найновішого доречного рядка, бо нижня частина часто каже вам, що kubelet чи планувальник наразі повторно намагається зробити.

HOW TO READ kubectl describe pod
┌──────────────────────────────┐
│ Identity │ Name, namespace, labels, owner, node
├──────────────────────────────┤
│ Status and Conditions │ Phase, Ready, ContainersReady, Scheduled
├──────────────────────────────┤
│ Container Details │ Image, ports, command, state, last state
├──────────────────────────────┤
│ Configuration References │ Env, ConfigMaps, Secrets, volumes, probes
├──────────────────────────────┤
│ Events │ Scheduler and kubelet timeline of actions
└──────────────────────────────┘

Логи відповідають на вужче запитання: що процес контейнера записав у стандартний вивід і стандартний потік помилок. Вони центральні, коли процес запустився та завершився, але вони не пояснюють незапланований Pod, тег образу, який не вдається отримати, або PersistentVolumeClaim, який не може прив’язатися. Для циклів аварійних перезапусків прапорець -p зазвичай є різницею між тим, щоб побачити справжній збій запуску, і тим, щоб не побачити нічого корисного з поточної спроби очікування.

Terminal window
k logs api-6d8b7c9f5c-f2mzp -n default
k logs api-6d8b7c9f5c-f2mzp -n default -p
k logs api-6d8b7c9f5c-f2mzp -n default -c api

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

Terminal window
k get events -n default --sort-by=.lastTimestamp

Практичне правило — не перетинати потоки доказів надто рано. Якщо подія каже 0/3 nodes are available: 3 Insufficient memory, код застосунку не є вашим першим напрямком розслідування, бо контейнер ніколи не мав місця для запуску. Якщо попередні логи кажуть FATAL: missing DB_PASSWORD, описувати кожну ноду в кластері — це відволікання, бо застосунок уже назвав залежність запуску. Найшвидші оператори — не ті, хто знає найдовший список команд; це ті, хто дозволяє кожному сигналу обирати наступну команду.

Компроміс полягає в тому, що жодне джерело доказів не є повним. describe може показати лаконічну подію, якій потрібен контекст з маніфесту, логи можуть показати помилку застосунку, не доводячи, як було змонтовано змінну середовища, а події можуть підсумувати повторюваний збій, не зберігаючи кожну історичну спробу. Ви розв’язуєте це, поєднуючи джерела в хронологію: бажаний стан запросив X, Kubernetes спробував Y, нода повідомила Z, а застосунок або запустився, або ні. Така хронологія дає вам обґрунтовану наступну дію замість здогадки.

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

В командних інцидентах така чіткість також покращує комунікацію. Сказати «Pod у статусі Pending, бо планувальник повідомляє про нестачу пам’яті» значно корисніше, ніж сказати «Pod зламаний». Сказати «контейнер запустився та завершився, повідомивши про відсутній ключ Secret» дає власнику застосунку чи платформи точну передачу. Хороша мова налагодження описує спостережувану стадію, джерело доказів і наступну безпечну дію, щоб інший інженер міг проаудитувати ваші міркування, не переграючи кожну команду. Така точність також пришвидшує передачу між змінами: фахівець, який заступає на чергування, одразу бачить, що вже перевірено, яка гіпотеза наразі активна та яка дія чекає на підтвердження, замість того щоб починати розслідування з нуля.

Частина 4: Робочий приклад — діагностуйте, перш ніж виправляти

Розділ «Частина 4: Робочий приклад — діагностуйте, перш ніж виправляти»

Припустімо, команда розгортає версію 1.8.2 API, і розгортання застопорюється. Старі Pod’и продовжують обслуговувати трафік, але новий ReplicaSet створює Pod’и, які так і не стають готовими, і релізний менеджер запитує, чи це поганий образ, проблема планування чи проблема застосунку. Дисциплінований фахівець спершу визначає область збою, бо патерн «старі Pod’и справні, а нові несправні» вказує на новий шаблон, новий образ чи конфігурацію, яку використовує лише нова версія.

Terminal window
k get pods -n shop -o wide
NAME READY STATUS RESTARTS AGE NODE
api-58c7d5f9b6-m2q8x 1/1 Running 0 2d worker-a
api-58c7d5f9b6-r6ndk 1/1 Running 0 2d worker-b
api-7b9c6d4f78-jk2tp 0/1 CrashLoopBackOff 6 9m worker-a

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

Terminal window
k logs api-7b9c6d4f78-jk2tp -n shop -p
2026-04-26T09:15:12Z starting api service
2026-04-26T09:15:12Z loading configuration from environment
2026-04-26T09:15:12Z FATAL missing required environment variable: DB_PASSWORD

Повідомлення логу вагоме, але старший фахівець усе одно перевіряє, як Kubernetes попросили надати це налаштування. Застосунок каже, що йому потрібен DB_PASSWORD; describe може показати, чи це значення береться з Secret, чи має контейнер останній стан і код виходу, що відповідають збою, і чи показують події kubelet повторюваний відкат. Така перевірка запобігає надто швидкому висновку на кшталт «база даних не працює», коли справжній збій — це відсутня конфігурація.

Terminal window
k describe pod api-7b9c6d4f78-jk2tp -n shop
State: Waiting
Reason: CrashLoopBackOff
Last State: Terminated
Reason: Error
Exit Code: 1
Environment:
DB_HOST: postgres.shop.svc.cluster.local
DB_PASSWORD: <set to the key 'password' in secret 'api-db'>
Events:
Warning BackOff kubelet Back-off restarting failed container api

Ймовірна першопричина тепер достатньо конкретна, щоб безпечно її перевірити: новий Pod очікує ключ Secret, який відсутній, перейменований, порожній або відсутній у просторі імен shop. Наступні перевірки мають оглянути об’єкт Secret, а потім розгортання Deployment, а не видаляти випадкові Pod’и чи редагувати живий Pod. Якщо Secret виправлено або шаблон Deployment вилікувано, фахівець має переконатися, що розгортання просувається, новий Pod стає готовим (Ready), а старі Pod’и замінюються відповідно до стратегії Deployment.

Terminal window
k get secret api-db -n shop
k describe secret api-db -n shop
k rollout status deployment/api -n shop

Цей робочий приклад показує різницю між збором доказів і збором команд. CrashLoopBackOff обрав попередні логи, попередні логи обрали конфігурацію, describe пов’язав цю конфігурацію з посиланням на Secret, а статус розгортання перевірив, чи контролер відновився після виправлення основної проблеми. Той самий патерн працює, коли симптом змінюється: почніть зі стадії збою, оберіть свідка для цієї стадії і лише потім обирайте дію. Якби симптомом натомість був Pending, ланцюжок доказів почався б з подій планувальника, а не з логів; якби це був ImagePullBackOff, він почався б з повідомлення kubelet про завантаження. Стадія завжди обирає свідка, а свідок завжди обирає наступну команду.

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

Частина 5: Патерни збоїв, які ви маєте розпізнавати

Розділ «Частина 5: Патерни збоїв, які ви маєте розпізнавати»

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

Ці патерни також допомагають уникати хибних подібностей. CrashLoopBackOff та ImagePullBackOff обидва виглядають тривожно у стовпці статусу, але один означає, що процес запустився, а інший — що процес навіть не вдалося створити. Pending і Running з готовністю 0/1 обидва можуть блокувати розгортання, але один належить до розміщення, а інший — до запуску чи справності. Коли два симптоми виглядають здалеку схожими, спершу порівняйте стадію життєвого циклу, а потім порівняйте докази.

CrashLoopBackOff означає, що контейнер запустився, завершився, а тепер перезапускається із затримкою. Kubernetes не каже, чому застосунок зазнав збою; він каже, що kubelet відкочується перед наступною спробою. Причиною може бути погана команда, відсутня змінна середовища, виняток застосунку, невдала залежність, неправильний дозвіл на файл, неможлива міграція при запуску чи проба життєздатності (liveness), яка вбиває процес після його запуску. Оскільки процес уже запускався, попередні логи та останній стан — це ваші найефективніші перші докази.

Terminal window
k logs <pod-name> -n <namespace> -p
k describe pod <pod-name> -n <namespace>

Цей патерн важливий, бо початківці часто оглядають лише поточні логи й пропускають корисний збій із завершеного екземпляра. У щільному циклі перезапусків поточний контейнер може очікувати, запускатися чи ще не дійти до точки збою, тоді як -p запитує вивід останнього завершеного контейнера. Якщо кожна репліка того самого Deployment аварійно завершується однаково, підозрюйте спільний образ, команду, конфігурацію, Secret, ConfigMap, пробу чи залежність, перш ніж винуватити одну ноду.

5.2 ImagePullBackOff та ErrImagePull

Розділ «5.2 ImagePullBackOff та ErrImagePull»

ErrImagePull та ImagePullBackOff означають, що kubelet не може отримати образ контейнера. Код застосунку ще не запускався, тож логи зазвичай порожні чи недоступні, а exec неможливий, бо немає створеного контейнера, у який можна зайти. Повідомлення події — це головна підказка, бо воно може відрізнити тег, який ніколи не публікувався, від збою автентифікації реєстру, відмови в доступі на завантаження, неправильного шляху до репозиторію, збою DNS, тайм-ауту мережі чи відключення реєстру.

Terminal window
k describe pod <pod-name> -n <namespace>

Шукайте фрази в подіях на кшталт manifest unknown, not found, pull access denied, unauthorized чи помилки тайм-ауту, а потім підбирайте виправлення до того точного формулювання. Образ із правильним на вигляд ім’ям усе одно може дати збій, якщо CI-конвеєр опублікував інший тег, простору імен бракує посилання imagePullSecrets, шлях реєстру змінився чи нода не може дістатися реєстру. Зміна проб чи конфігурації застосунку не може допомогти, доки kubelet не зможе завантажити та створити контейнер.

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

Terminal window
k describe pod <pod-name> -n <namespace>
k get nodes -o wide

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

OOMKilled означає, що процес перевищив свій ліміт пам’яті, і ядро його вбило. Kubernetes записує це в останній стан контейнера, і код виходу часто 137, бо процес отримав примусовий сигнал завершення. Pod потім може увійти в CrashLoopBackOff, якщо політика перезапуску чи контролер-власник продовжують запускати той самий ненажерливий до пам’яті процес під тим самим лімітом.

Terminal window
k describe pod <pod-name> -n <namespace>

Безпосереднє порівняння — між лімітом пам’яті контейнера та фактичною поведінкою пам’яті застосунку. Збільшення ліміту може бути слушним пом’якшенням, коли початковий ліміт був нереалістичним, але це не завжди повне виправлення. Витік пам’яті, необмежений кеш, випадкове велике пакетне завантаження чи налаштування купи (heap) середовища виконання можуть зрештою спожити будь-який більший ліміт, тож хороше налагодження відрізняє невідповідність ємності від зростання, яке слід виправити в застосунку.

5.5 Збої проб і Pod’и, що працюють, але не готові

Розділ «5.5 Збої проб і Pod’и, що працюють, але не готові»

Pod може працювати, але не отримувати трафіку Сервісу, бо провалилася готовність. Збої життєздатності (liveness) перезапускають контейнер, збої готовності (readiness) видаляють Pod з ендпоінтів, а проби запуску (startup) дають повільним застосункам час до того, як почнеться liveness. Збої проб поширені після зміни порту, шляху, схеми, тривалості запуску, поведінки автентифікації чи залежності, і їх особливо легко неправильно прочитати, бо STATUS може досі казати Running.

Terminal window
k describe pod <pod-name> -n <namespace>
k get endpoints <service-name> -n <namespace>

Небезпечна помилка початківця — побачити Running і припустити, що користувачі можуть дістатися робочого навантаження. Завжди порівнюйте STATUS із READY, а потім оглядайте події на повідомлення на кшталт Readiness probe failed чи Liveness probe failed. Якщо застосунок справний, але проба вказує на неправильний шлях чи порт, виправте пробу. Якщо проба правильна, а застосунок не може її задовольнити, виправте застосунок чи залежність, яку готовність точно викриває.

Є ще один клас збоїв, який варто тримати на думці: невідповідність контролера. Іноді симптом на рівні Pod’а реальний, але причина, чому він постійно повертається, у тому, що контролер-власник постійно створює нові Pod’и з незмінного шаблону. Пряме редагування Pod’а може на мить здаватися робочим, а потім зникнути, коли Deployment замінить Pod. Коли збій прив’язаний до розгортання, завжди пов’язуйте докази Pod’а назад з Deployment, ReplicaSet, Job, StatefulSet чи DaemonSet, який ним володіє.

ПатернГоловний сигналПерша командаЙмовірна область виправлення
Цикл аварійних перезапусківCrashLoopBackOff, зростання перезапусківk logs <pod> -pЗапуск застосунку, команда, конфіг, залежність, проба
Завантаження образуImagePullBackOff, ErrImagePullk describe pod <pod>Посилання на образ, автентифікація реєстру, доступність реєстру/мережі
ПлануванняPending, нода не призначенаk describe pod <pod>Запити, taint’и, affinity, PVC, ємність ноди
Завершення через пам’ятьOOMKilled, код виходу 137k describe pod <pod>Ліміт пам’яті, витік, розмір купи, форма навантаження
Збій готовностіRunning з готовністю 0/1k describe pod <pod>Шлях проби, порт, час запуску, справність залежності
Проблема нодиБагато Pod’ів дають збій на одній нодіk describe node <node>Тиск на ноду, kubelet, мережа, диск, taint’и

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

Частина 6: Побудуйте контрольний список першого реагування

Розділ «Частина 6: Побудуйте контрольний список першого реагування»

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

FIRST-RESPONSE CHECKLIST
┌───────────────────────┐
│ 1. Confirm Context │ Correct cluster, namespace, workload, time window
└───────────┬───────────┘
┌───────────────────────┐
│ 2. Scope Impact │ One pod, many pods, one node, all namespaces
└───────────┬───────────┘
┌───────────────────────┐
│ 3. Classify Failure │ Scheduling, image, runtime, readiness, node
└───────────┬───────────┘
┌───────────────────────┐
│ 4. Inspect Evidence │ Describe, logs, previous logs, events, nodes
└───────────┬───────────┘
┌───────────────────────┐
│ 5. Choose Action │ Roll back, fix config, scale, adjust resources
└───────────┬───────────┘
┌───────────────────────┐
│ 6. Verify Recovery │ Rollout status, readiness, events, endpoints
└───────────────────────┘

Починайте кожну сесію з підтвердження контексту, бо налагодження не того простору імен марнує час і може спричинити випадкові зміни. k config current-context та k get pods -A — це прості запобіжники, особливо в навчальних кластерах, де кілька просторів імен можуть містити робочі навантаження зі схожими назвами. У виробництві команди часто додають підказки в оболонці, конвенції kubeconfig та типові налаштування лише для читання з тієї самої причини: перший крок налагодження — це довести, що ви дивитеся на потрібний кластер і робоче навантаження.

Terminal window
k config current-context
k get pods -A -o wide

Після контексту й області оберіть найвужчу команду доказів, що відповідає стадії збою. Використовуйте describe для повідомлень про планування, завантаження образу, пробу, том і життєвий цикл kubelet. Використовуйте logs -p для попередніх аварійно завершених контейнерів і додавайте -c, коли Pod містить кілька контейнерів. Використовуйте команди ноди, коли багато незв’язаних Pod’ів дають збій на одній ноді або коли статус Pod’а Unknown. Використовуйте команди розгортання, коли старі та нові ReplicaSet поводяться по-різному, бо подання контролера каже вам, чи ізольований збій до нового шаблону.

Terminal window
k rollout status deployment/<deployment-name> -n <namespace>
k get rs -n <namespace>
k describe node <node-name>

Перевірка важлива, бо «виправлення», яке змінює статус одного Pod’а, може не відновити робоче навантаження. Для Deployment перевірте статус розгортання, готовність Pod’ів, лічильники перезапусків та ендпоінти для Сервісів, що обирають ці Pod’и. Для виправлень планування перевірте, що Pod отримує ноду, а потім проходить завантаження образу й запуск контейнера. Для виправлень проб перевірте, що Pod стає готовим (Ready) і що список ендпоінтів Сервісу включає його, бо користувачам важлива придатність приймати трафік, а не саме лише існування процесу.

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

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

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

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

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

ПатернКоли використовуватиЧому це працюєМіркування щодо масштабування
Визначення області перед виправленнямБудь-яке несправне навантаження, особливо під час розгортаньВідокремлює збої одного Pod’а від патернів ноди, простору імен чи кластераВикористовуйте мітки та власників, щоб швидко порівняти репліки між просторами імен
Читання попередніх логів для циклів перезапусківКонтейнери з перезапусками чи CrashLoopBackOffЗахоплює вивід невдалого процесу до того, як наступна спроба його приховаєЦентралізоване логування все одно потрібне, коли Pod’и швидко змінюються
Дотримання посилань на власниківPod’и, створені Deployment, Job, StatefulSet чи DaemonSetЗапобігає прямим редагуванням Pod’а, які контролери перезаписуютьВиправляйте шаблон чи джерело контролера, щоб заміни успадкували зміну
Перевірка придатності до трафікуPod’и у статусі Running, що не обслуговують користувачівГотовність і ендпоінти вирішують маршрутизацію СервісуПеревіряйте зрізи ендпоінтів (endpoint slices) чи бекенди Сервісу у більших кластерах
АнтипатернЩо йде не такКраща альтернатива
Налагодження «спершу перезапуск»Перезапуски стирають хронометраж, попередні логи й іноді єдиний несправний екземплярЗафіксуйте статус, попередні логи та події перед зміною стану
Сприйняття кожної проблеми Pod’а як коду застосункуЗбої планувальника, образу, тому, проби та ноди хибно приписуютьсяКласифікуйте стадію збою перед вибором власника
Редагування живого Pod’аКонтролери відтворюють Pod’и з початкового шаблону, тож виправлення зникаєЗмініть Deployment, StatefulSet, Job чи вихідний маніфест
Оголошення перемоги за одним зеленим Pod’омРозгортання, готовність чи ендпоінти можуть досі бути несправнимиПеревіряйте перебіг контролера й шлях трафіку, а не лише один об’єкт

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

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

Коли це використовувати, а коли — альтернативи

Розділ «Коли це використовувати, а коли — альтернативи»

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

СитуаціяВикористовуйте базовий цикл сортуванняВикористовуйте глибший інструментарій
Один новий Pod дає збій після розгортанняТак, порівняйте старі та нові Pod’и, логи, події й статус розгортанняПізніше, якщо потрібні трейси чи метрики застосунку
Багато незв’язаних Pod’ів дають збій на одній нодіТак, визначте область за нодою й огляньте умови нодиВикористовуйте логи ноди та інфраструктурні інструменти, якщо справність ноди незрозуміла
Запит повільний, але всі Pod’и готові (Ready)Частково, спершу перевірте розгортання та перезапускиВикористовуйте метрики застосунку, трейсинг і налагодження Сервісу/мережі
Загальнокластерний збій впливає на доступ до APIОбмежено, бо команди k можуть давати збійВикористовуйте діагностику площини управління, хмари та інфраструктури

Головний компроміс у тому, що базове сортування чудово локалізує першу очевидну межу збою, але не завжди достатнє, щоб пояснити глибоку поведінку продуктивності чи мережі. Pod може бути готовим (Ready), поки затримка застосунку неприйнятна, а Сервіс може мати ендпоінти, поки проблема NetworkPolicy чи DNS ламає конкретний шлях запиту. Звичка все одно допомагає, бо вона усуває поширені збої життєвого циклу навантаження, перш ніж ви перейдете до агрегації логів, дашбордів метрик, розподілених трейсів, захоплення пакетів чи діагностики хмарного провайдера.

Коли ви все ж переходите до глибшого інструментарію, несіть із собою ту саму дисципліну доказів. Дашборд метрик має відповідати на конкретне запитання, порушене хронологією Pod’а, — як-от чи зростала пам’ять перед OOM-завершенням чи чи змінилася затримка запитів після розгортання. Трейс має відповідати на запитання щодо шляху запиту, а не замінювати базові перевірки готовності. Складні інструменти найкорисніші, коли просте життєво-циклове свідчення вже звузило пошук.

Отже, межа між базовим і складним налагодженням — це передача, а не стіна. Базове сортування має породжувати речення на кшталт: «Pod готовий, ендпоінти його включають, а перезапуски стабільні, тож наступне запитання — затримка запиту крізь шлях Сервісу». Це речення каже наступному інструменту, що довести. Воно також не дає команді знову відкривати розв’язані життєво-циклові запитання, поки починається глибше дослідження мережі, трейсингу чи продуктивності застосунку. Чітко сформульована передача економить найдорожчий ресурс під час інциденту — час кількох людей, які інакше повторювали б ту саму роботу й доходили б до тих самих висновків паралельно.

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

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

  3. Попередні логи часто корисніші за поточні: у циклі аварійних перезапусків поточний контейнер може очікувати, запускатися чи ще не дійти до точки збою. k logs -p запитує логи останнього завершеного екземпляра, який часто містить справжню помилку.

  4. Код виходу 137 зазвичай вказує на примусове завершення: він поширено з’являється, коли контейнер OOMKilled, хоча вам слід перевіряти поле reason, а не покладатися лише на число. Поєднання коду виходу, причини та ліміту пам’яті розповідає переконливішу історію, ніж будь-яке окреме поле.

ПомилкаЧому це стаєтьсяЯк це виправити
Видалення несправного Pod’а до оглядуЗаміна може приховати попередні логи, хронометраж і події, водночас відтворивши той самий збій.Спершу прочитайте describe, попередні логи та події, а потім перезапускайте лише якщо докази це підтверджують.
Сприйняття Running як справногоПроцес існує, але готовність може бути хибною, а трафік Сервісу досі заблокованим.Порівняйте READY, умови, події проб та ендпоінти Сервісу, перш ніж оголошувати відновлення.
Читання логів застосунку для незапланованого Pod’аЗнайома команда логів здається налагодженням, але жоден контейнер ще не запускався.Прочитайте події Pod’а та обмеження планування за допомогою k describe pod.
Ігнорування простору імен і контекстуСхожі назви навантажень у різних просторах імен ведуть до хибних висновків чи небезпечних змін.Підтвердьте k config current-context і свідомо використовуйте -n <namespace>.
Виправлення живого Pod’а замість шаблону контролераКонтролер відтворює Pod’и зі старого шаблону, тож прямі редагування Pod’а не зберігаються.Змініть Deployment, StatefulSet, Job чи вихідний маніфест, який володіє Pod’ом.
Збільшення лімітів пам’яті без перевірки поведінкиБільший ліміт може відстрочити витік пам’яті, а не розв’язати його.Порівняйте ліміти з очікуваним використанням, огляньте поведінку пам’яті застосунку та за потреби налаштуйте середовище виконання.
Припущення, що всі збої реплік — це збої нодиОднаковий збій на всіх репліках часто вказує на спільну конфігурацію, образ чи залежність.Порівняйте розміщення на нодах, а потім огляньте спільний шаблон Pod’а та попередні логи.
Пропуск перевірки після зміниОдин Pod може відновитися, поки розгортання, готовність чи ендпоінти лишаються несправними.Перевіряйте статус розгортання, готовність Pod’а, лічильники перезапусків, події та ендпоінти Сервісу.
Ваша команда розгортає нову версію API, і всі нові Pod'и показують `CrashLoopBackOff`, тоді як старі Pod'и лишаються готовими (Ready). Які докази слід зібрати першими і яку першопричину ви перевіряєте?

Почніть з k logs <new-pod> -n <namespace> -p, бо контейнер уже запускався та аварійно завершився, і попередній екземпляр зазвичай містить справжню помилку запуску. Потім використайте k describe pod <new-pod> -n <namespace>, щоб підтвердити останній стан, код виходу, посилання на змінні середовища, проби та події. Оскільки кожна нова репліка дає збій, поки старі репліки працюють, ви перевіряєте проблему спільного нового шаблону — як-от поведінку образу, команду чи аргументи, конфігурацію, посилання на Secret чи ConfigMap або залежність, потрібну під час запуску. Це шлях налагодження несправного навантаження, бо він дотримується спостережуваних доказів замість здогадок.

Pod перебуває у статусі `Pending` кілька хвилин, не має призначеної ноди, а `k logs` повертає помилку, бо контейнер недоступний. Що слід перевірити далі й чому?

Запустіть k describe pod <pod> -n <namespace> і прочитайте розділ Events. Pod без призначеної ноди не досяг точки, де можуть існувати логи застосунку, тож повідомлення подій планувальника — це головні докази. Імовірні причини включають нестачу CPU чи пам’яті, taint’и, які Pod не толерує, невідповідність affinity чи селекторів нод, обмеження топології або непов’язаний PersistentVolumeClaim. Це аналізує фазу Pod’а та докази планувальника перед тим, як дивитися на стан контейнера.

Сервіс не отримує трафіку для нового Pod'а, хоча `k get pods` показує Pod як `Running` із нульовими перезапусками. Стовпець `READY` показує `0/1`. Як налагоджувати, не даючи фазі `Running` ввести вас в оману?

Розглядайте це як проблему готовності, доки докази не скажуть інше. Використайте k describe pod <pod> -n <namespace>, щоб оглянути умови та події проб, а потім перевірте, чи готовність провалюється через неправильний шлях, порт, схему, затримку запуску, тайм-аут чи залежність. Ви також можете оглянути k get endpoints <service> -n <namespace>, щоб перевірити, чи виключено Pod з маршрутизації Сервісу. Ключ — відокремити фазу Pod’а від готовності до трафіку, бо Running не означає, що навантаження придатне до використання.

Контейнер неодноразово завершується з причиною `OOMKilled`, і команда пропонує перезапуск розгортання. Чому це навряд чи буде повним виправленням і що слід оцінити натомість?

Перезапуск розгортання запускає той самий процес під тим самим лімітом пам’яті, тож він зазвичай відтворює те саме завершення після того, як використання пам’яті знову зросте. Вам слід оглянути ліміт пам’яті Pod’а в k describe pod, порівняти його з очікуваними потребами застосунку в пам’яті й оцінити, чи ліміт занизький, чи застосунок має витік пам’яті, чи купа (heap) середовища виконання хибно налаштована, чи навантаження завантажує забагато даних. Збільшення ліміту може бути пом’якшенням, але воно має відповідати доказам, а не здогадкам. Це порівнює докази OOM з доказами збою та розгортання, щоб дія була спрямована на правильного власника.

Посилання на образ виглядає правильним у маніфесті, але Pod показує `ImagePullBackOff`. Ваш колега хоче зайти (exec) в Pod, щоб перевірити доступ до реєстру. Що не так із цим планом і що слід зробити натомість?

Ви не можете зайти (exec) в контейнер, який не було створено, а збій завантаження образу означає, що процес застосунку ніколи не запускався. Використайте k describe pod <pod> -n <namespace> і прочитайте повідомлення подій kubelet щодо точного збою завантаження. Повідомлення має вказувати на відсутній тег, збій автентифікації реєстру, проблему з дозволами, тайм-аут DNS чи мережі або неправильний шлях реєстру. Це порівнює збої завантаження образу зі збоями виконання, запитуючи, які докази існують на цій стадії життєвого циклу.

Три незв'язані навантаження стають несправними приблизно одночасно, і всі уражені Pod'и перебувають на `worker-b`. Pod'и тих самих Deployment на інших нодах лишаються справними. Як розширити розслідування?

Цей патерн вказує на проблему рівня ноди, а не на три незалежні помилки застосунків. Використайте k get pods -A -o wide, щоб підтвердити розміщення, а потім огляньте k describe node worker-b на умови на кшталт тиску пам’яті, тиску диска, тиску PID, недоступності мережі, taint’ів і нещодавніх подій ноди. Вам усе одно слід зберегти докази рівня Pod’а, але спільна нода — найвагоміша підказка. Це оцінює, чи належить проблема ноді, а не застосунку, специфікації Pod’а, планувальнику чи розгортанню контролера.

Розгортання застопорилося: два старі Pod'и готові (Ready), а один новий — `Pending`. Власник продукту запитує, чи користувачі недоступні. Що ви перевіряєте і як пояснюєте ризик?

Перевірте k rollout status deployment/<name> -n <namespace>, k get pods -n <namespace> -o wide та k describe pod <pending-new-pod> -n <namespace>. Якщо старі Pod’и лишаються готовими (Ready) й обираються Сервісом, користувачів усе ще можуть обслуговувати, але розгортання заблоковане, а ємність чи резервування можуть бути зменшені. Події Pending-Pod’а пояснять, чи ресурси, taint’и, affinity чи томи заважають новій версії запланувати. Це оцінює розгортання контролера окремо від збою планування Pod’а та живого шляху трафіку.

У цій вправі ви створите три невеликі сценарії збоїв у тренувальному просторі імен, класифікуєте кожен збій і зберете правильні докази перед очищенням. Використовуйте одноразовий локальний чи лабораторний кластер, а не виробничий, бо ресурси навмисно зламані й генеруватимуть події чи перезапуски. Команди припускають, що ви вже виконали alias k=kubectl; якщо ваша оболонка не зберігає псевдоніми між сесіями, визначте його знову перед початком.

Крок 1: Створіть ізольований простір імен

Розділ «Крок 1: Створіть ізольований простір імен»

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

Terminal window
k create namespace kcna-debug
k get namespace kcna-debug
  • Простір імен kcna-debug існує й видимий у k get namespace.
  • Ви можете виконувати команди з -n kcna-debug без зміни типового простору імен.

Крок 2: Створіть збій завантаження образу

Розділ «Крок 2: Створіть збій завантаження образу»

Застосуйте Pod, який посилається на тег образу, що не повинен існувати. Мета — довести, що збої завантаження образу діагностуються з подій, а не з логів застосунку, бо процес застосунку не може писати логи, доки kubelet не завантажить образ і не створить контейнер.

Terminal window
k apply -n kcna-debug -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: bad-image
spec:
restartPolicy: Never
containers:
- name: app
image: nginx:no-such-kcna-debug-tag
ports:
- containerPort: 80
EOF

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

Terminal window
k get pod bad-image -n kcna-debug
k describe pod bad-image -n kcna-debug
k logs bad-image -n kcna-debug
  • Pod показує ErrImagePull чи ImagePullBackOff після того, як kubelet намагається завантаження.
  • Вивід describe містить подію, що пояснює збій завантаження образу.
  • Ви можете пояснити, чому k logs не є правильним джерелом доказів для цього сценарію.

Крок 3: Створіть збій циклу аварійних перезапусків

Розділ «Крок 3: Створіть збій циклу аварійних перезапусків»

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

Terminal window
k apply -n kcna-debug -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: crash-demo
spec:
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- echo "starting demo"; echo "missing required setting"; exit 1
EOF

Поспостерігайте, як він перезапускається, потім прочитайте і стан Pod’а, і попередні логи. Якщо ваша перша спроба k logs -p виконається до того, як контейнер перезапуститься, зачекайте кілька митей і спробуйте знову; важливий урок у тому, що попередній завершений екземпляр часто є найзрозумілішим свідком у циклі аварійних перезапусків.

Terminal window
k get pod crash-demo -n kcna-debug
k logs crash-demo -n kcna-debug -p
k describe pod crash-demo -n kcna-debug
  • Pod досягає CrashLoopBackOff чи показує повторювані перезапуски за кілька митей.
  • k logs -p показує повідомлення з попереднього невдалого екземпляра контейнера.
  • k describe pod показує завершений останній стан чи докази перезапуску, що відповідають виводу логу.

Крок 4: Створіть збій планування

Розділ «Крок 4: Створіть збій планування»

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

Terminal window
k apply -n kcna-debug -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: too-large
spec:
containers:
- name: app
image: busybox:1.36
command:
- /bin/sh
- -c
- sleep 3600
resources:
requests:
memory: "1000Gi"
cpu: "1"
EOF

Огляньте розміщення й повідомлення планувальника. Важлива деталь — відсутня нода у виводі з прапорцем wide і подія FailedScheduling у describe, бо разом вони показують, що Pod так і не досяг запуску контейнера в kubelet.

Terminal window
k get pod too-large -n kcna-debug -o wide
k describe pod too-large -n kcna-debug
  • Pod лишається Pending і не має призначеної ноди в k get pod -o wide.
  • Розділ Events пояснює, чому планувальник не зміг розмістити Pod.
  • Ви можете пояснити, чому перезапуск цього Pod’а не розв’язав би збій планування.

Крок 5: Складіть односторінкову нотатку сортування

Розділ «Крок 5: Складіть односторінкову нотатку сортування»

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

Pod:
Visible symptom:
First useful evidence:
Likely owner:
Next safe action:
  • bad-image класифіковано як збій завантаження образу з подіями kubelet як першими корисними доказами.
  • crash-demo класифіковано як збій під час виконання з попередніми логами як першими корисними доказами.
  • too-large класифіковано як збій планування з подіями планувальника як першими корисними доказами.
  • Кожна наступна дія зберігає докази й націлена на ймовірну першопричину замість випадкового перезапуску ресурсів.
  • Ваш контрольний список першого реагування явно охоплює рішення щодо налагодження, аналізу, порівняння, оцінки та проєктування з результатів навчання.

Крок 6: Очистіть тренувальний простір імен

Розділ «Крок 6: Очистіть тренувальний простір імен»

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

Terminal window
k delete namespace kcna-debug
  • k get namespace kcna-debug більше не показує простір імен після завершення видалення.
  • Ви можете пояснити три різні класи збоїв, не звертаючись до команд.

Перейдіть до Частина 2: Оркестрація контейнерів — Модуль 2.1: Планування, щоб дізнатися, як Kubernetes вирішує, де розмістити ваші Pod’и.