StatefulSets
StatefulSet — це обʼєкт робочого навантаження API, який використовується для управління застосунками зі збереженням стану.
StatefulSet керує розгортанням і масштабуванням групи Podʼів, і забезпечує гарантії щодо порядку та унікальності цих Podʼів.
Схожий на Deployment, StatefulSet керує Podʼами, які базуються на ідентичній специфікації контейнерів. На відміну від Deployment, StatefulSet зберігає постійну ідентичність для кожного свого Podʼа. Ці Podʼи створюються за однаковою специфікацією, але не є взаємозамінними: у кожного є постійний ідентифікатор, який він утримує при переплануванні.
Якщо ви хочете використовувати томи для забезпечення постійності для вашого завдання, ви можете використовувати StatefulSet як частину рішення. Навіть якщо окремі Podʼи в StatefulSet можуть вийти з ладу, постійні ідентифікатори Podʼів полегшують відповідність наявних томів новим Podʼам, які замінюють ті, що вийшли з ладу.
Використання StatefulSets
StatefulSets є цінним інструментом для застосунків, які потребують однієї або декількох речей з наступного.
- Стабільних, унікальних мережевих ідентифікаторів.
- Стабільного, постійного сховища.
- Упорядкованого, відповідного розгортання та масштабування.
- Упорядкованих, автоматизованих поступових (rolling) оновлень.
У випадку відсутності потреби в стабільних ідентифікаторах або упорядкованому розгортанні, видаленні чи масштабуванні, вам слід розгортати свою програму за допомогою робочого обʼєкта, який забезпечує набір реплік без збереження стану (stateless). Deployment або ReplicaSet можуть бути більш придатними для ваших потреб.
Обмеження
- Місце для зберігання для певного Podʼа повинно буде виділене чи вже виділено PersistentVolume Provisioner на основі запиту storage class, або виділено адміністратором наперед.
- Видалення та/або масштабування StatefulSet вниз не призведе до видалення томів, повʼязаних з StatefulSet. Це зроблено для забезпечення безпеки даних, яка загалом є важливішою, ніж автоматичне очищення всіх повʼязаних ресурсів StatefulSet.
- Наразі для StatefulSets обовʼязково потрібний Headless Service щоб відповідати за мережевий ідентифікатор Podʼів. Вам слід створити цей Сервіс самостійно.
- StatefulSets не надають жодних гарантій щодо припинення роботи Podʼів при видаленні StatefulSet. Для досягнення упорядкованого та відповідного завершення роботи Podʼів у StatefulSet можливо зменшити масштаб StatefulSet до 0 перед видаленням.
- При використанні Поступових Оновлень використовуючи стандартну Політику Керування Podʼів (
OrderedReady
), можливе потрапляння в стан, що вимагає ручного втручання для виправлення.
Компоненти
Наведений нижче приклад демонструє компоненти StatefulSet.
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # повинно відповідати .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # типово 1
minReadySeconds: 10 # типово 0
template:
metadata:
labels:
app: nginx # повинно відповідати .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.24
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
Примітка:
Цей приклад використовує режим доступуReadWriteOnce
, для спрощення. Для
промислового використання проєкт Kubernetes рекомендує використовувати режим доступу
ReadWriteOncePod
.У вищенаведеному прикладі:
- Використовується Headless Service, з назвою
nginx
, для управління мережевим доменом. - StatefulSet, названий
web
, має Spec, який вказує на те, що буде запущено 3 репліки контейнера nginx в унікальних Podʼах. volumeClaimTemplates
буде забезпечувати стійке зберігання за допомогою PersistentVolumes, виділених PersistentVolume Provisioner.
Назва обʼєкта StatefulSet повинна бути дійсною DNS міткою.
Селектор Podʼів
Вам слід встановити поле .spec.selector
StatefulSet, яке збігається з міткам його
.spec.template.metadata.labels
. Нездатність вказати відповідний селектор Pod призведе до помилки перевірки під час створення StatefulSet.
Шаблони заявок на місце для зберігання
Ви можете встановити поле .spec.volumeClaimTemplates
, щоб створити PersistentVolumeClaim. Це забезпечить стійке зберігання для StatefulSet, якщо:
- Для заявки на том встановлено StorageClass, який налаштований на використання динамічного виділення, або
- Кластер вже містить PersistentVolume з правильним StorageClass та достатньою кількістю доступного місця для зберігання.
Мінімальний час готовності
Kubernetes v1.25 [stable]
.spec.minReadySeconds
є необовʼязковим полем, яке вказує мінімальну кількість секунд, протягом яких новий створений Pod повинен працювати та бути готовим, без виходу будь-яких його контейнерів з ладу, щоб вважатися доступним. Це використовується для перевірки прогресу розгортання при використанні стратегії Поступового Оновлення. Це поле станлартно дорівнює 0 (Pod вважатиметься доступним одразу після готовності). Дізнайтеся більше про те, коли
Pod вважається готовим, див. Проби Контейнера.
Ідентичність Podʼа
Podʼи StatefulSet мають унікальну ідентичність, яка складається з порядкового номера, стабільного мережевого ідентифікатора та стійкого сховища. Ця ідентичність залишається прикріпленою до Podʼа, незалежно від того, на якому вузлі він перепланований чи знову запланований.
Порядковий індекс
Для StatefulSet з N реплік кожному Podʼу в StatefulSet буде призначено ціле число, яке є унікальним у наборі. Стандартно Podʼам буде призначено порядкові номери від 0 до N-1. Контролер StatefulSet також додасть мітку Podʼа з цим індексом: apps.kubernetes.io/pod-index
.
Початковий порядковий номер
Kubernetes v1.31 [stable]
(стандартно увімкнено: true).spec.ordinals
— це необовʼязкове поле, яке дозволяє налаштувати цілочисельні порядкові номери, призначені кожному Pod. Стандартно воно встановлено в nil
. В межах цього поля ви можете налаштувати наступні параметри:
.spec.ordinals.start
: Якщо встановлено поле.spec.ordinals.start
, Podʼам будуть призначені порядкові номери від.spec.ordinals.start
до.spec.ordinals.start + .spec.replicas - 1
.
Стабільний мережевий ідентифікатор
Кожен Pod в StatefulSet виводить назву свого хосту з імені StatefulSet та порядкового номера Podʼа. Шаблон для створеного імені хосту має вигляд $(імʼя statefulset)-$(порядковий номер)
. У вищезазначеному прикладі буде створено три Podʼа з іменами web-0,web-1,web-2
. StatefulSet може використовувати Headless Service
для управління доменом своїх Podʼів. Домен, яким управляє цей сервіс, має вигляд:
$(імʼя сервісу).$(простір імен).svc.cluster.local
, де "cluster.local" — це кластерний домен. При створенні кожного Podʼа він отримує відповідний DNS-піддомен, який має вигляд: $(імʼя Podʼа).$(головний домен сервісу)
, де головний сервіс визначається полем serviceName
в StatefulSet.
Залежно від того, як налаштований DNS у вашому кластері, ви можливо не зможете одразу знаходити DNS-імʼя для нового Podʼа. Це можливо, коли інші клієнти в кластері вже відправили запити на імʼя хосту Podʼа до його створення. Негативне кешування (зазвичай для DNS) означає, що результати попередніх невдалих пошуків запамʼятовуються та використовуються, навіть після того, як Pod вже працює, принаймні кілька секунд.
Якщо вам потрібно виявити Podʼи негайно після їх створення, у вас є кілька варіантів:
- Запитуйте API Kubernetes безпосередньо (наприклад, використовуючи режим спостереження), а не покладаючись на DNS-запити.
- Зменште час кешування в вашому постачальнику DNS Kubernetes (зазвичай це означає редагування ConfigMap для CoreDNS, який зараз кешує протягом 30 секунд).
Як зазначено в розділі Обмеження, ви відповідаєте за створення Headless Service, відповідального за мережевий ідентифікатор Podʼів.
Ось деякі приклади варіантів вибору кластерного домену, імені сервісу, імені StatefulSet та того, як це впливає на DNS-імена Podʼів StatefulSet.
Кластерний домен | Сервіс (ns/імʼя) | StatefulSet (ns/імʼя) | Домен StatefulSet | DNS Podʼа | Імʼя хоста Podʼа |
---|---|---|---|---|---|
cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} |
cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} |
kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} |
Стійке сховище
Для кожного вхідного запису volumeClaimTemplates
, визначеного в StatefulSet, кожен Pod отримує один PersistentVolumeClaim. У прикладі з nginx кожен Pod отримує один PersistentVolume з StorageClass my-storage-class
та 1 ГБ зарезервованого сховища. Якщо не вказано StorageClass, то використовуватиметься стандартний розмір сховища. Коли Pod переплановується на вузлі, його volumeMounts
монтує PersistentVolumes, повʼязані із його PersistentVolume Claims. Зазначте, що PersistentVolumes, повʼязані із PersistentVolume Claims Podʼів, не видаляються при видаленні Podʼів чи StatefulSet. Це слід робити вручну.
Мітка імені Podʼа
Коли StatefulSet контролер створює Pod, він додає мітку statefulset.kubernetes.io/pod-name
, яка дорівнює назві Podʼа. Ця мітка дозволяє прикріплювати Service до конкретного Podʼа в StatefulSet.
Мітка індексу Podʼа
Kubernetes v1.28 [beta]
Коли StatefulSet контролер створює Pod, новий Pod має мітку apps.kubernetes.io/pod-index
. Значення цієї мітки — це порядковий індекс Podʼа. Ця мітка дозволяє маршрутизувати трафік до певного індексу Podʼа, фільтрувати логи/метрики за допомогою мітки індексу Podʼа та інше. Зауважте, що feature gate PodIndexLabel
повинен бути увімкнений для цієї
функції, і стандартно він увімкнений.
Гарантії розгортання та масштабування
- Для StatefulSet із N реплік, при розгортанні Podʼи створюються послідовно, у порядку від {0..N-1}.
- При видаленні Podʼів вони закінчуються у зворотньому порядку, від {N-1..0}.
- Перед тим як застосувати масштабування до Podʼа, всі його попередники повинні бути запущені та готові.
- Перед тим як Pod буде припинено, всі його наступники повинні бути повністю зупинені.
StatefulSet не повинен вказувати pod.Spec.TerminationGracePeriodSeconds
рівним 0. Це практика небезпечна і настійно не рекомендується. Для отримання додаткової інформації, зверніться до примусового видалення Podʼів StatefulSet.
Коли створюється приклад nginx вище, три Podʼа будуть розгорнуті в порядку web-0, web-1, web-2. web-1 не буде розгорнуто, поки web-0 не буде запущений і готовий, і web-2 не буде розгорнуто, поки web-1 не буде запущений і готовий. Якщо web-0 виявиться несправним, після того, як web-1 стане запущеним і готовим, але до запуску web-2, web-2 не буде запущено, поки web-0 успішно перезапуститься і стане запущеним і готовим.
Якщо користувач масштабує розгорнутий приклад, застосовуючи патчи до StatefulSet так, так щоб replicas=1
, спочатку буде припинено web-2. web-1 не буде припинено, поки web-2 повністю не завершить свою роботу та буде видалено. Якщо web-0 виявиться невдалим після того, як web-2 вже був припинений і повністю завершено, але перед видаленням web-1, web-1 не буде припинено, поки web-0 не стане запущеним і готовим.
Політики управління Podʼами
StatefulSet дозволяє зменшити його гарантії послідовності, зберігаючи при цьому його гарантії унікальності та ідентичності за допомогою поля .spec.podManagementPolicy
.
Політика управління Podʼами "OrderedReady"
OrderedReady
є типовим значенням політики управління Podʼами для StatefulSet. Вона реалізує поведінку, описану вище.
Політика управління Podʼами "Parallel"
"Parallel" вказує контролеру StatefulSet запускати або припиняти всі Podʼи паралельно, і не чекати, поки Podʼи стануть запущеними та готовими або повністю припиняться перед запуском або видаленням іншого Podʼа. Ця опція впливає лише на поведінку операцій масштабування. Оновлення не підпадають під вплив.
Стратегії оновлення
Поле .spec.updateStrategy
обʼєкта StatefulSet дозволяє налаштовувати
та вимикати автоматизовані поетапні оновлення для контейнерів, міток, ресурсів (запити/обмеження) та анотацій для Podʼів у StatefulSet. Є два можливих значення:
OnDelete
- Коли поле
.spec.updateStrategy.type
StatefulSet встановлено вOnDelete
, контролер StatefulSet не буде автоматично оновлювати Podʼи в StatefulSet. Користувачам необхідно вручну видаляти Podʼи, щоб спричинити створення контролером нових Podʼів, які відображають зміни, внесені в.spec.template
StatefulSet. RollingUpdate
- Стратегія оновлення
RollingUpdate
реалізує автоматизовані, поточні оновлення для Podʼів у StatefulSet. Це значення є стандартною стратегією оновлення.
Поточні оновлення
Коли поле .spec.updateStrategy.type
StatefulSet встановлено на RollingUpdate
,
контролер StatefulSet буде видаляти та знову створювати кожен Pod у StatefulSet. Він буде продовжувати в тому ж порядку, як Podʼи завершують роботу (від найбільшого індексу до найменшого), оновлюючи кожен Pod по одному.
Панель управління Kubernetes чекає, доки оновлений Pod буде переведений в стан Running та Ready, перш ніж оновити його попередника. Якщо ви встановили .spec.minReadySeconds
(див. Мінімальна кількість секунд готовності), панель управління також чекає вказану кількість секунд після того, як Pod стане готовим, перш ніж перейти далі.
Поточні оновлення частинами
Стратегію оновлення RollingUpdate
можна поділити на розділи, вказавши .spec.updateStrategy.rollingUpdate.partition
. Якщо вказано розділ, всі Podʼи з індексом, який більший або рівний розділу, будуть оновлені при оновленні .spec.template
StatefulSet. Усі Podʼи з індексом, який менший за розділ, не будуть оновлені та, навіть якщо вони будуть видалені, вони будуть відновлені на попередню версію. Якщо .spec.updateStrategy.rollingUpdate.partition
StatefulSet більше, ніж .spec.replicas
, оновлення .spec.template
не буде розповсюджуватися на його Podʼи. У більшості випадків вам не знадобиться використовувати розподіл, але вони корисні, якщо ви хочете розгортати оновлення, робити канаркові оновлення або виконати поетапне оновлення.
Максимальна кількість недоступних Podʼів
Kubernetes v1.24 [alpha]
Ви можете контролювати максимальну кількість Podʼів, які можуть бути недоступні під час оновлення, вказавши поле .spec.updateStrategy.rollingUpdate.maxUnavailable
. Значення може бути абсолютним числом (наприклад, 5
) або відсотком від бажаних Podʼів (наприклад, 10%
). Абсолютне число обчислюється з відсоткового значення заокругленням вгору. Це поле не може бути 0. Стандартне значення — 1.
Це поле застосовується до всіх Podʼів у діапазоні від 0
до replicas - 1
. Якщо є будь-який недоступний Pod у діапазоні від 0
до replicas - 1
, він буде враховуватися в maxUnavailable
.
Примітка:
ПолеmaxUnavailable
знаходиться на етапі альфа-тестування і враховується тільки API-серверами, які працюють з увімкненою функціональною можливістю MaxUnavailableStatefulSet
Примусовий відкат
При використанні поступових оновлень зі стандартною політикою управління Podʼами (OrderedReady
), існує можливість потрапити в становище, яке вимагає ручного втручання для виправлення.
Якщо ви оновлюєте шаблон Podʼа до конфігурації, яка ніколи не стає в стан Running and Ready (наприклад, через поганий бінарний файл або помилку конфігурації на рівні застосунку), StatefulSet припинить розгортання і залишиться у стані очікування.
У цьому стані недостатньо повернути шаблон Podʼа до справної конфігурації. Через відомий дефект, StatefulSet продовжуватиме очікувати, доки неробочий Pod стане готовим (що ніколи не відбувається), перед тим як спробувати повернути його до робочої конфігурації.
Після повернення до шаблону вам також слід видалити будь-які Podʼи, які StatefulSet вже намагався запустити з поганою конфігурацією. Після цього StatefulSet почне перестворювати Podʼи, використовуючи відновлений шаблон.
Збереження PersistentVolumeClaim
Kubernetes v1.27 [beta]
Необовʼязкове поле .spec.persistentVolumeClaimRetentionPolicy
контролює, чи і як видаляються PVC під час життєвого циклу StatefulSet. Вам потрібно увімкнути функціональну можливість StatefulSetAutoDeletePVC
на сервері API та менеджері контролера, щоб використовувати це поле. Після активації ви можете налаштувати дві політики для кожного StatefulSet:
whenDeleted
- налаштовує поведінку зберігання тому, яке застосовується при видаленні StatefulSet
whenScaled
- налаштовує поведінку зберігання тому, яке застосовується при зменшенні кількості реплік у StatefulSet, наприклад, при масштабуванні вниз.
Для кожної політики, яку ви можете налаштувати, ви можете встановити значення Delete
або Retain
.
Delete
- PVC, створені за допомогою
volumeClaimTemplate
StatefulSet, видаляються для кожного Podʼа, який впливає на політику. З політикоюwhenDeleted
всі PVC відvolumeClaimTemplate
видаляються після того, як їх Podʼи були видалені. З політикоююwhenScaled
, лише PVC, що відповідають реплікам Podʼа, які зменшуються видаляються після того, як їх Podʼи були видалені. Retain
(стандартно)- PVC від
volumeClaimTemplate
не змінюються, коли їх Pod видаляється. Це поведінка до цієї нової функції.
Звертайте увагу, що ці політики застосовуються лише при вилученні Podʼів через видалення або масштабування StatefulSet. Наприклад, якщо Pod, повʼязаний із StatefulSet, зазнає відмови через відмову вузла, і панель управління створює замінний Pod, StatefulSet зберігає поточний PVC. Поточний том не піддається впливу, і кластер прикріплює його до вузла, де має запуститися новий Pod.
Станадртно для політик встановлено Retain
, відповідно до поведінки StatefulSet до цієї нової функції.
Ось приклад політики.
apiVersion: apps/v1
kind: StatefulSet
...
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain
whenScaled: Delete
...
Контролер StatefulSet додає посилання на власника до своїх PVC, які потім видаляються збирачем сміття після завершення Podʼа. Це дозволяє Podʼу чисто демонтувати всі томи перед видаленням PVC (і перед видаленням PV та обсягу, залежно від політики збереження). Коли ви встановлюєте whenDeleted
політику Delete
, посилання власника на екземпляр StatefulSet поміщається на всі PVC, повʼязані із цим StatefulSet.
Політика whenScaled
повинна видаляти PVC тільки при зменшенні розміру Podʼа, а не при видаленні Podʼа з іншої причини. Під час узгодження контролер StatefulSet порівнює очікувану кількість реплік із фактичними Podʼами, що присутні на кластері. Будь-який Pod StatefulSet, ідентифікатор якого більший за кількість реплік, засуджується та позначається для видалення. Якщо політика whenScaled
є Delete
, засуджені Podʼи спочатку встановлюються власниками для відповідних PVC зразків StatefulSet, перед видаленням Podʼа. Це призводить до того, що PVC видаляються збирачем сміття тільки після видалення таких Podʼів.
Це означає, що якщо контролер виходить з ладу і перезапускається, жоден Pod не буде видалено до того моменту, поки його посилання на власника не буде відповідно оновлено згідно з політикою. Якщо засуджений Pod видаляється примусово, коли контролер вимкнено, посилання на власника може бути або встановлене, або ні, залежно від того, коли відбулася аварія контролера. Для оновлення посилань на власника може знадобитися кілька циклів врегулювання, тому деякі засуджені Podʼи можуть мати встановлені посилання на власника, а інші — ні. З цієї причини ми рекомендуємо зачекати, поки контролер знову запуститься, що перевірить посилання на власника перед завершенням роботи Podʼів. Якщо це неможливо, оператор повинен перевірити посилання на власника на PVC, щоб забезпечити видалення очікуваних обʼєктів при примусовому видаленні Podʼів.
Репліки
.spec.replicas
— це необовʼязкове поле, яке вказує кількість бажаних Podʼів. Стандартно воно дорівнює 1.
Якщо ви масштабуєте Deployment вручну, наприклад, через kubectl scale statefulset statefulset --replicas=X
, а потім оновлюєте цей StatefulSet на основі маніфесту (наприклад, за допомогою kubectl apply -f statefulset.yaml
), то застосування цього маніфесту перезапише попереднє ручне масштабування.
Якщо HorizontalPodAutoscaler (або будь-який подібний API для горизонтального масштабування) керує масштабуванням StatefulSet, не встановлюйте .spec.replicas
. Замість цього дозвольте панелі управління Kubernetes автоматично керувати полем .spec.replicas
.
Що далі
- Дізнайтеся про Podʼи.
- Дізнайтеся, як використовувати StatefulSets
- Спробуйте приклад розгортання stateful застосунків.
- Спробуйте приклад розгортання Cassandra з Stateful Sets.
- Спробуйте приклад запуску реплікованого stateful застосунку.
- Дізнайтеся, як масштабувати StatefulSet.
- Дізнайтеся, що включає в себе видалення StatefulSet.
- Дізнайтеся, як налаштувати Pod для використання тома для зберігання.
- Дізнайтеся, як налаштувати Pod для використання PersistentVolume для зберігання.
StatefulSet
є ресурсом верхнього рівня в API REST Kubernetes. Ознайомтесь з визначеням обʼєкта StatefulSet для розуміння API.- Дізнайтеся про PodDisruptionBudget та як його можна використовувати для управління доступністю застосунків під час відключень.