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

Модуль 2.1: Поглиблене вивчення Pod'ів

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

Opens in Killercoda in a new tab

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

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

Передумови: Модуль 1.1 (Площина управління), Модуль 0.2 (Майстерність роботи з оболонкою)


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

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

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

  • Створювати Pod’и імперативно та декларативно із запитами ресурсів, пробами та контекстами безпеки
  • Діагностувати збої Pod’ів системно для станів Pending, ImagePullBackOff, CrashLoopBackOff, збоїв готовності та OOMKilled
  • Налаштовувати проби liveness, readiness та startup для застосунків із різною поведінкою запуску та залежностей
  • Проєктувати багатоконтейнерні Pod’и, які доречно використовують init-контейнери, sidecar’и, спільні томи та спільну мережу
  • Оцінювати політики перезапуску, фази життєвого циклу та поведінку завершення під час вибору способу відновлення робочого навантаження

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

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

Гіпотетичний сценарій: ваша команда розгортає невеликий API за Сервісом, Деплоймент повідомляє, що розгортання завершилося, але користувачі все одно час від часу отримують збої з’єднання. kubectl get pods показує одні Pod’и як Running, деякі як CrashLoopBackOff, а один — як Running із готовністю 0/1. Виправлення полягає не в тому, щоб запам’ятати якусь одну команду; виправлення полягає в тому, щоб читати Pod як набір рішень планувальника, станів контейнерів, проб, подій, логів, мережевої поведінки та правил завершення, доки накопичені докази не вкажуть на справжню несправність.

Pod’и — це атомарна одиниця розгортання в Kubernetes. Кожен контейнер, який ви запускаєте, живе всередині Pod’а, і кожен Deployment, StatefulSet, DaemonSet та Job створює Pod’и як об’єкти виконання, що приземляються на ноди. Якщо Pod’и здаються незрозумілими, робочі навантаження вищого рівня стають оманливими, тому що контролер може виглядати справним, тоді як Pod під ним не запланований, тягне неправильний образ, не проходить пробу, працює без трафіку або перезапускається швидше, ніж застосунок встигає записати корисні логи.

Цей модуль розглядає Pod’и як операційний об’єкт, а не як форму YAML для копіювання. Ви будете швидко створювати Pod’и, перетворювати імперативні команди на маніфести, додавати межі безпеки та ресурсів, міркувати про життєвий цикл від init-контейнерів до коректного завершення та усувати поширені режими збоїв, які ви побачите на іспиті CKA та у звичайній роботі з кластером. Зрештою kubectl get pod, kubectl describe pod, kubectl logs та kubectl exec мають відчуватися як зв’язаний робочий процес, а не як чотири не пов’язані між собою команди.

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


Основи Pod’ів: що Kubernetes насправді планує

Розділ «Основи Pod’ів: що Kubernetes насправді планує»

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

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

┌────────────────────────────────────────────────────────────────┐
│ Pod │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Container 1 │ │ Container 2 │ │
│ │ (main app) │ │ (sidecar) │ │
│ │ │ │ │ │
│ │ Port 8080 │ │ Port 9090 │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ └──────────┬───────────┘ │
│ │ │
│ Shared Network Namespace │
│ • Same IP address │
│ • localhost communication │
│ • Shared ports (can't conflict) │
│ │
│ Shared Volumes (optional) │
│ • Mount same volume │
│ • Share data between containers │
│ │
└────────────────────────────────────────────────────────────────┘

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

АспектКонтейнерPod
ОдиницяОдин процесГрупа контейнерів
МережаВласний мережевий простір іменСпільний мережевий простір імен
IP-адресаНемає (використовує адресу Pod’а)Одна на Pod
СховищеВласна файлова системаМоже мати спільні томи
Життєвий циклКерується Pod’омКерується Kubernetes

Зробіть паузу й передбачте: два контейнери в одному Pod’і обидва намагаються слухати порт 8080. Що ви очікуєте побачити в логах другого контейнера, і чим відрізнявся б результат, якби ці контейнери були в окремих Pod’ах? Зробіть передбачення, перш ніж читати далі, бо саме ця ментальна модель запобігає багатьом заплутаним збоям sidecar’ів.

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

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

Є ще одна тонка причина, чому Pod’и є правильним рівнем абстракції: вони дають змогу Kubernetes ухвалювати рішення про розміщення, використовуючи сукупну форму контейнерів, які мають працювати разом. Якщо основний контейнер потребує 200m CPU, а sidecar — 50m, слід Pod’а для планування дорівнює сумі цих запитів. Це не дає Kubernetes розмістити помічника там, де основний застосунок не може працювати, а також означає, що завеликий sidecar може заблокувати планування всього Pod’а навіть тоді, коли сам застосунок виглядає невеликим.

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

Вам також слід відокремлювати ідентичність Pod’а від ідентичності застосунку. Ім’я Pod’а — корисний інструмент для налагодження, але це не довговічна адреса для клієнтів, а IP Pod’а не є стабільним ендпоінтом, який можна вшити в конфігурацію. Мітки, селектори та Сервіси утворюють стабільний шар, обернений до застосунку, над Pod’ами. Цей модуль залишається на рівні Pod’а, бо вам потрібен цей фундамент, перш ніж наступний модуль покаже, як Деплойменти та ReplicaSet’и утримують замінні Pod’и узгодженими з бажаною кількістю реплік.


Швидке створення Pod’ів без втрати контролю

Розділ «Швидке створення Pod’ів без втрати контролю»

Найшвидший надійний робочий процес — згенерувати коректну вихідну точку, а потім відредагувати поля, які мають значення. Під час іспиту CKA kubectl run із --dry-run=client -o yaml дає вам коректну структуру Kubernetes без потреби пам’ятати кожне поле напам’ять. У роботі виробничого типу та сама звичка допомагає уникнути налагодження через одруківки, бо ви починаєте з форми об’єкта, створеної інструментами Kubernetes, а потім переглядаєте отриманий маніфест перед застосуванням.

Terminal window
# Create a simple pod
kubectl run nginx --image=nginx
# Create pod and expose port
kubectl run nginx --image=nginx --port=80
# Create pod with labels
kubectl run nginx --image=nginx --labels="app=web,env=prod"
# Create pod with environment variables
kubectl run nginx --image=nginx --env="ENV=production"
# Resource requests/limits cannot be patched onto a running bare pod — its
# resources are immutable. Set them in the pod spec at creation time (see the
# YAML workflow below).
# Generate YAML without creating (essential for exam!)
kubectl run nginx --image=nginx --dry-run=client -o yaml > pod.yaml

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

pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
env: production
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"

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

Terminal window
# Apply the pod
kubectl apply -f pod.yaml

Коли ви обслуговуєте Pod, використовуйте команди, які розкривають різні шари стану. kubectl get відповідає, чи має Kubernetes поточний об’єкт і який високорівневий статус він повідомляє, kubectl describe поєднує вибрані поля специфікації зі статусом та подіями, а kubectl get -o yaml показує повний об’єкт API. Видалення також є частиною життєвого циклу; звичайне видалення дає робочому навантаженню час на завершення роботи, тоді як примусове видалення — це інструмент усунення несправностей, який може приховати помилки завершення застосунку, якщо застосовувати його легковажно.

Terminal window
# List pods
kubectl get pods
kubectl get pods -o wide # Show IP and node
kubectl get pods --show-labels # Show labels
# Describe pod (detailed info)
kubectl describe pod nginx
# Get pod YAML
kubectl get pod nginx -o yaml
# Delete pod
kubectl delete pod nginx
# Delete pod immediately (skip graceful shutdown)
kubectl delete pod nginx --grace-period=0 --force
# Watch pods
kubectl get pods -w

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

apiVersion: v1
kind: Pod
metadata:
name: sec-ctx-demo
spec:
securityContext:
runAsUser: 1000
fsGroup: 2000
containers:
- name: myapp
image: busybox
command: [ "sh", "-c", "sleep 1h" ]
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true

Перш ніж запустити це, який результат ви очікуєте від kubectl describe pod sec-ctx-demo, якщо образ стартує успішно, але застосунок намагається писати під /? Важливий крок міркування — відокремити запуск контейнера від поведінки застосунку: Kubernetes може коректно запустити контейнер, проте процес усе одно може дати збій, бо контекст безпеки навмисно забороняє небезпечний запис у файлову систему.

Налаштування ресурсів заслуговують на таке саме уважне читання, як і налаштування безпеки. Запит — це обіцянка планувальника: Kubernetes намагається розмістити Pod лише на ноді, яка може задовольнити запитані CPU та пам’ять. Ліміт — це межа під час виконання: контейнер може бути обмежений у CPU або вбитий за пам’ять, якщо перевищить налаштовану стелю. Багато заплутаних збоїв Pod’ів починаються, коли команди задають ліміти, не розуміючи нормального пікового споживання пам’яті, а потім тлумачать CrashLoopBackOff як помилку застосунку, навіть якщо попередній стан каже OOMKilled.

Для роботи на іспиті призвичайтеся генерувати YAML, редагувати лише потрібні поля, а потім перевіряти форму об’єкта перед застосуванням. kubectl apply --dry-run=server корисний, коли доступний, бо просить сервер API перевірити об’єкт, не зберігаючи його, тоді як kubectl diff може показати, що змінилося б для наявного об’єкта. Ці команди не є магією, але вони сповільнюють саме той клас помилок, що походять від поспішних відступів та неправильного розташування полів.

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


Життєвий цикл, статус і завершення

Розділ «Життєвий цикл, статус і завершення»

Мова життєвого циклу Pod’а є точною, але kubectl get pods стискає кілька шарів в одну таблицю. Фаза Pod’а, як-от Pending чи Running, описує широкий стан життєвого циклу, тоді як стани контейнерів, як-от Waiting, Running та Terminated, описують окремі контейнери всередині Pod’а. Видимий стовпець STATUS може показувати причину очікування на кшталт ImagePullBackOff чи CrashLoopBackOff, тож завжди підтверджуйте деталі через describe, коли статус є частиною діагнозу.

ФазаОпис
PendingPod прийнято, очікує на планування або завантаження образів
RunningPod прив’язано до ноди, принаймні один контейнер працює
SucceededУсі контейнери завершилися успішно (exit 0)
FailedУсі контейнери завершилися, принаймні один із помилкою
UnknownСтан Pod’а неможливо визначити (проблема зв’язку з нодою)
СтанОпис
WaitingЩе не працює (завантаження образу, застосування секретів)
RunningВиконується без проблем
TerminatedЗавершив виконання (успішно або з помилкою)

Таблиця фаз корисна, але шлях переходів важливіший під час усунення несправностей. Pending до планування зазвичай указує на ресурси, селектори нод, affinity, taints чи брак ємності для планування. Pending після планування все ще може стосуватися завантаження образів або налаштування контейнерів, а Running не доводить готовності, бо контейнер може бути живим, поки readiness-проба тримає його поза ендпоінтами Сервісу.

┌────────────────────────────────────────────────────────────────┐
│ Pod Lifecycle │
│ │
│ Pod Created │
│ │ │
│ ▼ │
│ ┌─────────┐ No node available │
│ │ Pending │◄────────────────────────────────┐ │
│ └────┬────┘ │ │
│ │ Scheduled to node │ │
│ ▼ │ │
│ ┌─────────┐ Container crashes │ │
│ │ Running │────────────────────────────────►│ │
│ └────┬────┘ │ │
│ │ │ │
│ ├─────────────────────┐ │ │
│ │ │ │ │
│ ▼ ▼ │ │
│ ┌───────────┐ ┌────────┐ │ │
│ │ Succeeded │ │ Failed │ │ │
│ │ (exit 0) │ │(exit≠0)│ │ │
│ └───────────┘ └────────┘ │ │
│ │
└────────────────────────────────────────────────────────────────┘

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

Terminal window
# Quick status
kubectl get pod nginx
# NAME READY STATUS RESTARTS AGE
# nginx 1/1 Running 0 5m
# Detailed status
kubectl describe pod nginx | grep -A10 "Status:"
# Container states
kubectl get pod nginx -o jsonpath='{.status.containerStatuses[0].state}'
# Check why a pod is pending
kubectl describe pod nginx | grep -A5 "Events:"

Завершення є частиною життєвого циклу, а не запізнілою думкою. Коли ви видаляєте Pod, Kubernetes позначає його на видалення, прибирає готові ендпоінти зі звичайного трафіку Сервісу, надсилає SIGTERM контейнерам, чекає період пільгового завершення й зрештою надсилає SIGKILL, якщо процес не завершується. Типовий пільговий період — 30 секунд, що достатньо щедро для багатьох невеликих сервісів, але все ще достатньо коротко, щоб застосунки навмисно обробляли SIGTERM.

Ви можете перевизначити пільговий період під час видалення за допомогою kubectl delete pod nginx --grace-period=5, але це має бути свідомим вибором. Короткі пільгові періоди корисні для застряглих тестових Pod’ів та термінового прибирання, тоді як звичайним Pod’ам застосунку потрібно достатньо часу, щоб припинити приймати роботу, завершити запити в процесі, скинути логи та закрити з’єднання. Якщо користувачі бачать помилки під час розгортань, надто короткий або проігнорований шлях завершення є так само ймовірним, як поганий образ чи зламана readiness-проба.

apiVersion: v1
kind: Pod
metadata:
name: restart-demo
spec:
restartPolicy: OnFailure # Only restart if container fails
containers:
- name: worker
image: busybox
command: ["sh", "-c", "exit 1"] # Will be restarted

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

ПолітикаПоведінкаВипадок використання
Always (типова)Перезапуск за будь-якого завершенняДовготривалі сервіси
OnFailureПерезапуск лише за ненульового виходуЗавдання, які мають повторюватися при збої
NeverНіколи не перезапускатиОдноразові скрипти, налагодження
Terminal window
# Check restart count
kubectl get pods
# NAME READY STATUS RESTARTS AGE
# nginx 1/1 Running 3 10m
# Describe shows restart details
kubectl describe pod nginx | grep -A5 "Last State"

Зробіть паузу й передбачте: Pod із restartPolicy: Always має контейнер, що завершується з кодом 0, тоді як інший Pod із restartPolicy: OnFailure завершується з тим самим кодом. Який із них перезапуститься, і що ви очікуєте побачити в RESTARTS через кілька хвилин? Правильна відповідь показує, що ви читаєте політику, код виходу та намір робочого навантаження разом.

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

Стовпець RESTARTS — це лічильник, а не першопричина. Лічильник перезапусків 0 усе ще може приховувати Pod, який ніколи не планувався, а високий лічильник перезапусків не каже вам, чи причина — погана команда, відсутній файл, невдала liveness-проба чи тиск на пам’ять. Поєднуйте лічильник із Last State, кодом виходу, подіями та попередніми логами. Коли ці джерела узгоджуються, ви можете виправити причину замість того, щоб сприймати сам перезапуск як проблему.

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


Налагодження Pod’ів від симптому до доказу

Розділ «Налагодження Pod’ів від симптому до доказу»

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

Pod Problem
├── kubectl get pods (check STATUS)
│ │
│ ├── Pending → kubectl describe (check Events)
│ │ └── ImagePullBackOff, Insufficient resources, etc.
│ │
│ ├── CrashLoopBackOff → kubectl logs (check app errors)
│ │ └── Application crash, missing config, etc.
│ │
│ └── Running but not working → kubectl exec (check inside)
│ └── Network issues, wrong config, etc.
└── kubectl describe pod (always useful)

Розділ Events — це місце, де Kubernetes каже вам, що він нещодавно намагався зробити. Збій планування може згадати недостатність CPU, нестерпні taints, невідповідність node affinity чи проблему під’єднання тома. Збій образу може показати спроби завантаження, помилки автентифікації чи відсутній тег. Події не є постійними логами, тож їх найкраще використовувати рано, а потім поєднувати зі статусом Pod’а та логами застосунку.

Terminal window
# The trinity of debugging
kubectl get pod nginx # What's the status?
kubectl describe pod nginx # What's happening? (events)
kubectl logs nginx # What does the app say?
# Deeper investigation
kubectl exec -it nginx -- /bin/sh # Get inside
kubectl get events --sort-by='.lastTimestamp' # Recent events
kubectl top pod nginx # Resource usage (if metrics-server)

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

Terminal window
# Current logs
kubectl logs nginx
# Follow logs (like tail -f)
kubectl logs nginx -f
# Last 100 lines
kubectl logs nginx --tail=100
# Logs from last hour
kubectl logs nginx --since=1h
# Logs from specific container (multi-container pod)
kubectl logs nginx -c sidecar
# Previous container logs (after crash)
kubectl logs nginx --previous

kubectl exec призначений для огляду контейнера, що працює, а не для доведення того, що Pod справний. Він допомагає, коли Pod працює, але поведінка неправильна: файл конфігурації не змонтовано, не вдається розв’язання DNS, бракує змінної середовища процесу чи sidecar не може дістатися основного застосунку через localhost. Якщо контейнер падає надто швидко, щоб увійти до нього через exec, використовуйте логи, попередні логи, події чи ефемерний підхід до налагодження в наступних модулях усунення несправностей замість того, щоб змагатися з циклом перезапуску.

Terminal window
# Run a command
kubectl exec nginx -- ls /
# Interactive shell (/bin/sh works on minimal images; many images lack bash)
kubectl exec -it nginx -- /bin/sh
# Specific container in multi-container pod
kubectl exec -it nginx -c sidecar -- /bin/sh
# Run commands without shell
kubectl exec nginx -- cat /etc/nginx/nginx.conf
kubectl exec nginx -- env
kubectl exec nginx -- ps aux
СимптомПричинаРозв’язання
ImagePullBackOffНеправильне ім’я образу або немає доступуВиправте ім’я образу, перевірте автентифікацію реєстру
CrashLoopBackOffКонтейнер постійно падаєПеревірте логи на помилки застосунку
Pending (немає подій)Жодна нода не має достатньо ресурсівЗвільніть ресурси або додайте ноди
Pending (планування)Taints, правила affinityПеревірте taints нод та tolerations Pod’а
Running, але не готовийНевдала readiness-пробаПеревірте налаштування проби та застосунок
OOMKilledБрак пам’ятіЗбільште ліміти пам’яті

Гіпотетичний сценарій: Pod показує Running, але Сервіс не надсилає до нього трафіку, а лог застосунку виглядає нормально. Спокуслива дія — увійти через exec у контейнер і протестувати застосунок вручну, але першою корисною підказкою зазвичай є стовпець READY та події readiness-проби в kubectl describe pod. Контейнер може бути живим і все одно виключеним з ендпоінтів, бо готовність — це сигнал маршрутизації, а не сигнал про живість процесу.

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

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

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

Коли логи порожні, розширте мислення замість того, щоб припускати збій системи логування. Контейнер може завершуватися до того, як застосунок ініціалізує логування, точка входу може бути неправильною, образу може бракувати очікуваної оболонки, чи контекст безпеки може блокувати запис у файлову систему, потрібний під час запуску. describe може показати команду, образ, стан та події, тоді як get pod -o yaml розкриває розв’язану специфікацію. Разом вони часто виявляють невідповідність між маніфестом, який ви мали намір створити, та контейнером, що насправді запустився.

Для багатоконтейнерних Pod’ів завжди називайте контейнер, який ви оглядаєте, коли симптом стосується конкретного процесу. Sidecar може бути справним, поки основний застосунок падає, а основний застосунок може бути справним, поки проксі-sidecar блокує трафік. Лічильник READY каже вам, скільки контейнерів готові, але стан кожного контейнера в describe каже, який саме очікує, завершений чи перезапускається. Цей поконтейнерний перегляд — різниця між швидким виправленням та оманливим сукупним статусом.


Багатоконтейнерні Pod’и, init-контейнери та спільні томи

Розділ «Багатоконтейнерні Pod’и, init-контейнери та спільні томи»

Багатоконтейнерні Pod’и потужні, бо вони роблять тісну зв’язаність явною. Контейнери в одному Pod’і плануються разом, мають спільну IP-адресу Pod’а, можуть спілкуватися через localhost та можуть монтувати ті самі томи. Це ідеально для помічників, які безглузді без основного застосунку, але погано пасує незалежно масштабованим сервісам, бо Pod є одиницею масштабування.

┌────────────────────────────────────────────────────────────────┐
│ Multi-Container Patterns │
│ │
│ Sidecar Ambassador Adapter │
│ ┌──────────────────┐ ┌──────────────────┐ ┌─────────┐ │
│ │ ┌────┐ ┌────┐ │ │ ┌────┐ ┌────┐ │ │┌────┐ │ │
│ │ │Main│ │Log │ │ │ │Main│ │Proxy│ │ ││Main│ │ │
│ │ │App │──│Ship│ │ │ │App │──│ │──┼──││App │ │ │
│ │ └────┘ └────┘ │ │ └────┘ └────┘ │ │└──┬─┘ │ │
│ │ Main + Helper │ │ Proxy outbound │ │ │ │ │
│ └──────────────────┘ └──────────────────┘ │┌──▼──┐ │ │
│ ││Adapt│ │ │
│ Examples: Examples: ││Log │ │ │
│ - Log collectors - Service mesh proxy │└─────┘ │ │
│ - Config reloaders - Database proxy │Transform│ │
│ - Git sync - Auth proxy └─────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘

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

apiVersion: v1
kind: Pod
metadata:
name: web-with-sidecar
spec:
containers:
# Main application container
- name: web
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: logs
mountPath: /var/log/nginx
# Sidecar container - ships logs
- name: log-shipper
image: busybox
command: ["sh", "-c", "tail -F /var/log/nginx/access.log"]
volumeMounts:
- name: logs
mountPath: /var/log/nginx
volumes:
- name: logs
emptyDir: {}

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

Init-контейнери розв’язують іншу проблему: впорядкований запуск. Вони працюють перед контейнерами застосунку, працюють послідовно, і кожен має успішно завершитися, перш ніж стартує наступний init-контейнер чи будь-який звичайний контейнер. Це правильний інструмент для підготовки файлів, очікування на залежність чи виконання одноразового кроку налаштування, який не повинен залишатися працювати поруч із застосунком.

apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
# Init containers run first, in order
initContainers:
- name: wait-for-db
image: busybox
command: ['sh', '-c', 'until nc -z db-service 5432; do echo waiting for db; sleep 2; done']
- name: init-config
image: busybox
command: ['sh', '-c', 'echo "config initialized" > /config/ready']
volumeMounts:
- name: config
mountPath: /config
# App containers start after all init containers succeed
containers:
- name: app
image: myapp
volumeMounts:
- name: config
mountPath: /config
volumes:
- name: config
emptyDir: {}
Випадок використанняПриклад
Очікування на залежністьЗачекати на готовність бази даних
Налаштування конфігураціїКлонувати git-репозиторій, згенерувати конфігурацію
Міграції бази данихВиконати міграції перед запуском застосунку
Реєстрація в сервісіЗареєструвати екземпляр у зовнішній системі
Завантаження ресурсівОтримати статичні файли з S3

Зупиніться й подумайте: вашому вебзастосунку потрібен файл конфігурації, згенерований із шаблону перед запуском застосунку, а також потрібен помічник для відправлення логів на весь час роботи. Який патерн контейнера обслуговує кожну вимогу, і чи можуть обидва патерни з’явитися в одному Pod’і? Відповідь — так: використайте init-контейнер для завершеної роботи з налаштування та sidecar для довготривалого помічника.

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

Init-контейнери мають виконувати роботу, яку безпечно повторювати. Оскільки Kubernetes може повторити їх після збою, init-контейнер, що виконує міграцію, записує зовнішній стан чи реєструється у віддаленій системі, має бути ідемпотентним або захищеним зовнішньою системою. Простий init-контейнер для рендерингу файлів природно повторюваний; міграція бази даних може потребувати інструментарію міграцій на рівні застосунку, який фіксує застосовані версії. Якщо крок налаштування не витримує повторень, він, імовірно, потребує більш явного Job чи процесу релізу.

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

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

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


Проби, готовність та здоров’я під час виконання

Розділ «Проби, готовність та здоров’я під час виконання»

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

ПробаПризначенняДія при збоїКоли використовувати
StartupПеревіряє, чи застосунок успішно запустивсяПерезапускає контейнерДля застарілих застосунків із повільним стартом, яким потрібен додатковий час на ініціалізацію без провалу liveness-перевірок.
LivenessПеревіряє, чи застосунок здоровий і працюєПерезапускає контейнерЩоб відновитися після дедлоків чи збоїв застосунку, коли процес працює, але не відповідає.
ReadinessПеревіряє, чи застосунок готовий приймати трафікПрибирає Pod з ендпоінтів СервісуКоли застосунок працює, але тимчасово не може обслуговувати трафік (наприклад, завантажує великі кеші, втрачено з’єднання з базою даних).

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

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

apiVersion: v1
kind: Pod
metadata:
name: probe-demo
spec:
containers:
- name: myapp
image: nginx
ports:
- containerPort: 80
# 1. Startup Probe: Wait up to 300 seconds (30 * 10) for slow start
startupProbe:
httpGet:
path: /
port: 80
failureThreshold: 30
periodSeconds: 10
# 2. Liveness Probe: Restart if deadlocked
livenessProbe:
exec:
command:
- cat
- /usr/share/nginx/html/index.html
initialDelaySeconds: 5
periodSeconds: 5
# 3. Readiness Probe: Stop sending traffic if backend disconnected
readinessProbe:
tcpSocket:
port: 80
initialDelaySeconds: 5
periodSeconds: 10

Зробіть паузу й передбачте: якщо liveness-проба Pod’а проходить, але його readiness-проба не проходить, що покаже kubectl get pods у стовпцях READY та STATUS, і чи буде Pod перезапущено? Очікуваний результат — Pod, який залишається Running, але не повністю готовий, наприклад 0/1, і kubelet не повинен перезапускати його лише тому, що не пройшла readiness.

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

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

Startup-проби особливо корисні для застосунків, що мають довгий, але виправданий шлях ініціалізації. Без startup-проби liveness може почати судити контейнер до того, як застосунок завантажив індекси, прогрів кеші чи завершив міграції запуску. Зі startup-пробою kubelet дає застосунку окремий бюджет запуску, перш ніж liveness стане активною. Це не означає, що застосунок може стартувати вічно; це означає, що бюджет збоїв запуску є явним та окремим від звичайного здоров’я під час виконання.

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

Liveness має бути дешевою, локальною та змістовною. Якщо команда проби розгалужує важкий процес кожні кілька секунд, сама перевірка здоров’я може стати навантаженням. Якщо проба перевіряє лише те, що TCP-порт відкритий, вона може пропустити дедлок застосунку. Найкращий сигнал liveness — той, що відповідає на запитання «Чи застряг цей процес так, що перезапуск, імовірно, його полагодить?», а не «Чи може кожна низхідна залежність відповісти просто зараз?».

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


Мережа Pod’ів та пряма перевірка

Розділ «Мережа Pod’ів та пряма перевірка»

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

┌────────────────────────────────────────────────────────────────┐
│ Pod Networking │
│ │
│ Every pod gets a unique IP address │
│ Containers in pod share that IP │
│ Pods can communicate with all other pods (no NAT) │
│ │
│ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ Pod A (10.244.1.5) │ │ Pod B (10.244.2.8) │ │
│ │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ │ │
│ │ │ C1 │ │ C2 │ │ │ │ C1 │ │ │
│ │ │:80 │ │:9090│ │ │ │:8080│ │ │
│ │ └──┬──┘ └──┬──┘ │ │ └──┬──┘ │ │
│ │ │ │ │ │ │ │ │
│ │ └────┬─────┘ │ │ │ │ │
│ │ │ localhost │ │ │ │ │
│ └─────────┼─────────────┘ └────┼─────────────────┘ │
│ │ │ │
│ └───────────────────────┘ │
│ Can reach each other directly │
│ 10.244.1.5:80 ←→ 10.244.2.8:8080 │
│ │
└────────────────────────────────────────────────────────────────┘

Коли ви тестуєте мережу, чітко розумійте, який шлях ви тестуєте. Sidecar, що звертається curl до localhost:80, тестує комунікацію всередині Pod’а, окремий діагностичний Pod, що звертається curl до IP Pod’а, тестує досяжність мережі Pod’ів, а клієнт, що використовує ім’я Сервісу, тестує селектор, ендпоінт та поведінку kube-proxy чи площини даних. Це різні запитання, тож не дозволяйте одному успішному curl переконати вас, що весь шлях справний.

Terminal window
# Containers in same pod communicate via localhost
# Container 1 (nginx on port 80)
# Container 2 can reach it at localhost:80
# Example: curl from sidecar to main app
kubectl exec -it pod-name -c sidecar -- curl localhost:80
Terminal window
# Get pod IP
kubectl get pod nginx -o wide
# NAME READY STATUS IP NODE
# nginx 1/1 Running 10.244.1.5 worker-1
# Get IP with jsonpath
kubectl get pod nginx -o jsonpath='{.status.podIP}'
# Get all pod IPs
kubectl get pods -o custom-columns='NAME:.metadata.name,IP:.status.podIP'

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

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

Усунення несправностей DNS дотримується того самого методу «крок за кроком». Pod може не розв’язати ім’я Сервісу, бо CoreDNS недоступний, бо запит використовує неправильний простір імен, чи бо Сервіс не існує. Тест прямого IP Pod’а повністю оминає DNS, тож він корисний для відокремлення розв’язання імен від «сирої» зв’язності. У ранньому налагодженні Pod’ів від вас не очікують опанування кожної деталі мережевого плагіна, але від вас очікують уникнення змішування DNS, вибору Сервісу, готовності та перевірок процесу всередині Pod’а в одну розпливчасту «проблему з мережею».

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


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

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

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

ПатернКоли використовуватиЧому працюєМіркування щодо масштабування
Згенерувати YAML через --dry-run=client -o yamlВам потрібен швидкий, коректний стартовий маніфестІнструменти Kubernetes створюють скелет об’єкта й зменшують синтаксичні помилкиПерегляньте та зафіксуйте остаточний YAML, коли об’єкт важливий поза швидким завданням
Sidecar для тісно зв’язаних помічниківПомічник має жити поруч з одним екземпляром застосункуСпільна мережа та томи роблять координацію простоюSidecar масштабується лише тоді, коли масштабується основний застосунок
Init-контейнер для впорядкованого налаштуванняНалаштування має завершитися перед запуском застосункуInit-контейнери працюють послідовно та контролюють запуск застосункуПовільна чи крихка робота init затримує готовність Pod’а
Readiness для контролю трафікуЗастосунок живий, але не готовий до запитівЕндпоінти Сервісу виключають неготові Pod’и без перезапускуПогані readiness-перевірки можуть прибрати забагато ємності
Запити та ліміти ресурсівВам потрібне передбачуване планування та стримуванняЗапити спрямовують планування; ліміти обмежують споживанняНадто тісні ліміти можуть спричинити OOMKilled чи throttling

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

АнтипатернЩо йде не такКраща альтернатива
Розміщення не пов’язаних сервісів в одному Pod’іВони не можуть масштабуватися, розгортатися чи давати збій незалежноВикористовуйте окремі Деплойменти та з’єднайте через Сервіс
Використання тегів latestПерестворений Pod може запустити інший образ, ніж той, що тестувалиЗакріпіть версійний тег чи незмінний дайджест
Перевірка баз даних у liveness-пробахПовільність залежності спричиняє перезапуски, що посилюють збоїВикористовуйте readiness для доступності залежностей та liveness для здоров’я процесу
Пропуск запитів ресурсівПланувальник не може зарезервувати реалістичну ємністьЗадайте запити CPU та пам’яті на основі виміряної поведінки
Налагодження лише через kubectl execЦикли збоїв та збої планування можуть не мати робочої оболонки для оглядуПочніть із get, describe, подій та логів, а exec — коли контейнер стабільний

Таблиці патернів — це не правила для сліпого застосування; це підказки для операційної відповідності. Маленький навчальний Pod можна створити імперативно й видалити за кілька хвилин, тоді як виробниче робоче навантаження слід виражати в маніфестах під контролем версій чи в об’єктах робочих навантажень вищого рівня. Так само sidecar елегантний, коли помічник прив’язаний рівно до одного екземпляра застосунку, та незграбний, коли помічник стає спільним сервісом під виглядом помічника.


Структура для ухвалення рішень

Розділ «Структура для ухвалення рішень»

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

Need a pod?
├── Quick exam or throwaway test?
│ └── Use kubectl run, then generate YAML if fields need editing.
├── Repeatable workload definition?
│ └── Write or generate YAML, pin images, add labels, resources, and probes.
├── Pod is not starting?
│ └── Read STATUS, describe Events, then inspect image, scheduling, and init state.
├── Pod starts but receives no traffic?
│ └── Check READY, readiness probe events, labels, selectors, and endpoints.
└── Helper container needed?
├── Runs before app and exits? Use an init container.
└── Runs beside app for its lifetime? Use a sidecar.
РішенняВиберіть цеКоли докази показуютьСтережіться
Імперативна командаkubectl runВам потрібна швидкість чи згенерована стартова точкаВідсутні поля все одно треба переглянути
Декларативний YAML Pod’аkubectl apply -fВам потрібна відтворюваність та точний контроль специфікаціїОкремі Pod’и рідко є фінальним виробничим контролером
Init-контейнерinitContainersНалаштування має завершитися перед запуском застосункуОчікування залежностей можуть заблокувати весь Pod
SidecarКілька контейнерів застосункуПомічник має ділити життєвий цикл, мережу чи файлиНемає незалежного масштабування для помічника
Readiness-пробаreadinessProbeТрафік має призупинятися без перезапускуПроба має відображати здатність обслуговувати запити
Liveness-пробаlivenessProbeПерезапуск, імовірно, полагодить процесПеревірки зовнішніх залежностей можуть спричиняти шторми перезапусків

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


  • Kubernetes дає Pod’у одну IP-адресу, спільну для всіх контейнерів у цьому Pod’і, ось чому два контейнери в одному Pod’і не можуть обидва прив’язатися до того самого порту на цьому IP.
  • Типовий період пільгового завершення Pod’а — 30 секунд, тож застосунок, який ігнорує SIGTERM, може виглядати нормально під час звичайної роботи й усе одно спричиняти помилки під час розгортання чи видалення.
  • Init-контейнери виконуються до завершення перед запуском контейнерів застосунку, і вони не використовують readiness-проб, бо їхнє завдання — завершитися, а не залишатися готовими до трафіку.
  • Startup-проби додали, щоб повільно стартуючі застосунки могли отримати окремий бюджет запуску, перш ніж почнуться liveness-перевірки, що допомагає уникати перезапусків під час законної ініціалізації.

ПомилкаЧому це трапляєтьсяЯк виправити
Використання тегу latestПід час тестування це здається зручним, але пізніше перестворення Pod’а може завантажити інший образ.Закріпіть тег версії, як-от nginx:1.25, чи використовуйте незмінний дайджест образу для критичних робочих навантажень.
Немає запитів ресурсівPod може працювати в тихій лабораторії, тож відсутній сигнал планування легко пропустити.Задайте запити CPU та пам’яті, що відображають виміряні мінімальні потреби, потім свідомо додайте ліміти.
Ігнорування подій kubectl describeОператори одразу переходять до логів, навіть коли контейнер ніколи не стартував.Читайте Events про планування, завантаження образу, монтування та збої проб, перш ніж змінювати специфікацію.
Забування --previous при циклах збоївПоточний перезапущений контейнер може ще не містити повідомлення про збій.Використовуйте kubectl logs POD --previous та оглядайте Last State у describe.
Перевірка залежностей у livenessКоманди повторно використовують широкий ендпоінт /health для кожної проби.Тримайте liveness зосередженою на внутрішньому здоров’ї процесу та помістіть готовність залежностей у readiness-перевірки.
Забування -c у багатоконтейнерних Pod’ахkubectl logs чи exec можуть за замовчуванням обрати неправильний контейнер чи попросити вас обрати.Указуйте -c container-name, коли Pod має більше ніж один контейнер.
Сприйняття IP Pod’ів як стабільнихТести прямого IP Pod’а працюють один раз, що може приховати поведінку заміни.Використовуйте IP Pod’ів для налагодження та Сервіси для стабільного трафіку застосунку.
Використання примусового видалення як звичайної звичкиВоно швидко очищає застряглі Pod’и, але оминає шлях завершення роботи, який вам потрібно перевірити.Надавайте перевагу звичайному видаленню, а --grace-period=0 --force залишайте для свідомих випадків прибирання.

1. Ваш Pod перебуває у стані `Pending` кілька хвилин, і `kubectl logs` повертає помилку, бо жоден контейнер не стартував. Що ви перевіряєте першим і чому?

Почніть із kubectl describe pod <name> та прочитайте розділ Events, бо Pod у стані Pending може не мати контейнера, що працює, для виведення логів. Події можуть показати недостатність CPU чи пам’яті, невідповідність node affinity, нестерпні taints, проблеми з томами чи повідомлення про налаштування завантаження образу. Якщо планування не вдалося, логи застосунку нерелевантні, бо kubelet ніколи не запускав контейнер. Якщо Pod було заплановано і він чекає на завантаження образу чи роботу init, той самий вивід describe вказує вам на цей шар далі.

2. Pod показує `CrashLoopBackOff` із багатьма перезапусками після розгортання нового образу. Які команди дають найшвидші корисні докази, і що ви шукаєте?

Спершу виконайте kubectl logs <pod> --previous, бо попередній екземпляр контейнера часто містить повідомлення про збій, що зникло, коли контейнер перезапустився. Потім виконайте kubectl describe pod <pod> та огляньте Last State, код виходу, лічильник перезапусків та Events. Код виходу 137 часто вказує на тиск на пам’ять, тоді як звичайні ненульові виходи зазвичай вказують назад на команду застосунку, конфігурацію чи залежності. Вам слід уникати видалення Pod’а до збору цих доказів, бо заміна може скинути найкорисніший контекст.

3. Вашому застосунку потрібен згенерований файл конфігурації перед запуском та помічник для відправлення логів під час роботи. Як ви маєте структурувати Pod, і якої поведінки збоїв слід очікувати?

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

4. Pod перебуває у стані `Running`, але показує `0/1` у стовпці `READY`, і користувачі не можуть дістатися до нього через Сервіс. Яку область рівня Pod'а найімовірніше треба оглянути?

Огляньте readiness-пробу та шлях ендпоінта Сервісу, перш ніж припускати, що процес мертвий. Pod у стані Running із готовністю 0/1 означає, що контейнер може бути живим, поки Kubernetes вважає його неготовим до трафіку. kubectl describe pod має показати збої readiness-проби, а перевірка ендпоінтів може підтвердити, чи виключено Pod із Сервісу. Liveness — це інше: якби liveness повторно не проходила, ви б очікували перезапусків, а не лише проблему з лічильником готовності.

5. Під час сповільнення бази даних Pod'и повторно перезапускаються, бо перевірки `/health` звертаються до бази даних і налаштовані як liveness-проба. Чому це погіршує збій, і як би ви перепроєктували проби?

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

6. Sidecar не може під'єднатися до основного контейнера на `localhost:8080`, і обидва контейнери в одному Pod'і. Які факти про Pod спрямовують вашу діагностику?

Контейнери в одному Pod’і мають спільний мережевий простір імен, тож localhost:8080 має дістатися основного контейнера, якщо основний процес насправді слухає цей порт. Перевірте, чи основний застосунок прив’язався до іншого порту, прив’язався лише після роботи з запуску чи впав після того, як sidecar почав намагатися під’єднатися. Також підтвердьте, що немає конфлікту портів, бо два контейнери в одному Pod’і не можуть обидва прив’язатися до того самого порту на спільному IP Pod’а. kubectl logs -c, kubectl exec -c та kubectl describe pod разом відокремлюють поведінку застосунку від припущень про мережу рівня Pod’а.

7. Ви згенерували маніфест Pod'а через `kubectl run --dry-run=client -o yaml`, відредагували його, і тепер він дає збій із `ImagePullBackOff`. Що вам слід оглянути, перш ніж змінювати не пов'язані поля?

Огляньте ім’я образу, тег, шлях реєстру та події завантаження образу в kubectl describe pod. ImagePullBackOff зазвичай означає, що Kubernetes намагався завантажити образ і не зміг, бо тег не існує, реєстр недоступний чи бракує автентифікації. Запити ресурсів, проби та контекст безпеки можуть мати значення пізніше, але вони не пояснюють невдале завантаження образу до того, як контейнер стартує. Спершу виправте посилання на образ чи доступ до реєстру, а потім зачекайте, доки Pod перейде до наступного етапу життєвого циклу.


Сценарій вправи: ви створите багатоконтейнерний Pod з init-контейнером, основним вебконтейнером та sidecar’ом для читання логів, потім оглянете життєвий цикл і приберете його. Мета — не лише змусити Pod працювати, а й попрактикуватися читати докази на кожному кроці. Тримайте маніфест на видноті, поки працюєте, щоб ви могли пов’язати вивід кожної команди з конкретним полем у специфікації Pod’а.

Завдання 1: Створити Pod з init-контейнером та sidecar’ом

Розділ «Завдання 1: Створити Pod з init-контейнером та sidecar’ом»
Terminal window
cat > multi-container-pod.yaml << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
initContainers:
- name: init-setup
image: busybox
command: ['sh', '-c', 'echo "Init complete" > /shared/init-status.txt']
volumeMounts:
- name: shared
mountPath: /shared
containers:
- name: web
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: logs
mountPath: /var/log/nginx
- name: log-reader
image: busybox
command: ['sh', '-c', 'tail -F /logs/access.log 2>/dev/null || sleep infinity']
volumeMounts:
- name: logs
mountPath: /logs
volumes:
- name: shared
emptyDir: {}
- name: logs
emptyDir: {}
EOF
kubectl apply -f multi-container-pod.yaml
Нотатки до розв'язання

Маніфест використовує init-контейнер, щоб записати файл перед запуском nginx, а потім монтує той самий том shared у вебконтейнер. Він також монтує том logs і в nginx, і в sidecar log-reader, щоб помічник мав доступ до файлів, створених основним контейнером. Якщо Pod не стартує, використайте kubectl describe pod webapp, перш ніж редагувати маніфест, бо розділ Events зазвичай ідентифікує перший шар, що дав збій.

Завдання 2: Зачекати на запуск та оглянути стан init

Розділ «Завдання 2: Зачекати на запуск та оглянути стан init»
Terminal window
# Wait for the pod to be fully ready
kubectl wait --for=condition=ready pod/webapp --timeout=90s
# Check init container completed
kubectl describe pod webapp | grep -A10 "Init Containers"
Нотатки до розв'язання

Команда wait має завершитися лише після того, як звичайні контейнери стануть готовими. Вивід describe має показати init-контейнер як успішно завершений, що підтверджує, що крок налаштування завершився перед тим, як контейнери застосунку стали активними. Якщо Pod залишається у стані init, огляньте логи init-контейнера за допомогою kubectl logs webapp -c init-setup, а потім перевірте команду, образ та монтування тома.

Завдання 3: Перевірити спільний том та бачення sidecar’а

Розділ «Завдання 3: Перевірити спільний том та бачення sidecar’а»
Terminal window
# Init container created this file
kubectl exec webapp -c web -- cat /usr/share/nginx/html/init-status.txt
# Execute command non-interactively
kubectl exec webapp -c log-reader -- ls /logs
Нотатки до розв'язання

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

Завдання 4: Згенерувати трафік та прочитати логи

Розділ «Завдання 4: Згенерувати трафік та прочитати логи»
Terminal window
# Get pod IP
POD_IP=$(kubectl get pod webapp -o jsonpath='{.status.podIP}')
# Generate traffic from another pod
kubectl run curl --image=curlimages/curl --rm -i --restart=Never -- curl -s $POD_IP
# Check sidecar saw the log
kubectl logs webapp -c log-reader
Нотатки до розв'язання

Це завдання використовує IP Pod’а для прямого налагодження, а не для стабільного трафіку застосунку. Тимчасовий Pod із curl має дістатися nginx, а команда логів sidecar’а має показати, чи може помічник читати вивід логів зі спільного монтування. У реальному шляху сервісу ви додали б Сервіс і тестували через DNS чи IP Сервісу, але прямий доступ до Pod’а тримає цю вправу зосередженою на мережі Pod’ів та поведінці sidecar’а.

Завдання 5: Попрактикувати цілеспрямоване налагодження та прибирання

Розділ «Завдання 5: Попрактикувати цілеспрямоване налагодження та прибирання»
Terminal window
# Logs from specific container
kubectl logs webapp -c web
kubectl logs webapp -c log-reader
# View recent logs
kubectl logs webapp -c web --tail=10
# Cleanup
kubectl delete pod webapp
rm multi-container-pod.yaml
Нотатки до розв'язання

Указування -c тримає ціль налагодження явною в багатоконтейнерному Pod’і. Прибирання використовує звичайне видалення Pod’а, щоб ви могли спостерігати коректне завершення, якщо запустите kubectl get pods -w в іншому терміналі. Примусове видалення не потрібне для цієї вправи, якщо Pod не застрягне з причин, які ви вже оглянули.

Тренувальні вправи

Розділ «Тренувальні вправи»

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

Terminal window
# 1. Basic nginx pod
kubectl run nginx --image=nginx
# 2. Pod with labels
kubectl run labeled --image=nginx --labels="app=web,tier=frontend"
# 3. Pod with port
kubectl run webserver --image=nginx --port=80
# 4. Pod with environment variables
kubectl run envpod --image=nginx --env="ENV=production" --env="DEBUG=false"
# 5. Pod with resource requests (set at creation via --overrides; a running
# bare pod's resources are immutable, so they cannot be patched in afterward)
kubectl run limited --image=nginx --overrides='{"spec":{"containers":[{"name":"limited","image":"nginx","resources":{"requests":{"cpu":"100m","memory":"128Mi"},"limits":{"cpu":"200m","memory":"256Mi"}}}]}}'
# Verify all pods
kubectl get pods
# Cleanup
kubectl delete pod nginx labeled webserver envpod limited
Terminal window
# Generate base YAML
kubectl run webapp --image=nginx:1.25 --port=80 --dry-run=client -o yaml > webapp.yaml
# View and verify
cat webapp.yaml
# Apply it
kubectl apply -f webapp.yaml
# Modify: add a label
kubectl label pod webapp tier=frontend
# Verify label
kubectl get pod webapp --show-labels
# Cleanup
kubectl delete -f webapp.yaml
rm webapp.yaml
Terminal window
# Create a pod that will fail
kubectl run failing --image=nginx --command -- /bin/sh -c "exit 1"
# Check status
kubectl get pod failing
# STATUS: CrashLoopBackOff
# Debug step 1: describe
kubectl describe pod failing | tail -20
# Debug step 2: logs
kubectl logs failing --previous
# Debug step 3: check events
kubectl get events --field-selector involvedObject.name=failing
# Cleanup
kubectl delete pod failing
Terminal window
# Create pod with sidecar
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: sidecar-demo
spec:
containers:
- name: main
image: nginx
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: sidecar
image: busybox
command: ['sh', '-c', 'while true; do date > /html/index.html; sleep 5; done']
volumeMounts:
- name: shared
mountPath: /html
volumes:
- name: shared
emptyDir: {}
EOF
# Wait for ready
kubectl wait --for=condition=ready pod/sidecar-demo --timeout=60s
# Test - sidecar writes timestamp that nginx serves
kubectl exec sidecar-demo -c main -- cat /usr/share/nginx/html/index.html
# Wait 5 seconds and check again - timestamp should change
sleep 5
kubectl exec sidecar-demo -c main -- cat /usr/share/nginx/html/index.html
# Cleanup
kubectl delete pod sidecar-demo
Terminal window
# Create pod with init container
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: init-download
image: busybox
command: ['sh', '-c', 'echo "Hello from init" > /work/message.txt']
volumeMounts:
- name: workdir
mountPath: /work
containers:
- name: main
image: busybox
command: ['sh', '-c', 'cat /work/message.txt && sleep 3600']
volumeMounts:
- name: workdir
mountPath: /work
volumes:
- name: workdir
emptyDir: {}
EOF
# Wait for init container and main container to be ready
kubectl wait --for=condition=ready pod/init-demo --timeout=60s
# Verify init worked
kubectl logs init-demo
# Check init container status
kubectl describe pod init-demo | grep -A5 "Init Containers"
# Cleanup
kubectl delete pod init-demo
Terminal window
# Create two pods
kubectl run pod-a --image=nginx --port=80
kubectl run pod-b --image=busybox --command -- sleep 3600
# Wait for ready
kubectl wait --for=condition=ready pod/pod-a pod/pod-b --timeout=60s
# Get pod-a IP
POD_A_IP=$(kubectl get pod pod-a -o jsonpath='{.status.podIP}')
echo "Pod A IP: $POD_A_IP"
# From pod-b, reach pod-a
kubectl exec pod-b -- wget -qO- $POD_A_IP
# Cleanup
kubectl delete pod pod-a pod-b
Terminal window
# Create pod with wrong image
kubectl run broken --image=nginx:nonexistent-tag
# Check status
kubectl get pod broken
# STATUS: ImagePullBackOff or ErrImagePull
# Diagnose
kubectl describe pod broken | grep -A10 "Events"
# Fix: update the image
kubectl set image pod/broken broken=nginx:1.25
# Verify fixed
kubectl get pod broken
kubectl wait --for=condition=ready pod/broken --timeout=60s
# Cleanup
kubectl delete pod broken
Terminal window
# Challenge prompt: complete this workflow without looking at the solution
kubectl run challenge --image=nginx:1.25 --labels="app=web,env=test"
kubectl wait --for=condition=ready pod/challenge --timeout=60s
kubectl exec challenge -- sh -c 'echo "Hello" > /tmp/test.txt'
kubectl get pod challenge -o wide
kubectl logs challenge --tail=10
kubectl delete pod challenge
Terminal window
# Challenge solution check: prove each requested result explicitly
kubectl run challenge --image=nginx:1.25 --labels="app=web,env=test"
kubectl wait --for=condition=ready pod/challenge --timeout=60s
kubectl exec challenge -- sh -c 'echo "Hello" > /tmp/test.txt'
kubectl exec challenge -- cat /tmp/test.txt
kubectl get pod challenge -o jsonpath='{.status.podIP}'
kubectl logs challenge
kubectl delete pod challenge
Terminal window
# Probe inspection drill: collect readiness and liveness evidence
kubectl describe pod webapp | grep -A20 "Conditions:"
kubectl describe pod webapp | grep -A20 "Events:"
kubectl get pod webapp -o jsonpath='{.status.containerStatuses[*].ready}'
Terminal window
# Lifecycle inspection drill: compare phase, container state, and restart count
kubectl get pod webapp
kubectl get pod webapp -o jsonpath='{.status.phase}'
kubectl get pod webapp -o jsonpath='{.status.containerStatuses[*].restartCount}'
kubectl describe pod webapp | grep -A8 "Last State"
  • Можу створювати Pod’и імперативними командами
  • Можу генерувати YAML через --dry-run=client -o yaml
  • Можу пояснити фази життєвого циклу Pod’а та поведінку політики перезапуску зі спостережуваного виводу
  • Можу налагоджувати за допомогою kubectl get, describe, logs та exec у правильному порядку
  • Можу створювати багатоконтейнерні Pod’и з init-контейнерами, sidecar’ами та спільними томами
  • Можу обирати readiness-, liveness- та startup-проби на основі наслідків збоїв

  • Pods — Підкріплює основи Pod’ів: Pod’и як найменша придатна для розгортання одиниця, модель з одним або кількома контейнерами, спільний мережевий простір імен, спільне сховище, co-location та абстракцію Pod’а, яку використовують контролери робочих навантажень вищого рівня.
  • Deployments — Підкріплює поведінку Деплойменту, володіння Deployment-to-ReplicaSet-to-Pod, стратегію розгортання, послідовні оновлення, поведінку maxSurge/maxUnavailable, історію розгортання, паузу/відновлення та концепції відкату.
  • DaemonSet — Підкріплює семантику «один Pod на ноду», автоматичне покриття доданих нод, поширені випадки використання рівня ноди, вибіркове розміщення на нодах через nodeSelector/affinity та поведінку tolerations DaemonSet.
  • StatefulSets — Підкріплює стабільну ідентичність Pod’а, порядкове іменування, стабільне сховище через volumeClaimTemplates, упорядковане розгортання та послідовні оновлення, вимоги до headless-Сервісу та поведінку мережевої ідентичності DNS.
  • Jobs — Підкріплює семантику виконання до завершення, backoffLimit, обмеження restartPolicy, completions, parallelism, заміну Pod’а при збої та поведінку пакетних робочих навантажень, відмінну від Деплойментів.
  • Security Context — Сторінка завдання про контекст безпеки Kubernetes безпосередньо визначає поле та документує точні приклади налаштувань, використані тут.
  • Pod Lifecycle — Підтримує твердження про фази Pod’а, термінологію планування/прив’язки, коректне завершення, terminationGracePeriodSeconds, виконання хука preStop під час завершення роботи та умови статусу зміни розміру Pod’а у v1.35.
  • Init Containers — Підкріплює впорядкування init-контейнерів, поведінку виконання до завершення, відмінності від контейнерів застосунку та послідовність запуску Pod’а перед стартом основних контейнерів.
  • Liveness, Readiness, and Startup Probes — Підкріплює семантику проб, відмінності між пробами liveness/readiness/startup та те, як kubelet реагує на невдалі проби чи утримує готовність під час запуску.
  • kubectl run — Підкріплює імперативне створення Pod’а та робочий процес --dry-run=client -o yaml, що використовується для швидкої генерації маніфесту.

Модуль 2.2: Деплойменти та ReplicaSet’и — Послідовні оновлення, відкати та масштабування.