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

Модуль 4.3: Вимоги до ресурсів та обмеження

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

Opens in Killercoda in a new tab

Складність: [MEDIUM] — критично для продакшену, впливає на планування

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

Передумови: Модуль 1.1 (Поди), розуміння концепцій CPU та пам’яті


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

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

Ці результати зосереджені на рішеннях, які ви зможете обґрунтувати під тиском іспиту CKAD і в реальному кластері. Наприкінці ви повинні вміти прочитати специфікацію ресурсів, передбачити поведінку планувальника та kubelet, яку вона породжує, і вибрати наступну діагностичну команду, не вгадуючи лише за симптомами.

  • Впроваджувати запити та обмеження CPU й пам’яті у специфікаціях Pod, Deployment, LimitRange та ResourceQuota.
  • Діагностувати поди у стані Pending, перезапуски OOMKilled та дроселювання CPU, співвідносячи налаштування ресурсів зі статусом і подіями Kubernetes.
  • Проєктувати розподіл ресурсів, що збалансовує продуктивність застосунку, ємність ноди, клас QoS та політику простору імен.
  • Порівнювати запити, обмеження, LimitRange та ResourceQuota, щоб передбачити, чи буде робоче навантаження відхилене, заплановане, сповільнене, вбите чи витіснене.

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

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

Гіпотетичний сценарій: реліз розгортається у завантажений день, і одночасно з’являються два різні збої. Один новий под залишається у стані Pending з подією Insufficient cpu, тоді як інший под успішно запускається, а потім перезапускається з Reason: OOMKilled. Обидва збої згадують ресурси, але вони відбуваються на різних фазах циклу управління Kubernetes, тож сприймати їх як одну й ту саму проблему — це марнувати час і ще більше виводити кластер з рівноваги.

Запити та обмеження ресурсів — це контракт між вашим робочим навантаженням, планувальником і середовищем виконання на ноді. Запит повідомляє планувальнику, скільки ємності потрібно зарезервувати, перш ніж под зможе потрапити на ноду. Обмеження повідомляє kubelet та середовищу виконання контейнера, скільки CPU чи пам’яті може спожити запущений контейнер. Ці два поля стоять поруч у YAML, але відповідають на різні операційні запитання: «Чи вміститься цей под тут?» і «Що станеться після його запуску?»

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

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

Запити, обмеження та обіцянка планувальника

Розділ «Запити, обмеження та обіцянка планувальника»

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

ТермінЗначенняКоли застосовується
Запит (Request)Гарантований мінімум ресурсівПід час планування
Обмеження (Limit)Максимально дозволені ресурсиПід час виконання

Уявіть запит як резервування у книзі обліку планувальника. Якщо под запитує 500m CPU та 256Mi пам’яті, планувальник шукає ноду щонайменше з такою кількістю незарезервованої доступної для виділення ємності. Він не запускає ваш процес, не вимірює фактичне використання й не прогнозує майбутні сплески. Він лише вирішує, чи може заявлене резервування вміститися поруч із резервуваннями, які вже присутні на ноді.

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

┌─────────────────────────────────────────────────────────────┐
│ Resource Request vs Limit │
├─────────────────────────────────────────────────────────────┤
│ │
│ Memory: │
│ ├── Request: 256Mi (guaranteed, used for scheduling) │
│ ├── Actual usage can vary between 0 and Limit │
│ └── Limit: 512Mi (hard cap, exceeding = OOMKill) │
│ │
│ CPU: │
│ ├── Request: 100m (guaranteed, used for scheduling) │
│ ├── Can burst above request if node has spare capacity │
│ └── Limit: 500m (throttled if exceeded, NOT killed) │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 0 Request Actual Limit │ │
│ │ | | | | │ │
│ │ ├───────────┼───────────┼────────────┤ │ │
│ │ │ guaranteed│ burstable │ max │ │ │
│ │ └───────────┴───────────┴────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

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

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

Зробіть паузу й передбачте: под запитує 100m CPU й має обмеження CPU 500m. Якщо на ноді є вільний CPU, под може використати до свого обмеження; якщо сусіднім подам також потрібен CPU, середовище виконання розподіляє час відповідно до налаштувань cgroup кожного контейнера й дроселює ті, що досягли квоти. Запит забезпечив подові планування, але не обмежив назавжди споживання під час виконання.

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

Написання специфікацій ресурсів, які Kubernetes може допустити

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

Блок ресурсів належить до кожного контейнера, а не безпосередньо до спеки пода. Ця деталь часто стає причиною помилок на іспиті, бо под має один результат планування, але ресурси оголошуються для кожного контейнера й лише потім сумуються для планування. Под із двома контейнерами, кожен з яких запитує 100m CPU, має запит на планування на рівні пода 200m CPU. Контейнери ініціалізації (init) обробляються для планування інакше, але для основ роботи з ресурсами в CKAD ключова звичка — щоразу розміщувати блок на рівні контейнера.

apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"

Цей маніфест говорить, що контейнеру потрібна зарезервована десята частина ядра CPU та 256Mi пам’яті, щоб бути запланованим. Він може сплеснути до половини ядра CPU, коли це дозволяє ємність під час виконання, і може виділити пам’ять до 512Mi, перш ніж обмеження стане фатальним. Значення тут наведені як рядки, бо взяття величин ресурсів у лапки дозволяє уникнути сюрпризів YAML і зберігає чітку візуальну відмінність. Kubernetes приймає величини ресурсів і без лапок, але значення в лапках — надійна звичка для прикладів і згенерованих маніфестів.

CPU вимірюється в ядрах, а суфікс m означає міліядра (millicores). Одне повне ядро — це 1 або 1000m, тож 250m означає чверть ядра. Запити та обмеження CPU можуть бути дробовими, бо процесорний час можна планувати частками. Для перегляду людиною міліядра зазвичай зручніші для невеликих сервісів, бо 100m читається легше, ніж 0.1.

ЗначенняЗміст
11 ядро CPU
1000m1000 міліядер = 1 ядро
500m0.5 ядра
100m0.1 ядра (10%)

Величини пам’яті можуть використовувати двійкові суфікси, як-от Mi та Gi, або десяткові суфікси, як-от M та G. Kubernetes приймає обидва, але вони не ідентичні, бо двійкові одиниці базуються на степенях 1024, а десяткові — на степенях 1000. Більшість прикладів Kubernetes використовують Mi та Gi, і це безпечніша угода, коли ви хочете, щоб значення відповідало тому, як оператори обговорюють пам’ять на нодах. У невеликому обмеженні різниця між 128M та 128Mi не велика, але узгоджені одиниці зменшують кількість помилок під час перегляду.

ЗначенняЗміст
128Mi128 мебібайтів (на основі 1024)
1Gi1 гібібайт = 1024 Mi
128M128 мегабайтів (на основі 1000)
1G1 гігабайт = 1000 M

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

Коли ви генеруєте маніфести на іспиті чи в локальній лабораторії, тримайте блок ресурсів близько до контейнера, яким він керує. Для Deployment блок ресурсів розташований під spec.template.spec.containers[], а не під верхньорівневим spec самого Deployment. Це розміщення може здаватися вкладеним, але воно віддзеркалює модель об’єктів: Deployment створює ReplicaSet, ReplicaSet створюють Поди, а шаблон пода несе налаштування контейнера, що використовуються кожною реплікою.

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

Математика ресурсів для багатоконтейнерних подів

Розділ «Математика ресурсів для багатоконтейнерних подів»

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

Арифметика проста для звичайних контейнерів застосунку. Якщо под має контейнер app, що запитує 200m CPU, та sidecar, що запитує 50m, то под просить планувальник зарезервувати 250m CPU. Запити пам’яті додаються так само, а обмеження описують стелю під час виконання для кожного контейнера окремо. Саме тому навіть невеликий сайдкар повинен мати ресурси: він може бути маленьким, але множення його на багато реплік перетворює забутий запит на помилку планування ємності.

apiVersion: v1
kind: Pod
metadata:
name: multi-container-demo
spec:
containers:
- name: app
image: nginx
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
- name: sidecar
image: busybox
command: ["sh", "-c", "sleep 3600"]
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "128Mi"

Для цього пода стале резервування для планування — це 250m CPU та 320Mi пам’яті. Контейнер app і сайдкар можна обмежувати незалежно, тож app може бути OOMKilled без того, щоб сайдкар перевищив власне обмеження пам’яті, а сайдкар може бути задроселений без зміни обмеження CPU контейнера app. Статус пода може підсумувати результат, але статус контейнера дає точну причину для кожного контейнера. Під час усунення несправностей завжди оглядайте назву контейнера, прикріплену до перезапуску чи останнього стану.

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

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

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

Розширені ресурси (extended resources) та величезні сторінки (huge pages) дотримуються тієї самої загальної теми: оголосіть те, що має бути зарезервоване перед запуском пода, і очікуйте, що Kubernetes плануватиме за цим оголошенням, а не за живим використанням. Питання з ресурсів у CKAD зазвичай тримаються CPU та пам’яті, але базовий урок переноситься. Kubernetes не може захистити спільну ємність здогадами, прихованими всередині застосунку. Спека пода мусить заявити резервування достатньо чітко, щоб допуск, планування та застосування на ноді могли виконати свою роботу.

Застосування під час виконання: OOMKill, дроселювання та QoS

Розділ «Застосування під час виконання: OOMKill, дроселювання та QoS»

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

Container uses > limit → OOMKilled → Container restarts

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

Terminal window
# Check if a pod was OOMKilled
kubectl describe pod my-pod | grep -A5 "Last State"
kubectl get pod my-pod -o jsonpath='{.status.containerStatuses[0].lastState}'

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

Container uses > limit → Throttled (slowed down, NOT killed)

Дроселювання CPU тихіше за OOMKill, бо контейнер зазвичай залишається у стані Running. Застосунок може повідомляти про повільні відповіді, затримку готовності, пропущені тайм-аути чи низьку пропускну здатність, тоді як Kubernetes усе ще показує под справним. kubectl top може показати поточне використання, коли встановлено Metrics Server, але саме дроселювання часто краще підтверджується через метрики часу виконання чи застосунку. На іспиті головна відмінність у тому, що обмеження CPU сповільнюють роботу, тоді як обмеження пам’яті можуть її завершити.

Зробіть паузу й передбачте: под має requests.cpu: 100m та limits.cpu: 500m, а на ноді доступне одне повне ядро CPU. Под може споживати до 500m, поки доступна ємність, але йому не гарантовано цей обсяг під час суперництва. Якщо кілька подів сплескують одночасно, їхні запити та засоби контролю часу виконання впливають на те, як розподіляється процесорний час. Саме тому сервіс може бути успішно запланований і все одно працювати погано, якщо його обмеження CPU занадто тісне.

Kubernetes призначає кожному поду клас якості обслуговування (QoS) на основі його налаштувань ресурсів. QoS не замінює запити, обмеження чи квоти; він впливає на порядок витіснення, коли нода під тиском. Поди Guaranteed отримують найсильніший захист від витіснення, бо кожен контейнер має рівні запити й обмеження CPU та пам’яті. Поди BestEffort отримують найслабший захист, бо вони не мають оголошеного резервування, тож будь-яке використання перевищує їхній запит, що дорівнює нулю.

Клас QoSУмоваІмовірність витіснення
GuaranteedЗапити = Обмеження для всіх контейнерівНайнижча (захищено)
BurstableЗапити < Обмеження (або встановлено лише одне)Середня
BestEffortНе встановлено запитів чи обмеженьНайвища

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

resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "256Mi" # Same as request
cpu: "100m" # Same as request

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

resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi" # Higher than request
cpu: "500m" # Higher than request

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

resources: {} # No resources defined

Зупиніться й подумайте: под має обмеження, але не має запитів. Kubernetes у деяких випадках може скопіювати обмеження в запити, а значення за замовчуванням простору імен також можуть мутувати відсутні поля. Це означає, що клас QoS, який ви очікуєте з маніфесту, може відрізнятися від об’єкта, збереженого після допуску. Оглядайте створений под, коли поведінка має значення, бо значення за замовчуванням під час допуску — частина контракту кластера.

Планування, політика простору імен та сигнали ємності

Розділ «Планування, політика простору імен та сигнали ємності»

Збої планування часто легше розв’язати, ніж збої під час виконання, бо планувальник залишає прямі докази в подіях. Под у стані Pending з Insufficient cpu чи Insufficient memory не зазнав збою всередині контейнера; він провалив тест на розміщення. Тест порівнює запити пода з доступною для виділення ємністю ноди, яка ще не зарезервована іншими подами. Саме тому саме лише зниження обмеження не змусить под у стані Pending заплануватися, якщо запит усе ще завеликий.

Terminal window
# Check why a pod is Pending
kubectl describe pod my-pod
# Events may show:
# 0/3 nodes are available: 3 Insufficient cpu.
# or
# 0/3 nodes are available: 3 Insufficient memory.

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

Terminal window
# Node capacity and allocatable
kubectl describe node NODE_NAME | grep -A5 Capacity
kubectl describe node NODE_NAME | grep -A5 Allocatable
# Already allocated
kubectl describe node NODE_NAME | grep -A10 "Allocated resources"

Сценарій-вправа: под запитує два ядра CPU, кожна нода має чотири ядра, і кожна нода все ще показує вільний CPU на дашборді. Под усе одно може залишатися у стані Pending, якщо наявні поди вже зарезервували планований CPU через запити. У цій ситуації збільшення обмеження пода нічого не дає, а зниження запиту пода допомагає лише тоді, коли нижче значення залишається чесним для робочого навантаження. Тривкі виправлення — це коректне розмірення запитів, переміщення чи масштабування інших робочих навантажень або додавання ємності.

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

apiVersion: v1
kind: LimitRange
metadata:
name: cpu-memory-limits
spec:
limits:
- default: # Default limits if not specified
cpu: "500m"
memory: "512Mi"
defaultRequest: # Default requests if not specified
cpu: "100m"
memory: "256Mi"
max: # Maximum allowed
cpu: "2"
memory: "2Gi"
min: # Minimum allowed
cpu: "50m"
memory: "64Mi"
type: Container
Terminal window
# View LimitRange objects in the current namespace
kubectl get limitrange
kubectl describe limitrange cpu-memory-limits

LimitRange змінює поведінку допуску до початку планування. Якщо под опускає ресурси, а простір імен має значення за замовчуванням, сервер API може зберегти спеку пода, що містить значення, яких автор не писав. Якщо под просить менше за мінімум чи більше за максимум, допуск відхиляє його ще до того, як планувальник його побачить. Ця відмінність дає вам чіткий порядок усунення несправностей: помилки допуску з’являються під час створення об’єкта, помилки планування з’являються після того, як об’єкт існує й залишається у стані Pending.

ResourceQuota також обмежена простором імен, але вона контролює загальний бюджет, спожитий об’єктами в цьому просторі імен. Квота може обмежити загальний запитаний CPU, запитану пам’ять, обмеження CPU, обмеження пам’яті, кількість подів та багато інших ресурсів. Коли квота відстежує обчислювальні ресурси, подам зазвичай потрібні поля ресурсів, щоб сервер API міг обчислити, чи перевищить новий об’єкт бюджет простору імен. Значення за замовчуванням LimitRange та ResourceQuota часто працюють разом, бо значення за замовчуванням дають квоті, що рахувати.

apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
spec:
hard:
requests.cpu: "4"
requests.memory: "8Gi"
limits.cpu: "8"
limits.memory: "16Gi"
pods: "10"
Terminal window
# View quota usage in the current namespace
kubectl get resourcequota
kubectl describe resourcequota compute-quota

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

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

Terminal window
# Check pod resources
kubectl get pod POD -o jsonpath='{.spec.containers[*].resources}'
# Check node capacity and allocation
kubectl describe node NODE | grep -A10 "Allocated"
# Check QoS class
kubectl get pod POD -o jsonpath='{.status.qosClass}'
# Check current usage when Metrics Server is available
kubectl top pod POD

Розбір прикладу: налаштування невеликого вебпода

Розділ «Розбір прикладу: налаштування невеликого вебпода»

Почніть з невеликого вебдеплойменту, що має реалістичний базовий рівень та помірний запас на сплеск. Деплоймент використовує дві репліки, тож планувальник мусить розмістити два резервування подів, а не лише одне. Кожна репліка запитує 50m CPU та 64Mi пам’яті, тож сукупний запитаний слід — це 100m CPU та 128Mi пам’яті на весь Деплоймент. Кожна репліка може сплеснути до 100m CPU та 128Mi пам’яті, перш ніж застосується обмеження.

apiVersion: apps/v1
kind: Deployment
metadata:
name: resource-web
spec:
replicas: 2
selector:
matchLabels:
app: resource-web
template:
metadata:
labels:
app: resource-web
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "128Mi"

Цей приклад навмисно невеликий, бо він навчає арифметики без потреби у великому кластері. Якщо ви застосуєте його в однонодному навчальному середовищі, запитаний слід має легко вміститися. Якщо под залишається у стані Pending, запит ресурсів — лише одна з можливих причин; селектори нод, taint’и, проблеми зі стягуванням образу та політика простору імен також можуть заблокувати поступ. Першою діагностичною командою все одно має бути kubectl describe pod, бо вона повідомляє події планувальника та підказки, пов’язані з допуском, поруч з об’єктом.

Terminal window
kubectl apply -f resource-web.yaml
kubectl get deploy resource-web
kubectl get pods -l app=resource-web
kubectl get pod -l app=resource-web -o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.qosClass}{"\n"}{end}'

Припустімо, обидва поди працюють і повідомляють QoS Burstable. Цей результат випливає безпосередньо з маніфесту, бо запити нижчі за обмеження як для CPU, так і для пам’яті. Якщо ви зміните кожне обмеження так, щоб воно дорівнювало відповідному запиту, поди стануть Guaranteed, але вони також втратять запас на сплеск. Якщо ви повністю приберете блок ресурсів, вони стануть BestEffort, якщо тільки LimitRange не підставить значення за замовчуванням.

Тепер припустімо, що Деплоймент має обслуговувати короткі сплески трафіку без частого дроселювання CPU. Підвищення обмеження CPU зі 100m до 250m може допомогти затримці, якщо нода має вільну ємність, але воно не змінює планування, бо запит CPU залишається 50m на репліку. Підвищення запиту CPU змінює планування та резервування, що може покращити справедливість під час суперництва, але може зменшити, скільки подів вміщується. Правильне редагування залежить від того, чи проблема — це ємність для сплесків під час виконання, чи резервування планувальником.

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

Який підхід ви б вибрали тут і чому: підвищити лише обмеження, підвищити лише запит, підвищити обидва чи спершу дослідити застосунок? Обґрунтована відповідь називає симптом. Поди у стані Pending вказують на запити та ємність, перезапуски OOMKilled вказують на обмеження пам’яті чи поведінку застосунку, а повільні-але-запущені поди вказують на дроселювання CPU, недостатній запит CPU під час суперництва або вузькі місця на рівні застосунку.

Остання перевірка — оглянути збережений об’єкт, а не лише файл, який ви редагували. Допуск може додати значення за замовчуванням, контролери можуть шаблонувати поди з Деплойменту, а люди можуть застосувати інший файл, ніж той, що на перегляді. kubectl get з JSONPath лаконічний, тоді як kubectl describe кращий, коли вам потрібен контекст подій та виділення на ноді. В умовах іспиту використовуйте найкоротшу команду, що доводить конкретне твердження, яке вам потрібно зробити.

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

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

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

ПатернКоли використовуватиЧому це працюєАспект масштабування
Базовий запит з виміряним обмеженням на сплескБездержавні сервіси зі змінним трафікомПланувальник резервує звичайний попит, тоді як середовище виконання дозволяє короткі сплескиПерегляньте після навантажувальних тестів та продакшен-вимірювань
Ресурси Guaranteed для критичних подів фіксованого розміруІнфраструктурні чи чутливі до затримки компоненти зі сталим використаннямЗахист QoS найсильніший, а конверт часу виконання явнийЕфективність ущільнення падає, бо спільне використання для сплесків зменшено
Значення за замовчуванням простору імен плюс квотаСпільні навчальні, командні чи орендарські простори іменКожен под має обчислювані ресурси, а простір імен має бюджетЗначення за замовчуванням треба переглядати, щоб крихітні лабораторії не успадковували завеликі резервування
Окрема діагностика за фазоюБудь-який под у стані Pending, відхилений, повільний чи з перезапускамиЗбої допуску, планування та виконання залишають різні доказиЗапустіть специфічну для фази команду, перш ніж змінювати YAML

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

АнтипатернЩо йде не такКраща альтернатива
Немає ресурсів на продакшен-подахПоди стають BestEffort, якщо тільки не застосуються значення за замовчуванням, а планування ємності стає оманливимВстановіть принаймні запити CPU та пам’яті для важливих робочих навантажень
Запити скопійовані з обмежень без роздумівПланувальник резервує пікову ємність, і кластер виглядає заповненим раноВстановлюйте запити за звичайним попитом, а обмеження — за безпечною межею сплеску чи захисту
Крихітні обмеження пам’яті для застосунків з важким часом виконанняКонтейнери перезапускаються під час запуску, збирання сміття чи прогріву кешуВиміряйте пам’ять процесу, врахуйте накладні витрати часу виконання й додайте свідомий запас
Гігантські обмеження CPU як виправлення продуктивностіДроселювання може переміщатися, а шумні робочі навантаження можуть впливати на сусідівВиміряйте дроселювання, налаштуйте запити та масштабуйте репліки чи шляхи коду за потреби

Команди потрапляють у ці антипатерни, бо YAML ресурсів виглядає простим. Складна частина — не синтаксис; це рішення, яке число відображає резервування, яке число відображає межу безпеки і який симптом доводить, що поточне число неправильне. Для CKAD вам потрібно бути швидкими із синтаксисом, але іспит усе одно винагороджує ту саму уявну модель, що використовується в продакшені. Опишіть под, ідентифікуйте фазу, а потім відредагуйте поле, що впливає на цю фазу.

Ще один практичний патерн — робити зміни ресурсів спостережуваними. Pull request, що змінює запити чи обмеження, має пояснити симптом, який він усуває, очікуваний вплив на планування та очікуваний вплив на час виконання. У лабораторії ви можете записати це обґрунтування в нотатці поруч із командою. У реальному репозиторії воно належить до контексту перегляду, щоб майбутні супровідники знали, чи значення було виміряне, успадковане чи вибране як безпечна стартова точка.

Фреймворк прийняття рішень

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

Використовуйте цей фреймворк, коли з’являється проблема з ресурсами і вам потрібно швидко вибрати наступний крок. Мета — не запам’ятати кожну можливу подію Kubernetes. Мета — класифікувати фазу збою, а потім вибрати об’єкт і поле, що справді можуть вплинути на цю фазу. Под у стані Pending не виправляється більшим обмеженням пам’яті, якщо запит також не змінюється, а под OOMKilled не виправляється меншим запитом CPU, якщо справжня проблема не в іншому місці.

Resource symptom appears
|
v
Was the object rejected by the API server?
|-- yes --> Check LimitRange and ResourceQuota admission rules
|
no
v
Does the pod exist but stay Pending?
|-- yes --> Check requests, node allocatable capacity, and scheduler events
|
no
v
Does the container restart with OOMKilled?
|-- yes --> Check memory limit, memory usage, runtime overhead, and leaks
|
no
v
Is the pod Running but slow under load?
|-- yes --> Check CPU limits, CPU requests under contention, and app metrics
|
no
v
Inspect QoS, eviction events, and neighboring workload pressure

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

СимптомПерший доказ для перевіркиНайімовірніше задіяне поле чи об’єктЧому
Под відхилено під час створенняПомилка API від kubectl applyLimitRange чи ResourceQuotaПолітика допуску виконується перед плануванням
Под залишається у стані PendingПодії kubectl describe podЗапити CPU чи пам’ятіПланувальник вміщує запити в доступну для виділення ємність
Контейнер перезапускається як OOMKilledОстанній стан контейнераОбмеження пам’яті чи поведінка пам’яті застосункуЧас виконання застосовує пам’ять як жорстку межу
Под у стані Running, але повільнийМетрики використання, затримки, дроселюванняОбмеження CPU, запит CPU чи кількість реплікТиск на CPU сповільнює роботу, а не вбиває її
Под витіснено під час тискуСтатус пода та події нодиКлас QoS та використання понад запитиВитіснення kubelet враховує запити та сигнали пріоритету пода

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

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

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

Останнє правило прийняття рішень — уникати сліпої зміни значень ресурсів під час інциденту. Якщо под у стані Pending, доведіть, що запитаний ресурс — це обмеження. Якщо контейнер OOMKilled, доведіть, чи обмеження нижче за спостережуваний пік, чи застосунок виділяє пам’ять неочікувано. Якщо сервіс повільний, доведіть, чи відбувається дроселювання CPU, перш ніж підвищувати обмеження. Швидка діагностика — це не те саме, що випадкове редагування YAML; це короткий шлях від симптому до механізму.

  • CPU стискуваний, пам’ять — ні. Якщо ви перевищите обмеження CPU, вас задроселюють. Якщо ви перевищите обмеження пам’яті, вас вб’ють.
  • Запити впливають на планування, обмеження — на час виконання. Под із запитом пам’яті 1Gi не запланується на ноді, де доступно лише 512Mi, навіть якщо контейнер використовує лише 100Mi.
  • Kubernetes не запобігає переобтяженню пам’яті. Якщо всі поди одночасно сплеснуть до своїх обмежень, на ноді може скінчитися пам’ять, і вона почне витісняти чи вбивати робочі навантаження.
  • Синтаксис cpu: 0.1 еквівалентний cpu: 100m, бо Kubernetes виражає дробовий CPU в міліядрах, де 1000m дорівнює одному ядру.

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

ПомилкаЧому вона трапляєтьсяЯк її виправити
Не встановлено ресурсівПоди BestEffort легко створити, і вони можуть працювати в порожніх кластерахВстановіть принаймні запити CPU та пам’яті для важливих подів
Запит більший за обмеженняАвтор сприймає обидва поля як незалежні нотатки, а не як впорядкований конвертТримайте кожен запит меншим чи рівним відповідному обмеженню
Обмеження пам’яті занадто низькеНакладні витрати часу виконання, сплески під час запуску чи зростання кешу не були врахованіПрофілюйте застосунок, огляньте стан OOMKilled і підвищуйте обмеження лише за наявності доказів
Обмеження CPU занадто низькеПод залишається у стані Running, тож дроселювання виглядає як сповільнення застосункуПеревірте використання та сигнали дроселювання, потім налаштуйте обмеження, запити чи репліки
Запит рівний ємності нодиПод не залишає доступного для виділення місця для системних резервувань чи інших подівЗалиште запас на ноді й розмірюйте запити відносно доступної для виділення ємності
Квота без запитів за замовчуваннямПоди, що опускають ресурси, не можна чисто врахувати у обчислювальній квотіПоєднуйте ResourceQuota зі значеннями за замовчуванням LimitRange у спільних просторах імен
Редагування Deployment, але огляд старого PodКонтролери створюють заміщувальні поди, а старі поди зберігають старі спеки до перестворенняРозгорніть оновлений шаблон і огляньте збережені ресурси нового пода

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

Запитання 1: Под постійно перезапускається, і `kubectl describe` показує `Last State: Terminated, Reason: OOMKilled`. Контейнер має `limits.memory: 128Mi`, а розробник каже, що застосунок зазвичай використовує близько 80MB. Що ви перевіряєте, перш ніж змінювати маніфест?

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

Запитання 2: Под залишається у стані Pending з `0/3 nodes are available: 3 Insufficient cpu`. Под запитує два ядра CPU, а кожна нода має чотири ядра, але вже запускає кілька робочих навантажень. Які ваші практичні варіанти?

Планувальник не може знайти ноду з двома незарезервованими доступними для виділення ядрами CPU, тож вам потрібно змінити запит чи доступну ємність. Ви можете зменшити запит, якщо докази показують, що робоче навантаження не потребує двох зарезервованих ядер, перемістити чи зменшити масштаб інших робочих навантажень або додати ємність ноди. Зміна лише обмеження CPU не виправить цей стан Pending, бо планувальник вміщує запити. Огляньте виділені ресурси через kubectl describe node, щоб побачити, скільки CPU вже зарезервовано.

Запитання 3: Деплоймент має п'ять реплік без запитів чи обмежень ресурсів. Під час тиску на пам'ять ноди ці поди витісняються раніше за сусідні сервіси. Чому Kubernetes сприйняв їх як легших кандидатів на витіснення?

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

Запитання 4: Простір імен має LimitRange зі значеннями CPU та пам'яті за замовчуванням. Розробник створює под без ресурсів, а потім бачить запити та обмеження на збереженому поді. Що сталося, і чому це може допомогти з ResourceQuota?

Плагін допуску LimitRange застосував значення за замовчуванням простору імен до контейнера, перш ніж об’єкт було збережено. Це означає, що маніфест, який написав розробник, — не вся історія; збережений под включає значення ресурсів, керовані політикою. Це допомагає ResourceQuota, бо обчислювальним квотам потрібні значення запитів та обмежень, щоб послідовно рахувати використання ресурсів. Правильні діагностичні команди — це kubectl get pod ... -o jsonpath для збережених ресурсів та kubectl describe limitrange для значень за замовчуванням простору імен.

Запитання 5: Сервіс у стані Running і ніколи не перезапускається, але затримка різко зростає під навантаженням після того, як обмеження CPU було знижено. Запит пода залишився тим самим. Який механізм ресурсів найбільш підозрілий?

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

Запитання 6: Новий под одразу відхиляється з помилкою квоти, але в кластері є ноди з вільною пам'яттю. Чому планувальник — не той компонент, який налагоджувати першим?

Об’єкт було відхилено під час допуску, тож планувальник так і не отримав под для розміщення. ResourceQuota обмежена простором імен і може відхилити под, коли додавання його запитів чи обмежень перевищило б бюджет простору імен. Вільна пам’ять ноди не перекриває квоту простору імен, бо квоти захищають межі виділення перед плануванням. Огляньте kubectl describe resourcequota, потім зменшіть запит пода, видаліть інші робочі навантаження простору імен або запросіть зміну квоти.

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

Завдання 1: Створіть Под з явними запитами та обмеженнями

Розділ «Завдання 1: Створіть Под з явними запитами та обмеженнями»

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

Розв'язок
Terminal window
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
EOF
# Check QoS class
kubectl get pod resource-demo -o jsonpath='{.status.qosClass}'
echo
# Check resources
kubectl get pod resource-demo -o jsonpath='{.spec.containers[0].resources}'
echo

Завдання 2: Спричиніть та огляньте контейнер OOMKilled

Розділ «Завдання 2: Спричиніть та огляньте контейнер OOMKilled»

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

Розв'язок
Terminal window
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: memory-hog
spec:
containers:
- name: app
image: polinux/stress
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "200M", "--vm-hang", "1"]
resources:
limits:
memory: "100Mi"
EOF
# Wait for pod initialization because image pull may take time
kubectl wait --for=condition=Initialized pod/memory-hog --timeout=60s
# Allow time for the stress test to hit the memory limit
sleep 10
kubectl get pod memory-hog
# Check the previous container state
kubectl describe pod memory-hog | grep -A3 "Last State"

Завдання 3: Попрактикуйте швидкий огляд ресурсів

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

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

Розв'язок
Terminal window
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: drill1
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
EOF
kubectl get pod drill1 -o jsonpath='{.spec.containers[0].resources}'
echo
kubectl get pod drill1 -o jsonpath='{.status.qosClass}'
echo
kubectl delete pod drill1

Завдання 4: Порівняйте поди Guaranteed та Burstable

Розділ «Завдання 4: Порівняйте поди Guaranteed та Burstable»

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

Розв'язок
Terminal window
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: drill2
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "100m"
memory: "128Mi"
EOF
kubectl get pod drill2 -o jsonpath='{.status.qosClass}'
echo
kubectl delete pod drill2

Завдання 5: Додайте ресурси до шаблону Deployment

Розділ «Завдання 5: Додайте ресурси до шаблону Deployment»

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

Розв'язок
Terminal window
cat << 'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: drill4
spec:
replicas: 2
selector:
matchLabels:
app: drill4
template:
metadata:
labels:
app: drill4
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "100m"
memory: "128Mi"
EOF
kubectl get pods -l app=drill4
kubectl get deploy drill4 -o jsonpath='{.spec.template.spec.containers[0].resources}'
echo
kubectl delete deploy drill4

Завдання 6: Спостерігайте значення за замовчуванням простору імен з LimitRange

Розділ «Завдання 6: Спостерігайте значення за замовчуванням простору імен з LimitRange»

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

Розв'язок
Terminal window
# Create namespace with LimitRange
kubectl create namespace drill6
cat << 'EOF' | kubectl apply -n drill6 -f -
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
spec:
limits:
- default:
cpu: "200m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
type: Container
EOF
# Create pod without resources
kubectl run drill6-pod --image=nginx -n drill6
# Check defaults were applied
kubectl get pod drill6-pod -n drill6 -o jsonpath='{.spec.containers[0].resources}'
echo
# Cleanup
kubectl delete namespace drill6

Видаліть усі поди, що залишилися з попередніх завдань, щоб простір імен був готовий до наступного модуля. Прибирання — частина вправи, бо лабораторії з ресурсами можуть залишати по собі збійні поди, і ці поди можуть заплутати пізніші огляди. Якщо ресурс не існує, бо ви вже його видалили, прапорець --ignore-not-found робить прибирання ідемпотентним.

Розв'язок
Terminal window
kubectl delete pod resource-demo memory-hog drill1 drill2 --ignore-not-found
kubectl delete deploy drill4 --ignore-not-found
kubectl delete namespace drill6 --ignore-not-found
  • Ви можете пояснити, чому resource-demo є Burstable, виходячи зі значень його запиту та обмеження.
  • Ви можете знайти OOMKilled у попередньому стані контейнера для memory-hog.
  • Ви можете оглянути збережені ресурси пода за допомогою JSONPath.
  • Ви можете відрізнити результат QoS на рівні пода від блоку ресурсів на рівні контейнера.
  • Ви можете ідентифікувати, де належать ресурси всередині шаблону пода Деплойменту.
  • Ви можете показати, що значення за замовчуванням LimitRange були застосовані до пода, який опустив ресурси.

Модуль 4.4: SecurityContexts — далі ви налаштуєте параметри безпеки пода й контейнера, а потім з’єднаєте ці засоби контролю з межами часу виконання, які ввели налаштування ресурсів тут.