Deployments, StatefulSets і DaemonSets у Kubernetes
У Kubernetes для керування подами використовують різні типи контролерів. Найпоширеніші з них — Deployment, StatefulSet та DaemonSet. Вони виконують різні функції, хоча на рівні конфігурацій можуть виглядати схожими.
Вибір контролера безпосередньо впливає на стабільність застосунку, поведінку під час оновлень, масштабування та відновлення після збоїв. Помилки на цьому етапі зазвичай проявляються вже в продакшні — під навантаженням або під час інцидентів.
У цій статті розглянемо, як працюють Deployments, StatefulSets і DaemonSets, у чому полягають їх ключові відмінності та в яких випадках кожен із них доцільно використовувати в кластерах Kubernetes.
Контролери Kubernetes
У Kubernetes майже всім керують контролери. Їхнє завдання — стежити за поточним станом ресурсів і приводити його до бажаного. Ви описуєте як має бути, а контролер вирівнює реальність під цю декларацію.
Важливо: Deployments, StatefulSets і DaemonSets керують подами, але з різними гарантіями щодо ідентичності, порядку запуску та прив’язки до вузлів. Саме ці гарантії та визначають, який варіант правильний.
Deployment: стандарт для застосунків stateless
Deployment — найпоширеніший спосіб запуску застосунків у Kubernetes. Він створює й підтримує потрібну кількість однакових подів (реплік) та вміє оновлювати їх поступово, без простою сервісу.
Ключова ідея: поди взаємозамінні. Якщо один падає, його можна замінити іншим з таким самим шаблоном, і для користувача це буде непомітно.
Що дає Deployment на практиці?
- Автовідновлення. Видалили под випадково або він впав — контролер підніме новий.
- Масштабування. Потрібно більше потужності — збільшили replicas, і кластер додав поди.
- Rolling update. Оновлення образу відбувається порціями: частина подів уже на новій версії, частина — ще на старій.
- Rollback. Якщо оновлення пішло не так, можна повернутися до попереднього стану.
Ось базовий YAML-файл для розгортання:
apiVersion: apps/v1
kind: Deployment
metadata:
name: simple-web-app
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
image: nginx:latest
ports:
- containerPort: 80
Коли обирати Deployment?
Deployment підходить, якщо:
- застосунок не зберігає критичний стан усередині пода;
- будь-який под може обробити будь-який запит;
- ви хочете прості оновлення й масштабування.
Типові приклади: фронтенд, API, мікросервіси, проксі.
На що звернути увагу, щоб не наступити на граблі?
- Readiness та liveness probes
Readiness визначає, коли под готовий приймати трафік. Без нього оновлення може пройти формально успішно, але запити почнуть надходити на сервіс, який ще не готовий до роботи. Liveness відповідає за перезапуск завислих або некоректно працюючих контейнерів.
- Ресурсні обмеження
Якщо для контейнерів не задано мінімальні та максимальні обсяги ресурсів, Kubernetes гірше розподіляє навантаження. У результаті один сервіс може перевантажувати вузол і впливати на роботу інших компонентів кластера.
- Стратегія оновлення
Для сервісів, що мають працювати без простою, важливо коректно налаштувати параметри maxUnavailable і maxSurge. Вони визначають, скільки подів може бути недоступно та скільки нових подів створюється під час rolling update.
Корисні команди для перевірки:
- kubectl get deployments
Виводить список наявних розгортань у поточному namespace та їхній стан: кількість бажаних, поточних і доступних реплік. Дозволяє перевірити, чи конфігурація застосована коректно.
- kubectl get pods
Показує всі поди, створені в межах розгортання, їхній статус і час роботи. Команда допомагає швидко виявити проблеми зі стартом або виконанням контейнерів.
- kubectl rollout status deployment/web
Відображає стан процесу оновлення. Дає змогу перевірити, чи rolling update завершився успішно або ще триває.
- kubectl rollout undo deployment/web
Повертає систему до попередньої версії у разі проблем після оновлення.
StatefulSet: керування застосунками зі збереженням даних
StatefulSet потрібен там, де застосунок має зберігати дані або покладається на стабільну ідентичність кожного екземпляра. На відміну від Deployment, він гарантує, що поди матимуть сталі імена та запускатимуться в чіткому порядку.
Побачите таке найменування: app-0, app-1, app-2. Якщо app-1 впаде, Kubernetes підніме саме app-1 з тим самим індексом.
Ключові можливості StatefulSet
- Стабільні імена подів. Поди мають імена, що дозволяє базам даних і розподіленим сервісам коректно працювати після перезапусків.
- Окреме постійне сховище для кожного пода. Зазвичай через volumeClaimTemplates.
- Послідовне масштабування. Поди стартують і зупиняються по черзі, що зменшує ризик хаосу під час перебудови кластера.
Скорочений фрагмент YAML-файлу для прикладу:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
spec:
serviceName: "redis"
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:latest
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Коли потрібен StatefulSet?
Обирайте StatefulSet, якщо:
- дані мають пережити перезапуск пода;
- вузли кластера мають стабільні DNS-імена;
- важливий порядок старту/зупинки (наприклад, leader/follower).
Типові приклади: PostgreSQL, MySQL, MongoDB, Redis у кластерному режимі, Kafka.
Практичні нюанси, про які часто забувають
- Service для StatefulSet
Для коректної роботи StatefulSet зазвичай використовують headless Service. Він забезпечує стабільні DNS-імена для подів і дозволяє сервісам звертатися до них напряму. - StorageClass
У кластері має бути налаштований StorageClass для динамічного створення томів. Якщо його немає, PersistentVolumeClaim не буде прив’язаний до сховища й залишиться в статусі Pending. - Доступ до даних
Режим ReadWriteOnce дозволяє підключати том лише до одного вузла одночасно. Це підходить для більшості баз даних, але обмежує можливість паралельного доступу з кількох вузлів.
Корисні команди:
- kubectl get statefulsets
Показує список StatefulSet у поточному namespace та їхній поточний стан.
- kubectl get pvc
Виводить усі PersistentVolumeClaim та їхній статус, зокрема чи прив’язані вони до сховища.
- kubectl describe pvc <name>
Відображає детальну інформацію про вибраний PVC, включно з подіями та можливими причинами проблем.
DaemonSet: запуск одного пода на кожному вузлі кластера
DaemonSet розв’язує завдання запусти цей под на кожному вузлі кластера. Тут ви не задаєте кількість реплік вручну: скільки вузлів — стільки й подів. Додали новий вузол — под з’явився автоматично.
Де DaemonSet найчастіше використовується?
- Збір логів (Fluentd, Filebeat), коли потрібно читати файли на вузлі.
- Моніторинг вузлів (node exporter), щоб бачити метрики системи.
- Мережеві плагіни (Calico, Cilium) та інші компоненти, які мають бути всюди.
Приклад:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: log-collector-container
image: fluentd:latest
resources:
limits:
memory: "200Mi"
cpu: "100m"
Нюанси DaemonSet, які впливають на безпеку
DaemonSet часто використовує hostPath, тобто отримує доступ до файлової системи вузла. Це нормально для лог-агента, але потребує дисципліни:
- давайте мінімально необхідні права;
- уникайте запуску з привілейованим режимом без потреби;
- контролюйте, на яких вузлах це має працювати (nodeSelector, tolerations).
Як швидко обрати правильний контролер?
Спробуйте пройтися чеклистом:
- Застосунок stateless і поди взаємозамінні? Обирайте Deployment.
- Потрібні стабільні імена, власні диски, порядок старту? Обирайте StatefulSet.
- Потрібно, щоб компонент працював на кожному вузлі? Обирайте DaemonSet.
І ще одна порада з практики: якщо хочеться запустити базу даних у Deployment краще зупинитись. На демо це може пройти, але під час перезапусків ви ризикуєте отримати втрату даних або неконсистентний кластер. Для баз даних у Kubernetes майже завжди доречніший StatefulSet (або керований сервіс у хмарі).
Висновок
У Kubernetes немає універсального контролера для всіх випадків. Кожен тип закладає різні припущення щодо життєвого циклу подів, роботи зі сховищем і взаємодії з вузлами кластера. Якщо ці припущення не збігаються з реальними вимогами застосунку, система починає поводитися непередбачувано під час оновлень, або відновлення після збоїв.
Тому під час проєктування варто виходити не з простоти конфігурації, а з очікуваної поведінки сервісу в продакшні. Саме це визначає, який контролер забезпечить стабільну роботу кластера в довгостроковій перспективі.