Збої containerd у кластері: що ламається і чому
Найчастіша картина: вузол оновили, службу перезапустили — і контейнер не запускається. Поди висять у стані очікування створення, хоча образ на місці й реєстр доступний, а в логах видно, що запит до середовища виконання контейнерів завершився помилкою.
Для сервісу це втрата ємності: частина реплік не піднімається, решта отримує підвищене навантаження.
Причина майже завжди в розсинхронізації налаштувань, а не в «сирому» оновленні. У containerd налаштування драйвера керування групами процесів має збігатися з тим, що використовує kubelet: якщо один працює через systemd, а другий через cgroupfs, поди мовчки не стартують.
Туди ж додаються обраний snapshotter, ліміти на паралельні операції та сміття від старих шарів — кластер втрачає вузли по одному.
Друга група збоїв середовища виконання контейнерів — служба перестає відповідати, а не падає. Сокет зайнятий завислим процесом, збирання сміття йде довше звичайного, sandbox-образ не завантажується через недоступне дзеркало — і частина подів іде в перезапуск по колу.
Помилки середовища виконання при цьому не завжди доходять до моніторингу: вузол вважається здоровим, перевірки готовності не проходять, тому сервіс тихо втрачає частку трафіку.
Ціна таких інцидентів — не зупинка кластера, а розтягнуте розслідування. Автоперезапуск маскує першопричину, метрики вузла виглядають рівно, а деградація накопичується годинами. Нижче розбираємо, як це закривається налаштуванням і регламентом.
Що дає кероване середовище виконання контейнерів
Налаштоване середовище виконання проявляється насамперед у часі запуску контейнерів. Профіль containerd визначає, як розкладаються шари образу, скільки розпакувань іде паралельно і як довго живе кеш на вузлі.
З вивіреними значеннями зникає основна частина звернень до реєстру під час розкатки реплік — старт поду скорочується із секунд до десятих часток, а масовий перезапуск застосунку перестає розтягуватися на хвилини.
Передбачуваність кластера тримається на тому, що конфігурація описана як код і розкочується однаково на всі вузли. Оновлення рантайму спочатку проходить на одному вузлі, і лише після повного циклу запуску застосунку профіль вирушає в інші групи.
Поведінка під час оновлень перестає залежати від того, хто і коли правив вузол руками, а розбіжність між нодами видно до того, як воно стане інцидентом.
Окремо знімається клас відмов, які виглядають як спонтанні: вузол переходить у статус недоступного, поди переїжджають, причина не читається в журналі. За цим зазвичай стоять ліміти на дисковий ввід-вивід, некероване зростання сховища образів і витоки знімків файлової системи.
Ззовні це падіння вузла, фактично — кілька рядків у конфігурації, після правки яких відмови вузлів припиняються.
Ефект налаштування вимірюваний: частка відмов на етапі запуску падає, перевстановлення вузла з профілю займає хвилини замість ручного складання, інциденти переходять у розряд відтворюваних.
Сховище перестає зростати безконтрольно — чищення старих образів іде за розкладом, при цьому відкат на попереднє складання залишається доступним.
У підсумку стабільність середовища виконання перестає бути заслугою конкретного інженера. Профіль версіонується разом з інфраструктурним кодом, зміни проходять перевірку на тестовому контурі, і кожен новий вузол входить у стрій у тому ж стані, що й попередні.
Порівняння режимів роботи containerd та їх обмеження
containerd як середовище виконання задає поведінку вузла конфігурацією: який плагін приймає запити від kubelet, як зберігаються шари образів, чим обмежуються ресурси контейнерів.
Один профіль на всіх вузлах — умова передбачуваного планування; різні профілі на сусідніх вузлах дають розбіжності, які спливають уже під навантаженням.
| Варіант налаштування | Коли підходить | Обмеження |
|---|---|---|
| Вбудований плагін для Kubernetes, запуск через звичайні простори імен, шарувате зберігання образів | Сервіси з високою щільністю на вузол, важлива швидкість старту | Потрібна файлова система з підтримкою шарів; ізоляція лише на рівні ядра |
| Той самий плагін, але дискове зберігання шарів | Мережеві томи та файлові системи без підтримки шарів | Більше місця під образи, довше підйом контейнера |
| Ізольоване ядро на контейнер | Недовірений код, мультиорендність, жорсткі вимоги безпеки | Вища витрата процесора та пам'яті, частина системних викликів недоступна |
| Шар сумісності з Docker | Лише на час переходу старого парку | Застарілий шлях, зайвий посередник, розбіжності під час оновлення вузлів |
| Окремі профілі виконання на одному вузлі | Змішані навантаження: сервіси поряд зі складаннями та ізоляцією | Складніша конфігурація, ресурси плануються окремо для кожного профілю |
Де налаштування впирається в обмеження
Профіль зберігання визначає щільність вузла: шарувате зберігання економить місце й прискорює запуск, але потребує сумісної файлової системи, дискове — передбачуваніше щодо запису, зате образи займають помітно більше.
Зміна схеми зберігання або драйвера обмеження ресурсів не застосовується на живому вузлі: потрібен перезапуск служби, а отже, витиснення контейнерів і перепланування — такі роботи планують як планове обслуговування, а не як правку «на ходу».
Окреме обмеження — узгодженість: профіль, якого немає на частині вузлів, ламає розклад і моніторинг. Ми фіксуємо матрицю профілів, перевіряємо її на тестовому контурі і лише потім розкочуємо по групах вузлів.
Порядок впровадження: від аудиту до передачі в експлуатацію
Впровадження йде одним маршрутом: спочатку фіксуємо фактичний стан середовища виконання, потім проєктуємо цільову конфігурацію і лише потім чіпаємо прод.
Такий порядок прибирає правки «на живу»: на кожному кроці залишається артефакт, за яким можна звірити результат або відкотитися.
- Аудит конфігурації кластера. Знімаємо версію containerd, склад плагінів, ліміти ресурсів, параметри збирача сміття та логування, налаштування драйвера знімків. Розбіжності між вузлами зазвичай видно саме тут.
- Схема цільової конфігурації. Узгоджуємо єдиний профіль для всіх вузлів і позначаємо кожне відхилення від поточного стану: навіщо воно потрібне і що зачепить.
- Налаштування середовища виконання на стенді. Переносимо профіль на тестовий контур, перевіряємо сумісність із поточною гілкою Kubernetes, монтованими томами та образами робочих навантажень.
- Перевірка під навантаженням. Проганяємо щільний потік створення та видалення контейнерів, дивимося затримки старту, споживання пам'яті та піки дискового вводу-виводу. Деградацію ловимо до проду, а не після.
- Викочування на прод. Оновлюємо вузли по одному з витисненням подів і паузами на звірку метрик; у разі відхилення вузол повертається до попереднього профілю.
- Передача в експлуатацію. Віддаємо черговій команді конфігурації під контролем версій, схему відкату та розбір типових відмов, проводимо тренування на реальному інциденті.
Конфігурації, схеми та регламенти на виході
Усі налаштування, які ми робимо під час робіт, залишаються в замовника у вигляді файлів, а не в листуванні та головах інженерів. Це ключова умова: якщо через пів року задачу вестиме інша команда або ваш штатний фахівець, він отримує робочу картину середовища, а не набір здогадок. Нижче — що саме передається разом із кластером.
- Файли конфігурації кластера — декларації по кожному середовищу окремо, з явним зазначенням, що успадковується від базового шару, а що перевизначається на місці; правки вносяться лише через систему контролю версій.
- Схеми зв'язків сервісів — що з чим спілкується, через які точки входу йде трафік, де проходять межі довіри і які вузли стають єдиною точкою відмови.
- Правила обмеження прав — ролі та області доступу для сервісів і людей, заборона зайвих привілеїв за замовчуванням, порядок видачі тимчасового розширеного доступу та його автоматичного відкликання.
- Документація щодо середовища — склад вузлів, актуальна гілка рантайму (зокрема containerd), адреси сховищ образів і систем логування, порядок підключення нових вузлів.
- Регламенти оновлення — послідовність викочування, перевірка сумісності до застосування, умови зупинки та покроковий відкат на попередній стан.
- Сценарії діагностики типових збоїв — що перевіряє черговий у разі недоступності сервісу, при завислому вузлі, при нестачі місця під образи, — з командами та очікуваним виводом.
- Перелік приймальних перевірок — які тести мають пройти зеленими на кожному середовищі перед передачею, і хто фіксує результат.
Комплект документів оновлюється разом зі змінами, а не оформлюється заднім числом. Якщо щось у середовищі змінюється без відображення у файлах і схемах, це вважається незавершеною роботою.
Кейс: кластер перестав втрачати вузли при піковому навантаженні
Кластер під піковим навантаженням втрачав вузли: агент на вузлі перестав відповідати на перевірки стану, вузол переходив у NotReady, і планувальник перезапускав його контейнери на решті машин. Ті отримували подвійний трафік і відпадали слідом — каскад ішов по колу.
У години піку в стані NotReady перебувало 12–18% вузлів, виведення вузла в робочий режим займало до 40 хвилин, доступність сервісів просідала до 99,3%.
Розбір показав, що річ не в залізі, а в конфігурації середовища виконання.
Стандартний профіль containerd з базовими лімітами не витримував щільності контейнерів на вузлі: драйвер логування писав синхронно й блокував процеси, образи тягнулися із зовнішнього реєстру при кожному старті, перевірки готовності спрацьовували раніше, ніж застосунок піднімався.
Ми підняли ліміти на дескриптори та процеси під реальну щільність, перевели логування в асинхронний режим з обмеженням розміру файлу, додали локальний кеш образів із попереднім завантаженням на вузли й привели таймаути перевірок до фактичного часу ініціалізації.
Метрики до та після
| Показник | До | Після |
|---|---|---|
| Вузли в NotReady у пік | 12–18% | 0 |
| Виведення вузла в робочий режим | до 40 хв | 6 хв |
| Запуск застосунку | 25 с | 4 с |
| Доступність сервісу | 99,3% | 99,95% |
Зміни застосовували по групах із 3–5 вузлів, конфігурація версіонується разом із маніфестами — у разі відхилення метрик група відкочується на попередній профіль. За місяць пікових навантажень жодної каскадної відмови: вузли вибували лише на плановому обслуговуванні.
Чим containerd відрізняється від альтернативних середовищ виконання
<cite>containerd</cite> — окремий демон, який kubelet викликає через інтерфейс середовища виконання (CRI): завантажує образ, готує кореневу файлову систему та запускає процес низькорівневим середовищем runc.
Docker Engine влаштований інакше — той самий containerd усередині, але зверху додано складання образів, командний рядок, томи та користувацьку мережу.
Кластеру ця надбудова не потрібна: вона додає зайвий демон між kubelet і контейнером, а розбіжності її стану між вузлами дають різну поведінку при однаковому маніфесті.
Найближча альтернатива — CRI-O, і вона свідомо вужча: лише мінімум, потрібний інтерфейсом, без плагінів складання й кількох снапшоттерів.
Критерій вибору простий: CRI-O — коли потрібне гранично тонке середовище, containerd — коли потрібні різні снапшоттери, простори імен для орендарів та ізольовані пісочниці.
Сумісність задає не назва середовища, а підтримка потрібної версії інтерфейсу та налаштування мережі й томів. Перехід на інше середовище в працюючому кластері — не підміна виконуваного файлу.
Контейнери, створені попереднім середовищем, нове не побачить: потрібне виведення вузла з балансування, зупинка навантаження, переналаштування й повторний запуск подів, які створюються вже в новому сховищі.
Образи тому завантажуються заново, а журнали та метрики переїжджають в інший формат — збір треба переналаштувати заздалегідь.
Перехід виправданий, коли заважає сама надбудова: розбіжності версій між вузлами, зайва витрата пам'яті, потреба в ізоляції, яку попереднє середовище не підтримує. Після нього ланцюжок запуску коротший, налаштування єдине на всіх вузлах, а точок відмови на одну менше.
Часті сумніви щодо налаштування та сумісності
Зміни в середовищі контейнерів майже завжди зачіпають працюючий кластер, тому сумніви в команд одні й ті самі: чи доведеться зупиняти сервіси, що буде при розбіжності вузлів і як переконатися, що правки не зламали запуск. Нижче — короткі відповіді, далі переходимо до плану робіт.
Чи можна застосовувати правки на живому кластері?
Так, і зазвичай тільки так і роблять. Налаштування рантайму застосовуються до нових запусків, а працюючі контейнери продовжують жити у своїх просторах імен — їхній перезапуск не потрібен.
Тому конфігурацію закочують по одному вузлу: вузол виводиться з обслуговування, навантаження переїжджає на решту, застосовуються правки, вузол повертається в стрій. Доступність сервісу не падає, змінюється лише порядок викочування.
Що робити, якщо версії вузлів розійшлися?
Спочатку вирівнюємо: однаковий набір параметрів рантайму на всіх вузлах, інакше той самий образ поводиться по-різному залежно від того, куди його поставив планувальник.
Розбіжність зазвичай спливає на старих вузлах, які не перезбирали під час оновлення — їх оновлюємо в першу чергу і лише потім переносимо навантаження.
Як переконатися, що зміни коректні?
Кожну правку перевіряємо на тестовому вузлі тим самим набором робочих навантажень, що й у продуктивному середовищі: запуск контейнера, монтування томів, мережевий доступ, коректне завершення процесів.
Потім — контрольний прогін на одному вузлі кластера і лише після цього викочування на решту. Так помилка конфігурації видна до того, як зачепить весь кластер.
Як відкотити конфігурацію?
Файли налаштувань зберігаємо під контролем версій, а перед кожною зміною знімаємо копію поточного стану вузла. Відкат — це повернення попереднього набору та повторне викочування тим самим порядком, по одному вузлу. Займає стільки ж часу, скільки й саме оновлення, і не потребує перезбирання кластера.
Обговоримо задачу: аудит конфігурації та план робіт
Обговоримо задачу: аудит конфігурації та план робіт
Щоб оцінка робіт по кластеру спиралася на факти, а не на здогадки, інженерам достатньо мінімального набору ввідних.
Надсилати вивантаження повністю не потрібно — вистачить переліченого нижче: за цими даними ми відновимо картину оточення й зрозуміємо, де конфігурація розходиться з реальним навантаженням.
- Чинний конфігураційний файл containerd і вивід поточних параметрів. За ним видно, що перевизначено вручну, а що залишилося в значеннях за замовчуванням.
- Спосіб створення вузлів: шаблони образів, сценарії встановлення або конфігурація провіжинінгу. Так зрозуміло, де правки закріпляться, а де роз’їдуться при наступному масштабуванні.
- Опис симптому з прив’язкою до часу та повні журнали вузла за вікно збою — вони дають більше, ніж переказ.
- Склад оточення: число вузлів та їхніх груп, чи відрізняються профілі керуючих і робочих машин, скільки середовищ обслуговується.
- Відомості про реєстр образів: чи використовується локальний кеш, як організована автентифікація, чи є обмеження на вивантаження.
- Обмеження: вікно обслуговування, вимоги до відкату, політики безпеки та розмежування прав.
- Що вже пробували і з яким результатом — це знімає етап повторної діагностики.
Після розбору ввідних ми повернемося з оцінкою та планом налаштування: що змінюємо на першому етапі, де потрібні вікна обслуговування і в якому порядку йдемо.
Аудит конфігурації йде першим — він задає точки відкату, тому початок робіт не залежить від того, наскільки запущений поточний стан. Опишіть задачу — обговоримо склад робіт і строки.







