Керування навантаженням
Kubernetes надає кілька вбудованих API для декларативного керування вашими робочими навантаженнями та їх компонентами.
У кінцевому підсумку ваші застосунки працюють як контейнери всередині Podʼів; однак керувати окремими Podʼами вимагало б багато зусиль. Наприклад, якщо Pod зазнає збою, ви, ймовірно, захочете запустити новий Pod для його заміни. Kubernetes може зробити це за вас.
Ви використовуєте API Kubernetes для створення робочого обʼєкта, який представляє вищий рівень абстракції, ніж Pod, а потім Kubernetes control plane автоматично керує обʼєктами Pod від вашого імені, відповідно до специфікації обʼєкта робочого навантаження, яку ви визначили.
Вбудовані API для керування робочими навантаженнями:
Deployment (і, опосередковано, ReplicaSet), найпоширеніший спосіб запуску застосунку у вашому кластері. Deployment є хорошим вибором для керування робочим навантаженням, яке не зберігає стану, де будь-який Pod у Deployment може бути замінений, якщо це потрібно. (Deployments є заміною застарілого API ReplicationController).
StatefulSet дозволяє вам керувати одним або кількома Pod, які виконують один і той же код застосунку, де Pod мають унікальну ідентичність. Це відрізняється від Deployment, де очікується, що Pod будуть взаємозамінними. Найпоширеніше використання StatefulSet полягає в тому, щоб забезпечити звʼязок між Pod та їх постійним сховищем. Наприклад, ви можете запустити StatefulSet, який асоціює кожен Pod з PersistentVolume. Якщо один з Pod у StatefulSet зазнає збою, Kubernetes створює новий Pod, який підключений до того ж PersistentVolume.
DemonSet визначає Podʼи, які надають можливості, що є локальними для конкретного вузла; наприклад, драйвер, який дозволяє контейнерам на цьому вузлі отримувати доступ до системи сховища. Ви використовуєте DemonSet, коли драйвер або інша служба рівня вузла має працювати на вузлі, де вона корисна. Кожен Pod в DemonSet виконує роль, схожу на системний демон на класичному сервері Unix/POSIX. DemonSet може бути фундаментальним для роботи вашого кластера, наприклад, як втулок мережі кластера, він може допомогти вам керувати вузлом, або надати додаткову поведінку, яка розширює платформу контейнерів, яку ви використовуєте. Ви можете запускати DemonSet (і їх Podʼи) на кожному вузлі вашого кластера, або лише на підмножині (наприклад, встановити драйвер прискорювача GPU лише на вузлах, де встановлено GPU).
Ви можете використовувати Job та / або CronJob для визначення завдань, які виконуються до завершення та зупиняються. Job представляє одноразове завдання, тоді як кожен CronJob повторюється згідно з розкладом.
Інші теми в цьому розділі:
1 - Deployment
Deployment керує набором екземплярів Podʼів та їх робочими навантаженнями, як правило, тими, що не зберігають стан.
Розгортання (Deployment) забезпечує декларативні оновлення для Podʼів та ReplicaSets.
Ви описуєте бажаний стан у Deployment, і Контролер Deployment змінює фактичний стан на бажаний стан з контрольованою швидкістю. Ви можете визначити Deployment для створення нових ReplicaSets або видалення існуючих Deployment та прийняття всіх їхніх ресурсів новими Deployment.
Примітка:
Не керуйте ReplicaSets, що належать Deployment. Розгляньте можливість створення тікета в основному репозиторії Kubernetes, якщо ваш випадок використання не врахований нижче.Сценарії використання
Наступні сценарії є типовими для Deployment:
Створення Deployment
Розглянемо приклад Deployment. Він створює ReplicaSet для запуску трьох Podʼів nginx
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
В цьому прикладі:
Створюється Deployment з назвоюnginx-deployment
, назва вказується в полі .metadata.name
. Ця назва буде основою для ReplicaSets та Podʼів які буде створено потім. Дивіться Написання Deployment Spec для отримання додаткових відомостей.
Deployment створює ReplicaSet, який створює три реплікованих Podʼи, кількість зазначено у полі .spec.replicas
.
Поле .spec.selector
визначає як створений ReplicaSet відшукує Podʼи для керування. В цьому випадку вибирається мітка, яка визначена в шаблоні Pod, app: nginx
. Однак можливі складніші правила вибору, якщо шаблон Pod задовольняє це правило.
Примітка:
Поле .spec.selector.matchLabels
є масивом пар {key,value}. Одна пара {key,value} у matchLabels
еквівалентна елементу matchExpressions
, де поле key
— "key", operator
— "In", а масив values
містить лише "value". Всі умови, як від matchLabels
, так і від matchExpressions
, повинні бути виконані для отримання збігу.Поле template
має наступні вкладені поля:
- Podʼи позначаються міткою
app: nginx
з поля .metadata.labels
. - Шаблон специфікації Podʼа, поле
.template.spec
, вказує на те, що Podʼи використовують один контейнер, nginx
, який використовує образ nginx
з Docker Hub версія якого – 1.14.2. - Створюється один контейнер, який отримує назву
nginx
, яка вказана в полі .spec.template.spec.containers[0].name
.
Перед тим, як почати, переконайтеся, що ваш кластер Kubernetes працює. Дотримуйтесь наведених нижче кроків для створення Deployment:
Створіть Deployment скориставшись командою:
kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
Виконайте kubectl get deployments
для перевірки створення Deployment.
Якщо Deployment все ще створюється, ви побачите вивід подібний цьому:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 0/3 0 0 1s
Коли ви досліджуєте Deploymentʼи у вашому кластері, показуються наступні поля:
NAME
— містить назву Deploymentʼів у просторі імен.READY
— показує скільки реплік застосунку доступно користувачам. Значення відповідає шаблону наявно/бажано.UP-TO-DATE
— показує кількість реплік, які були оновлені для досягнення бажаного стану.AVAILABLE
— показує скільки реплік доступно користувачам.AGE
— показує час впродовж якого застосунок працює.
Notice how the number of desired replicas is 3 according to .spec.replicas
field.
Для перевірки стану розгортання Deployment, виконайте kubectl rollout status deployment/nginx-deployment
.
Має бути подібний вивід:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
Запустіть kubectl get deployments
знов через кілька секунд. Має бути подібний вивід:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
Бачите, що Deployment створив три репліки, і всі репліки актуальні (вони містять останній шаблон Pod) та доступні.
Для перевірки ReplicaSet (rs
), створених Deployment, виконайте kubectl get rs
. Має бути подібний вивід:
NAME DESIRED CURRENT READY AGE
nginx-deployment-75675f5897 3 3 3 18s
Вивід ReplicaSet має наступні поля:
NAME
— перелік назв ReplicaSets в просторі імен.DESIRED
— показує бажану кількість реплік застосунку, яку ви вказали при створенні Deployment. Це — бажаний стан.CURRENT
— показує поточну кількість реплік, що працюють на поточний момент.READY
— показує скільки реплік застосунку доступно користувачам.AGE
— показує час впродовж якого застосунок працює.
Зверніть увагу, що назва ReplicaSet завжди складається як [DEPLOYMENT-NAME]-[HASH]
. Ця назва буде основою для назв Podʼів, які буде створено потім.
Рядок HASH
є відповідником мітки pod-template-hash
в ReplicaSet.
Для ознайомлення з мітками, які було створено для кожного Pod, виконайте kubectl get pods --show-labels
.
Вивід буде схожим на це:
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=75675f5897
Створений ReplicaSet таким чином переконується, що в наявності є три Podʼи nginx
.
Примітка:
Ви маєте зазначити відповідний селектор та мітки шаблону Pod в Deployment (тут, app: nginx
).
Не використовуйте однакові мітки або селектори з іншими контролерами (включаючи інші Deployments та StatefulSets). Kubernetes не завадить вам це зробити, і якщо кілька контролерів мають селектори, що збігаються, ці контролери можуть конфліктувати та поводитись непередбачувано.
Мітка pod-template-hash
Увага:
Не змінюйте цю мітку.Мітка pod-template-hash
додається контролером Deployment до кожного ReplicaSet, який створює або бере під нагляд Deployment.
Ця мітка забезпечує унікальність дочірніх ReplicaSets Deploymentʼа. Вона генерується шляхом хешування PodTemplate
ReplicaSet, і отриманий хеш використовується як значення мітки, яке додається до селектора ReplicaSet, міток шаблону Podʼа, а також до всіх наявних Podʼів, які можуть бути у ReplicaSet.
Оновлення Deployment
Примітка:
Оновлення Deployment викликається тільки в тому випадку, якщо шаблон Deployment Podʼа (тобто .spec.template
) змінився, наприклад, якщо оновлено мітки чи образ контейнера шаблону. Інші оновлення, такі як масштабування Deployment, не викликають розгортання.Дотримуйтеся поданих нижче кроків для оновлення вашого Deployment:
Оновіть Podʼи nginx, щоб використовувати образ nginx:1.16.1
замість nginx:1.14.2
.
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1
або використовуйте наступну команду:
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
де deployment/nginx-deployment
вказує на Deployment, nginx
— на контейнер, який буде оновлено, і nginx:1.16.1
— на новий образ та його теґ.
Вивід буде схожий на:
deployment.apps/nginx-deployment image updated
Альтернативно, ви можете відредагувати розгортання і змінити .spec.template.spec.containers[0].image
з nginx:1.14.2
на nginx:1.16.1
:
kubectl edit deployment/nginx-deployment
Вивід буде схожий на:
deployment.apps/nginx-deployment edited
Щоб перевірити статус розгортання, виконайте:
kubectl rollout status deployment/nginx-deployment
Вивід буде схожий на це:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
або
deployment "nginx-deployment" successfully rolled out
Отримайте більше деталей про ваш оновлений Deployment:
Після успішного розгортання можна переглянути Deployment за допомогою kubectl get deployments
. Вивід буде схожий на це:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 36s
Виконайте kubectl get rs
, щоб перевірити, що Deployment оновив Podʼи, створивши новий ReplicaSet та масштабував його до 3 реплік, а також зменшивши розмір старого ReplicaSet до 0 реплік.
Вивід схожий на це:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
Виклик get pods
повинен тепер показати лише нові Podʼи:
Вивід буде схожий на це:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
Наступного разу, коли вам потрібно буде оновити ці Podʼи, вам достатньо буде знову оновити шаблон Podʼа в Deployment.
Deployment забезпечує, що тільки певна кількість Podʼів буде відключена під час оновлення. Типово це забезпечує, що принаймні 75% відомої кількості Podʼів будуть активними (максимум недоступних 25%).
Deployment також забезпечує, що тільки певна кількість Podʼів буде створена поверх відомої кількості Podʼів. Типово це забезпечує, що як максимум буде активно 125% відомої кількості Podʼів (25% максимального збільшення).
Наприклад, якщо ви ретельно досліджуєте Deployment вище, ви побачите, що спочатку було створено новий Pod, потім видалено старий Pod і створено ще один новий. Старі Podʼи не прибираються допоки не зʼявиться достатня кількість нових, і не створюються нові Podʼи допоки не буде прибрано достатню кількість старих. Deployment переконується, що принаймні 3 Podʼи доступні, і що вони не перевищують 4 Podʼа. У випадку розгортання з 4 репліками кількість Podʼів буде між 3 і 5.
Отримайте деталі вашого розгортання:
kubectl describe deployments
Вивід буде схожий на це:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
Тут ви бачите, що при створенні Deployment спочатку було створено ReplicaSet (nginx-deployment-2035384211) та масштабовано його до 3 реплік безпосередньо. Коли ви оновили Deployment, було створено новий ReplicaSet (nginx-deployment-1564180365) та масштабовано його до 1, потім Deployment дочекався, коли він запуститься. Потім було зменшено розмір старого ReplicaSet
до 2 і масштабовано новий ReplicaSet до 2, таким чином, щоб принаймні 3 Podʼа були доступні, і не більше 4 Podʼів в будь-який момент. Потім було продовжено масштабування нового та старого ReplicaSet, з однаковою стратегією поетапного оновлення. У кінці вас буде 3 доступні репліки в новому ReplicaSet, і старий ReplicaSet зменшений до 0.
Примітка:
Kubernetes не враховує Podʼи, які завершують роботу, коли розраховує кількість availableReplicas
, яка повинна бути між replicas - maxUnavailable
та replicas + maxSurge
. Внаслідок цього ви можете помітити, що під час розгортання є більше Podʼів, ніж очікувалося, і що загальні ресурси, які використовує Deployment, перевищують replicas + maxSurge
до того моменту, поки не мине terminationGracePeriodSeconds
для Podʼів, що завершують роботу.Rollover (або кілька одночасних оновлень)
Кожного разу, коли новий Deployment спостерігається контролером Deployment, ReplicaSet створюється для запуску необхідних Podʼів. Якщо Deployment оновлюється, поточний ReplicaSet, Podʼи якого збігаються з міткам з .spec.selector
, але не збігаються з .spec.template
, зменшується. Зрештою, новий ReplicaSet масштабується до .spec.replicas
, і всі старі ReplicaSets масштабуються в 0.
Якщо ви оновите Deployment під час вже поточного процесу розгортання, Deployment створить новий ReplicaSet відповідно до оновлення і почне масштабувати його, і розвертати ReplicaSet, який він раніше масштабував — він додасть його до списку старих ReplicaSets та почне зменшувати його.
Наприклад, припустимо, ви створюєте Deployment для створення 5 реплік nginx:1.14.2
, але потім оновлюєте Deployment для створення 5 реплік nginx:1.16.1
, коли вже створено тільки 3 репліки nginx:1.14.2
. У цьому випадку Deployment негайно починає
знищувати 3 Podʼи nginx:1.14.2
, які вже створено, і починає створювати
Podʼи nginx:1.16.1
. Deployment не чекає, доки буде створено 5 реплік nginx:1.14.2
, перш ніж змінити напрямок.
Оновлення селектора міток
Зазвичай не рекомендується вносити оновлення до селектора міток, і рекомендується планувати ваші селектори наперед. У будь-якому випадку, якщо вам потрібно виконати оновлення селектора міток, дійте з великою обережністю і переконайтеся, що ви розумієте всі його наслідки.
Примітка:
В API-версії apps/v1
селектор міток Deployment є незмінним після створення.- Додавання селектора вимагає оновлення міток шаблону Podʼа в специфікації Deployment новою міткою, інакше буде повернуто помилку перевірки. Ця зміна не є такою, що перетинається з наявними мітками, що означає, що новий селектор не вибирає ReplicaSets та Podʼи, створені за допомогою старого селектора, що призводить до залишення всіх старих ReplicaSets та створення нового ReplicaSet.
- Оновлення селектора змінює поточне значення ключа селектора — призводить до такого ж результату, як і додавання.
- Вилучення селектора вилучає наявний ключ з селектора Deployment — не вимагає будь-яких змін у мітках шаблону Podʼа. Наявні ReplicaSets не залишаються сиротами, і новий ReplicaSet не створюється, але слід зауважити, що вилучена мітка все ще існує в будь-яких наявних Podʼах і ReplicaSets.
Відкат Deployment
Іноді вам може знадобитися відкотити Deployment, наприклад, коли Deployment нестабільний, наприклад цикл постійних помилок. Типово, вся історія Deployment зберігається в системі, щоб ви могли відкотити його в будь-який час (ви можете змінити це, змінивши обмеження історії ревізій).
Примітка:
Ревізія Deployment створюється, коли спрацьовує Deployment. Це означає, що нова ревізія створюється тільки тоді, коли змінюється шаблон Podʼа Deployment (.spec.template
), наприклад, якщо ви оновлюєте мітки або образи контейнера в шаблоні. Інші оновлення, такі як масштабування Deployment, не створюють ревізію Deployment, щоб ви могли одночасно використовувати ручне або автоматичне масштабування. Це означає, що при відкаті до попередньої ревізії повертається лише частина шаблону Podʼа Deployment.Припустимо, ви припустилися помилки при оновленні Deployment, вказавши назву образу як nginx:1.161
замість nginx:1.16.1
:
kubectl set image deployment/nginx-deployment nginx=nginx:1.161
Вивід буде подібний до цього:
deployment.apps/nginx-deployment image updated
Розгортання застрягає. Ви можете перевірити це, перевіривши стан розгортання:
kubectl rollout status deployment/nginx-deployment
Вивід буде подібний до цього:
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Натисніть Ctrl-C, щоб зупинити спостереження за станом розгортання. Щодо деталей розгортання, що застрягло, читайте тут.
Ви бачите, що кількість старих реплік (додаючи кількість реплік від nginx-deployment-1564180365
та nginx-deployment-2035384211
) — 3, а кількість нових реплік (від nginx-deployment-3066724191
) — 1.
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 25s
nginx-deployment-2035384211 0 0 0 36s
nginx-deployment-3066724191 1 1 0 6s
При перегляді створених Podʼів ви бачите, що 1 Pod, створений новим ReplicaSet, застряг у циклі завантаження образу.
Вивід буде подібний до цього:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
nginx-deployment-1564180365-hysrc 1/1 Running 0 25s
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
Примітка:
Контролер Deployment автоматично зупиняє невдале розгортання та припиняє масштабування нового ReplicaSet. Це залежить від параметрів rollingUpdate (maxUnavailable
), які ви вказали. Стандартно Kubernetes встановлює значення 25%.Отримання опису розгортання:
kubectl describe deployment
Вивід буде подібний до цього:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.161
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created)
NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
Для виправлення цього вам потрібно відкотитиcm до попередньої ревізії Deployment, яка є стабільною.
Перевірка історії розгортання Deployment
Виконайте наведені нижче кроки, щоб перевірити історію розгортань:
По-перше, перевірте ревізії цього Deployment:
kubectl rollout history deployment/nginx-deployment
Вивід буде подібний до цього:
deployments "nginx-deployment"
REVISION CHANGE-CAUSE
1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
3 kubectl set image deployment/nginx-deployment nginx=nginx:1.161
CHANGE-CAUSE
копіюється з анотації Deployment kubernetes.io/change-cause
до його ревізій при створенні. Ви можете вказати повідомлення CHANGE-CAUSE
:
- Анотуючи Deployment командою
kubectl annotate deployment/nginx-deployment kubernetes.io/change-cause="image updated to 1.16.1"
- Ручним редагуванням маніфесту ресурсу.
Щоб переглянути деталі кожної ревізії, виконайте:
kubectl rollout history deployment/nginx-deployment --revision=2
Вивід буде подібний до цього:
deployments "nginx-deployment" revision 2
Labels: app=nginx
pod-template-hash=1159050644
Annotations: kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
QoS Tier:
cpu: BestEffort
memory: BestEffort
Environment Variables: <none>
No volumes.
Відкат до попередньої ревізії
Виконайте наведені нижче кроки, щоб відкотити Deployment з поточної версії на попередню версію, яка є версією 2.
Тепер ви вирішили скасувати поточне розгортання та повернутися до попередньої ревізії:
kubectl rollout undo deployment/nginx-deployment
Вивід буде подібний до цього:
deployment.apps/nginx-deployment rolled back
Замість цього ви можете виконати відкат до певної ревізії, вказавши її параметром --to-revision
:
kubectl rollout undo deployment/nginx-deployment --to-revision=2
Вивід буде подібний до цього:
deployment.apps/nginx-deployment rolled back
Для отримання додаткових відомостей про команди, повʼязані з розгортаннями, читайте kubectl rollout
.
Deployment тепер повернуто до попередньої стабільної ревізії. Як ви можете бачити, контролер розгортань генерує подію DeploymentRollback
щодо відкату до ревізії 2.
Перевірте, чи відкат був успішним і Deployment працює як очікується, виконавши:
kubectl get deployment nginx-deployment
Вивід буде подібний до цього:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 30m
Отримайте опис розгортання:
kubectl describe deployment nginx-deployment
Вивід подібний до цього:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=4
kubernetes.io/change-cause=kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.16.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1
Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2
Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Масштабування Deployment
Ви можете масштабувати Deployment за допомогою наступної команди:
kubectl scale deployment/nginx-deployment --replicas=10
Вивід буде подібний до цього:
deployment.apps/nginx-deployment scaled
Припускаючи, що горизонтальне автомасштабування Pod увімкнено у вашому кластері, ви можете налаштувати автомасштабування для вашого Deployment і вибрати мінімальну та максимальну кількість Podʼів, які ви хочете запустити на основі використання ЦП вашими поточними Podʼами.
kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80
Вивід буде подібний до цього:
deployment.apps/nginx-deployment scaled
Пропорційне масштабування
Deployment RollingUpdate підтримує виконання кількох версій застосунку одночасно. Коли ви або автомасштабування масштабуєте Deployment RollingUpdate, яке знаходиться в процесі розгортання (будь-то в процесі або призупинено), контролер Deployment балансує додаткові репліки в наявних активних ReplicaSets (ReplicaSets з Podʼами), щоб помʼякшити ризик. Це називається пропорційним масштабуванням.
Наприклад, ви використовуєте Deployment з 10 репліками, maxSurge=3 та maxUnavailable=2.
Переконайтеся, що в вашому Deployment працює 10 реплік.
Вивід буде подібний до цього:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 10 10 10 10 50s
Ви оновлюєте образ, який, як виявляється, неможливо знайти в межах кластера.
kubectl set image deployment/nginx-deployment nginx=nginx:sometag
Вивід подібний до цього:
deployment.apps/nginx-deployment image updated
Оновлення образу розпочинає новий rollout з ReplicaSet nginx-deployment-1989198191, але воно блокується через вимогу maxUnavailable
, яку ви вказали вище. Перевірте стан rollout:
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 5 5 0 9s
nginx-deployment-618515232 8 8 8 1m
Потім надходить новий запит на масштабування для Deployment. Автомасштабування збільшує репліки Deployment до 15. Контролер Deployment повинен вирішити, куди додати цих нових 5 реплік. Якби ви не використовували пропорційне масштабування, всі 5 реплік були б додані в новий ReplicaSet. З пропорційним масштабуванням ви розподіляєте додаткові репліки між всіма ReplicaSets. Більші частки йдуть в ReplicaSets з найбільшою кількістю реплік, а менші частки йдуть в ReplicaSets з меншою кількістю реплік. Залишки додаються до ReplicaSet з найбільшою кількістю реплік. ReplicaSets з нульовою кількістю реплік не масштабуються.
У нашому прикладі вище 3 репліки додаються до старого ReplicaSet, а 2 репліки — до нових ReplicaSet. Процес розгортання повинен остаточно перемістити всі репліки в новий ReplicaSet, за умови, що нові репліки стають справними. Для підтвердження цього виконайте:
Вивід буде подібний до цього:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
Статус rollout підтверджує, як репліки були додані до кожного ReplicaSet.
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Призупинення та відновлення розгортання Deployment
При оновленні Deployment або плануванні оновлення ви можете призупинити розгортання для цього Deployment перед тим, як запустити одне чи кілька оновлень. Коли ви готові застосувати зміни, ви відновлюєте розгортання для Deployment. Цей підхід дозволяє вам застосовувати кілька виправлень між призупиненням та відновленням без зайвих розгортань.
Наприклад, з Deployment, яке було створено:
Отримайте деталі Deployment:
Вивід буде подібний до цього:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
Отримайте стан розгортання:
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
Зробіть паузу за допомогою наступної команди:
kubectl rollout pause deployment/nginx-deployment
Вивід буде подібний до цього:
deployment.apps/nginx-deployment paused
Потім оновіть образ в Deployment:
kubectl set image deployment/nginx-deployment nginx=nginx:1.16.1
Вивід буде подібний до цього:
deployment.apps/nginx-deployment image updated
Зверніть увагу, що новий rollout не розпочався:
kubectl rollout history deployment/nginx-deployment
Вивід буде подібний до цього:
deployments "nginx"
REVISION CHANGE-CAUSE
1 <none>
Отримайте стан розгортання, щоб перевірити, що існуючий ReplicaSet не змінився:
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 2m
Ви можете робити стільки оновлень, скільки вам потрібно, наприклад, оновіть ресурси, які будуть використовуватися:
kubectl set resources deployment/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
Вивід буде подібний до цього:
deployment.apps/nginx-deployment resource requirements updated
Початковий стан Deployment перед призупиненням його rollout продовжить свою роботу, але нові оновлення до Deployment не матимуть жодного впливу, поки розгортання Deployment призупинено.
У кінці відновіть розгортання Deployment і спостерігайте, як новий ReplicaSet зʼявляється з усіма новими оновленнями:
kubectl rollout resume deployment/nginx-deployment
Вивід буде подібний до цього:
deployment.apps/nginx-deployment resumed
Спостерігайте за статусом розгортання, доки воно не завершиться.
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 2 2 2 2m
nginx-3926361531 2 2 0 6s
nginx-3926361531 2 2 1 18s
nginx-2142116321 1 2 2 2m
nginx-2142116321 1 2 2 2m
nginx-3926361531 3 2 1 18s
nginx-3926361531 3 2 1 18s
nginx-2142116321 1 1 1 2m
nginx-3926361531 3 3 1 18s
nginx-3926361531 3 3 2 19s
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 1 1 2m
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 20s
Отримайте статус останнього розгортання:
Вивід буде подібний до цього:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
Примітка:
Ви не можете відкотити призупинене розгортання Deployment, доки ви його не відновите.Статус Deployment
Deployment переходить через різні стани протягом свого життєвого циклу. Він може бути d процесі, коли виконується розгортання нового ReplicaSet, може бути завершеним або невдалим.
Deployment в процесі
Kubernetes позначає Deployment як в процесі (progressing), коли виконується одне з наступних завдань:
- Deployment створює новий ReplicaSet.
- Deployment масштабує вгору свій новий ReplicaSet.
- Deployment масштабує вниз свої старі ReplicaSet(s).
- Нові Podʼи стають готовими або доступними (готові принаймні MinReadySeconds).
Коли розгортання стає "в процесі" (progressing), контролер Deployment додає умову із наступними атрибутами до .status.conditions
Deployment:
type: Progressing
status: "True"
reason: NewReplicaSetCreated
| reason: FoundNewReplicaSet
| reason: ReplicaSetUpdated
Ви можете відстежувати хід розгортання за допомогою kubectl rollout status
.
Завершений Deployment
Kubernetes позначає Deployment як завершений (complete), коли він має наступні характеристики:
- Всі репліки, повʼязані з Deployment, були оновлені до останньої версії, яку ви вказали. Це означає, що всі запитані вами оновлення були завершені.
- Всі репліки, повʼязані з Deployment, доступні.
- Не працюють жодні старі репліки для Deployment.
Коли розгортання стає "завершеним" (complete), контролер Deployment встановлює умову із наступними атрибутами до .status.conditions
Deployment:
type: Progressing
status: "True"
reason: NewReplicaSetAvailable
Ця умова Progressing
буде зберігати значення статусу "True"
до тих пір, поки не буде запущено нове розгортання. Умова залишається незмінною навіть тоді, коли змінюється доступність реплік (це не впливає на умову Available
).
Ви можете перевірити, чи завершено Deployment, використовуючи kubectl rollout status
. Якщо Deployment завершився успішно, kubectl rollout status
повертає код виходу нуль (успіх).
kubectl rollout status deployment/nginx-deployment
Вивід буде схожий на наступний:
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
і код виходу з kubectl rollout
дорівнює 0 (успіх):
0
Невдалий Deployment
Ваш Deployment може застрягти під час намагання розгорнути свій новий ReplicaSet і ніколи не завершитися. Це може статися через наступне:
- Недостатні квоти
- Збій проб readiness
- Помилки підтягування образів
- Недостатні дозволи
- Обмеження лімітів
- Неправильна конфігурація середовища виконання застосунку
Один із способів виявлення цього стану — це вказати параметр граничного терміну в специфікації вашого розгортання: (.spec.progressDeadlineSeconds
). .spec.progressDeadlineSeconds
вказує кількість секунд, протягом яких контролер Deployment чекатиме, перш ніж вказати (в статусі Deployment), що прогрес розгортання зупинився.
Наступна команда kubectl
встановлює специфікацію з progressDeadlineSeconds
, щоб змусити контролер повідомляти про відсутність прогресу розгортання для Deployment після 10 хвилин:
kubectl patch deployment/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
Вивід буде схожий на наступний:
deployment.apps/nginx-deployment patched
Після того як граничний термін закінчився, контролер Deployment додає DeploymentCondition з наступними атрибутами до .status.conditions
Deployment:
type: Progressing
status: "False"
reason: ProgressDeadlineExceeded
Ця умова також може зазнати невдачі на ранніх етапах, і тоді вона встановлюється в значення статусу "False"
з причинами, такими як ReplicaSetCreateError
. Крім того, термін не враховується більше після завершення розгортання.
Дивіться Домовленості API Kubernetes для отримання додаткової інформації щодо умов статусу.
Примітка:
Kubernetes не вживає ніяких заходів стосовно до зупиненого Deployment, крім як звітувати про умову статусу з reason: ProgressDeadlineExceeded
. Оркестратори вищого рівня можуть використовувати це і відповідним чином діяти, наприклад, відкотити Deployment до його попередньої версії.Примітка:
Якщо ви призупините розгортання Deployment, Kubernetes не перевірятиме прогрес відносно вашого вказаного терміну. Ви можете безпечно призупинити розгортання Deployment в середині процесу розгортання та відновити його, не викликаючи
умову виходу за граничним терміном.Ви можете зіткнутися з тимчасовими помилками у Deployment, або через низький таймаут, який ви встановили, або через будь-який інший вид помилок, який можна розглядати як тимчасовий. Наприклад, допустімо, що у вас недостатні квоти. Якщо ви
опишете Deployment, ви помітите наступний розділ:
kubectl describe deployment nginx-deployment
Вивід буде схожий на наступний:
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
Якщо ви виконаєте kubectl get deployment nginx-deployment -o yaml
, статус Deployment схожий на це:
status:
availableReplicas: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
last
UpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 2
В решті решт, коли граничний термін прогресу Deployment буде перевищений, Kubernetes оновить статус і причину умови Progressing:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Ви можете вирішити проблему недостатньої квоти, зменшивши масштаб вашого Deployment, зменшивши масштаб інших контролерів, які ви можете виконувати, або збільшивши квоту у вашому просторі імен. Якщо ви задовольните умови квоти
і контролер Deployment завершить розгортання, ви побачите, що статус Deployment оновлюється успішною умовою (status: "True"
та reason: NewReplicaSetAvailable
).
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
type: Available
з status: "True"
означає, що у вас є мінімальна доступність Deployment. Мінімальна доступність визначається параметрами, вказаними в стратегії розгортання. type: Progressing
з status: "True"
означає, що ваш Deployment або знаходиться в середині розгортання і прогресує, або він успішно завершив свій прогрес, і доступна мінімально необхідна нова кількість реплік (див. причину умови для конкретики — у нашому випадку reason: NewReplicaSetAvailable
означає, що Deployment завершено).
Ви можете перевірити, чи Deployment не вдався за допомогою kubectl rollout status
. kubectl rollout status
повертає код виходу, відмінний від нуля, якщо Deployment перевищив граничний термін виконання.
kubectl rollout status deployment/nginx-deployment
Вивід буде схожий на наступний:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
і код виходу з kubectl rollout
дорівнює 1 (позначає помилку):
1
Операції з невдалим Deployment
Всі дії, які застосовуються до завершеного Deployment, також застосовуються до невдалого Deployment. Ви можете масштабувати його вгору/вниз, відкотити на попередню ревізію або навіть призупинити, якщо вам потрібно застосувати кілька корекцій у шаблоні Pod Deployment.
Політика очищення
Ви можете встановити поле .spec.revisionHistoryLimit
у Deployment, щоб вказати, скільки старих ReplicaSets для цього Deployment ви хочете зберегти. Решта буде видалена як сміття в фоновому режимі. Типове значення становить 10.
Примітка:
Якщо явно встановити це поле на 0, буде виконано очищення всієї історії вашого Deployment, і цей Deployment не зможе виконати відкат.Canary Deployment
Якщо ви хочете впроваджувати релізи для підмножини користувачів чи серверів, використовуючи Deployment, ви можете створити кілька Deployment, один для кожного релізу, слідуючи шаблону Canary, описаному в управлінні ресурсами.
Написання специфікації Deployment
Як і з усіма іншими конфігураціями Kubernetes, у Deployment потрібні поля .apiVersion
, .kind
і .metadata
. Для загальної інформації щодо роботи з файлами конфігурацій дивіться документи розгортання застосунків, налаштування контейнерів та використання kubectl для управління ресурсами.
Коли панель управління створює нові Podʼи для Deployment, .metadata.name
Deployment є частиною основи для найменування цих Podʼів. Назва Deployment повинна бути дійсним значенням DNS-піддомену, але це може призводити до неочікуваних результатів для імен хостів Podʼів. Для найкращої сумісності імʼя повинно відповідати більш обмеженим правилам DNS-мітки.
Deployment також потребує розділу .spec
.
Шаблон Pod
.spec.template
та .spec.selector
— єдині обовʼязкові поля .spec
.
.spec.template
— це шаблон Pod. Він має точно таку ж схему, як і Pod, за винятком того, що він вкладений і не має apiVersion
або kind
.
Крім обовʼязкових полів для Pod, шаблон Pod в Deployment повинен вказати відповідні мітки та відповідну політику перезапуску. Щодо міток, переконайтеся, що вони не перекриваються з іншими контролерами. Дивіться селектор.
Дозволяється лише .spec.template.spec.restartPolicy
, рівне Always
, що є стандартним значенням, якщо не вказано інше.
Репліки
.spec.replicas
— це необовʼязкове поле, яке вказує кількість бажаних Podʼів. Стандартно встановлено значення 1.
Якщо ви вручну масштабуєте Deployment, наприклад, через kubectl scale deployment deployment --replicas=X
, а потім ви оновлюєте цей Deployment на основі маніфесту (наприклад: виконуючи kubectl apply -f deployment.yaml
), то застосування цього маніфесту перезаписує ручне масштабування, яке ви раніше вказали.
Якщо HorizontalPodAutoscaler (або будь-який аналогічний API для горизонтального масштабування) відповідає за масштабування Deployment, не встановлюйте значення в .spec.replicas
.
Замість цього дозвольте панелі управління Kubernetes автоматично керувати полем .spec.replicas
.
Селектор
.spec.selector
— обовʼязкове поле, яке вказує селектор міток для Podʼів, які створює цей Deployment.
.spec.selector
повинно відповідати .spec.template.metadata.labels
, або воно буде відхилено API.
В API-версії apps/v1
.spec.selector
та .metadata.labels
не встановлюють стандартні значення на основі .spec.template.metadata.labels
, якщо вони не встановлені. Таким чином, їх слід встановлювати явно. Також слід зазначити, що .spec.selector
неможливо змінити після створення Deployment в apps/v1
.
Deployment може примусово завершити Podʼи, мітки яких відповідають селектору, якщо їх шаблон відмінний від .spec.template
або якщо загальна кількість таких Podʼів перевищує .spec.replicas
. Запускає нові Podʼи з .spec.template
, якщо кількість Podʼів менше, ніж бажана кількість.
Примітка:
Вам не слід створювати інші Podʼи, мітки яких відповідають цьому селектору, або безпосередньо, створюючи інший Deployment, або створюючи інший контролер, такий як ReplicaSet або ReplicationController. Якщо ви це зробите, перший Deployment вважатиме, що він створив ці інші Podʼи. Kubernetes не забороняє вам робити це.Якщо у вас є кілька контролерів із подібними селекторами, контролери будуть конфліктувати між собою і не будуть вести себе коректно.
Стратегія
.spec.strategy
визначає стратегію, якою замінюються старі Podʼи новими. .spec.strategy.type
може бути "Recreate" або "RollingUpdate". Типовим значенням є "RollingUpdate".
Перестворення Deployment
Всі поточні Podʼи примусово зупиняються та вилучаються, перш ніж створюються нові, коли .spec.strategy.type==Recreate
.
Примітка:
Це гарантує тільки завершення роботи Podʼи до створення для оновлення. Якщо ви оновлюєте Deployment, всі Podʼи старої ревізії будуть негайно завершені. Успішне видалення очікується перед створенням будь-якого Podʼи нової ревізії. Якщо ви вручну видаляєте Pod, життєвий цикл керується ReplicaSet, і заміщення буде створено негайно (навіть якщо старий Pod все ще перебуває в стані Terminating). Якщо вам потрібна гарантія "at most" для ваших Podʼів, вам слід розглянути використання
StatefulSet.
Оновлення Deployment
Deployment оновлює Podʼи в режимі поетапного оновлення, коли .spec.strategy.type==RollingUpdate
. Ви можете вказати maxUnavailable
та maxSurge
, щоб контролювати процес поетапного оновлення.
Максимально недоступний
.spec.strategy.rollingUpdate.maxUnavailable
— це необовʼязкове поле, яке вказує максимальну кількість Podʼів, які можуть бути недоступні під час процесу оновлення. Значення може бути абсолютним числом (наприклад, 5) або відсотком від бажаної кількості Podʼів (наприклад, 10%). Абсолютне число обчислюється з відсотком, округленим вниз. Значення не може бути 0, якщо MaxSurge
дорівнює 0. Станадартне значення — 25%.
Наприклад, якщо це значення встановлено на 30%, старий ReplicaSet може бути масштабований до 70% від бажаної кількості Podʼів негайно, коли починається поетапне оновлення. Як тільки нові Podʼи готові, старий ReplicaSet може бути ще більше масштабований вниз, а після цього може бути збільшено масштаб нового ReplicaSet, забезпечуючи, що загальна кількість Podʼів, доступних у будь-який час під час оновлення, становить принаймні 70% від бажаної кількості Podʼів.
Максимальний наплив
.spec.strategy.rollingUpdate.maxSurge
— це необовʼязкове поле, яке вказує максимальну кількість Podʼів, які можуть бути створені понад бажану кількість Podʼів. Значення може бути абсолютним числом (наприклад, 5) або відсотком від бажаної кількості Podʼів (наприклад, 10%). Абсолютне число обчислюється з відсотком, округленим вгору. Значення не може бути 0, якщо MaxUnavailable
дорівнює 0. Станадартне значення - 25%.
Наприклад, якщо це значення встановлено на 30%, новий ReplicaSet може бути масштабований негайно, коли починається поетапне оновлення, таким чином, щоб загальна кількість старих і нових Podʼів не перевищувала 130% від бажаної кількості Podʼів. Як тільки старі Podʼи буде вилучено, новий ReplicaSet може бути масштабований ще більше, забезпечуючи, що загальна кількість Podʼів, які працюють в будь-який час під час оновлення, становить найбільше 130% від бажаної кількості Podʼів.
Ось кілька прикладів оновлення Deployment за допомогою maxUnavailable
та maxSurge
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
Час Progress Deadline
.spec.progressDeadlineSeconds
— це необовʼязкове поле, яке вказує кількість секунд, протягом яких ви хочете чекати, поки ваш Deployment продовжиться, перш ніж система повідомить, що Deployment має помилку — відображається як умова з type: Progressing
, status: "False"
та reason: ProgressDeadlineExceeded
в статусі ресурсу. Контролер Deployment буде продовжувати
повторювати спроби Deployment. Станадартно це значення становить 600. У майбутньому, коли буде реалізовано автоматичний відкат, контролер Deployment відкотить Deployment, як тільки він виявить таку умову.
Якщо вказано це поле, воно повинно бути більше, ніж значення .spec.minReadySeconds
.
Час Min Ready
.spec.minReadySeconds
— це необовʼязкове поле, яке вказує мінімальну кількість секунд, протягом яких новий створений Pod повинен бути готовим, і жоден з його контейнерів не повинен виходити з ладу, щоб його вважалим доступним. Стандартно це значення становить 0 (Pod буде вважатися доступним, як тільки він буде готовий). Щоб дізнатися більше про те, коли Pod вважається готовим, див. Проби контейнерів.
Ліміт історії ревізій
Історія ревізій Deployment зберігається в ReplicaSets, якими він керує.
.spec.revisionHistoryLimit
— це необовʼязкове поле, яке вказує кількість старих ReplicaSets, які слід зберігати для можливості відкату. Ці старі ReplicaSets витрачають ресурси в etcd
та заважають виводу kubectl get rs
. Конфігурація кожного ревізії Deployment зберігається в його ReplicaSets; отже, після видалення старого ReplicaSet ви втрачаєте можливість відкотитися до цієї ревізії Deployment. Стандартно буде збережено 10 старих ReplicaSets, але ідеальне значення залежить від частоти та стабільності нових Deployment.
Зокрема, встановлення цього поля рівним нулю означає, що всі старі ReplicaSets з 0 реплік буде очищено. У цьому випадку нове розгортання Deployment не може бути скасовано, оскільки його історія ревізій очищена.
Пауза
.spec.paused
— це необовʼязкове булеве поле для призупинення та відновлення Deployment. Єдиний відмінок між призупиненим Deployment і тим, який не призупинений, полягає в тому, що будь-які зміни в PodTemplateSpec призупиненого Deployment не викличуть нових розгортань, поки він призупинений. Deployment типово не призупинений при створенні.
Що далі
2 - ReplicaSet
Призначення ReplicaSet полягає в забезпеченні стабільного набору реплік Podʼів, які працюють у будь-який момент часу. Зазвичай ви визначаєте Deployment та дозволяєте цьому Deployment автоматично керувати ReplicaSets.
Призначення ReplicaSet полягає в забезпеченні стабільного набору реплік Podʼів, які працюють у будь-який момент часу. Тож, ReplicaSet часто використовується для гарантування наявності вказаної кількості ідентичних Podʼів.
Як працює ReplicaSet
ReplicaSet визначається полями, включаючи селектор, який вказує, як ідентифікувати Podʼи, які він може отримати, кількість реплік, що вказує, скільки Podʼів він повинен підтримувати, і шаблон Podʼа, який вказує дані для нових Podʼів, які слід створити для відповідності критеріям кількості реплік. ReplicaSet виконує своє призначення, створюючи та видаляючи Podʼи за необхідності для досягнення їх бажаної кількості. Коли ReplicaSet потребує створення нових Podʼів, він використовує свій шаблон Podʼа.
ReplicaSet повʼязаний зі своїми Podʼами через поле metadata.ownerReferences Podʼа, яке вказує, яким ресурсом є власник поточного обʼєкта. Усі Podʼи, які отримав ReplicaSet, мають інформацію про ідентифікацію їхнього власного ReplicaSet у полі ownerReferences. Завдяки цим посиланням ReplicaSet знає про стан Podʼів, які він підтримує, і планує дії відповідно.
ReplicaSet визначає нові Podʼи для отримання за допомогою свого селектора. Якщо існує Pod, який не має OwnerReference або OwnerReference не є контролером, і він відповідає селектору ReplicaSet, його негайно отримає вказаний ReplicaSet.
Коли використовувати ReplicaSet
ReplicaSet забезпечує наявність вказаної кількості реплік Podʼів у будь-який момент часу. Проте Deployment є концепцією вищого рівня, яка управляє ReplicaSets і надає декларативні оновлення для Podʼів, разом із багатьма іншими корисними можливостями. Тому ми рекомендуємо використовувати Deployments замість безпосереднього використання ReplicaSets, якщо вам необхідне настроювання оркестрування оновлень або взагалі не потрібні оновлення.
Це означає, що вам можливо навіть не доведеться працювати з обʼєктами ReplicaSet: використовуйте Deployment та визначайте ваш застосунок у розділі spec.
Приклад
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# змініть кількість реплік відповідно до ваших потреб
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5
Зберігаючи цей маніфест у файл frontend.yaml
та застосовуючи його до кластера Kubernetes ви створите визначений обʼєкт ReplicaSet та Podʼи, якими він керує.
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
Ви можете переглянути створений ReplicaSet за допомогою команди:
І побачите що створено frontend:
NAME DESIRED CURRENT READY AGE
frontend 3 3 3 6s
Ви також можете перевірити стан ReplicaSet:
kubectl describe rs/frontend
Ви побачите вивід подібний до цього:
Name: frontend
Namespace: default
Selector: tier=frontend
Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: tier=frontend
Containers:
php-redis:
Image: us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 13s replicaset-controller Created pod: frontend-gbgfx
Normal SuccessfulCreate 13s replicaset-controller Created pod: frontend-rwz57
Normal SuccessfulCreate 13s replicaset-controller Created pod: frontend-wkl7w
І нарешті, ви можете перевірити, що Podʼи створені:
І побачите щось подібне до цього:
NAME READY STATUS RESTARTS AGE
frontend-gbgfx 1/1 Running 0 10m
frontend-rwz57 1/1 Running 0 10m
frontend-wkl7w 1/1 Running 0 10m
Ви можете також перевірити, що посилання на власника цих Podʼів вказує на ReplicaSet. Для цього отримайте деталі одного з Pod в форматі YAML:
kubectl get pods frontend-gbgfx -o yaml
Вихід буде схожий на цей, з інформацією ReplicaSet, встановленою в полі ownerReferences метаданих:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2024-02-28T22:30:44Z"
generateName: frontend-
labels:
tier: frontend
name: frontend-gbgfx
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: e129deca-f864-481b-bb16-b27abfd92292
...
Володіння Podʼами без шаблону
Хоча ви можете створювати прості Podʼи без проблем, настійно рекомендується переконатися, що ці прості Podʼи не мають міток, які відповідають селектору одного з ваших ReplicaSets. Причина цього полягає в тому, що ReplicaSet не обмежується володінням Podʼів, зазначених у його шаблоні — він може отримати інші Podʼи у спосіб, визначений в попередніх розділах.
Візьмемо приклад попереднього ReplicaSet для фронтенду та Podʼів, визначених у наступному маніфесті:
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0
Оскільки ці Podʼи не мають контролера (або будь-якого обʼєкта) як власника та відповідають селектору ReplicaSet для фронтенду, вони одразу перейдуть у його володіння.
Припустимо, ви створюєте Podʼи після того, як ReplicaSet для фронтенду буде розгорнуто та встановлено свої початкові репліки Podʼів для виконання вимог до кількості реплік:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Нові Podʼи будуть отримані ReplicaSet та негайно завершені, оскільки ReplicaSet буде мати більше, ніж його бажана кількість.
Отримання Podʼів:
Вивід покаже, що нові Podʼи або вже завершено, або в процесі завершення:
NAME READY STATUS RESTARTS AGE
frontend-b2zdv 1/1 Running 0 10m
frontend-vcmts 1/1 Running 0 10m
frontend-wtsmm 1/1 Running 0 10m
pod1 0/1 Terminating 0 1s
pod2 0/1 Terminating 0 1s
Якщо ви створите Podʼи спочатку:
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
А потім створите ReplicaSet таким чином:
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
Ви побачите, що ReplicaSet отримав Podʼи та створив нові лише відповідно до свого опису, доки кількість його нових Podʼів та оригінальних не відповідала його бажаній кількості. Якщо отримати Podʼи:
Вивід покаже, що:
NAME READY STATUS RESTARTS AGE
frontend-hmmj2 1/1 Running 0 9s
pod1 1/1 Running 0 36s
pod2 1/1 Running 0 36s
Таким чином, ReplicaSet може володіти неоднорідним набором Podʼів.
Написання маніфесту ReplicaSet
Як і усі інші обʼєкти API Kubernetes, ReplicaSet потребує полів apiVersion
, kind
та metadata
. Для ReplicaSet kind
завжди є ReplicaSet.
Коли панель управління створює нові Podʼи для ReplicaSet, .metadata.name
ReplicaSet є частиною основи для найменування цих Podʼів. Назва ReplicaSet повинна бути дійсним значенням DNS-піддомену, але це може призвести до неочікуваних результатів для імен хостів Podʼа. Для найкращої сумісності назва має відповідати більш обмеженим правилам для DNS-мітки.
ReplicaSet також потребує розділу .spec
.
Шаблон Podʼа
.spec.template
— це шаблон Podʼа, який також повинен мати встановлені мітки. У нашому прикладі frontend.yaml
ми мали одну мітку: tier: frontend
. Будьте обережні, щоб селектори не перекривалися з селекторами інших контролерів, інакше вони можуть намагатися взяти контроль над Podʼом.
Для політики перезапуску шаблону restart policy, .spec.template.spec.restartPolicy
, є допустимим тільки значення Always
, яке є стандартним значенням.
Селектор Podʼа
Поле .spec.selector
є селектором міток. Як обговорювалося раніше, це мітки, які використовуються для ідентифікації потенційних Podʼів для володіння. У нашому прикладі frontend.yaml
селектор був:
matchLabels:
tier: frontend
У ReplicaSet .spec.template.metadata.labels
має відповідати spec.selector
, інакше він буде відхилений API.
Примітка:
Для 2 ReplicaSets, які вказують на однаковий .spec.selector
, але різні .spec.template.metadata.labels
та .spec.template.spec
поля, кожен ReplicaSet ігнорує
Podʼи, створені іншим ReplicaSet.Репліки
Ви можете вказати, скільки Podʼів мають виконуватись одночасно, встановивши значення .spec.replicas
. ReplicaSet буде створювати/видаляти свої Podʼи щоб кількість Podʼів відповідала цьому числу. Якщо ви не вказали .spec.Podʼа
, то типово значення дорівнює 1.
Робота з ReplicaSets
Видалення ReplicaSet та його Podʼів
Щоб видалити ReplicaSet і всі його Podʼи, використовуйте kubectl delete
. Збирач сміття Garbage collector автоматично видаляє всі
залежні Podʼи.
При використанні REST API або бібліотеки client-go
, вам потрібно встановити propagationPolicy
в Background
або Foreground
в опції -d
. Наприклад:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
-H "Content-Type: application/json"
Видалення лише ReplicaSet
Ви можете видалити ReplicaSet, не впливаючи на його Podʼи за допомогою
kubectl delete
з опцією --cascade=orphan
. При використанні REST API або бібліотеки client-go
, вам потрібно встановити propagationPolicy
в Orphan
. Наприклад:
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
Після видалення оригіналу ви можете створити новий ReplicaSet для заміни. До тих пір поки старий та новий .spec.selector
однакові, новий прийме старі Podʼи. Однак він не буде намагатися повʼязувати наявні Podʼи з новим, відмінним шаблоном Podʼа. Для оновлення Podʼів до нової специфікації у контрольований спосіб використовуйте Deployment, оскільки ReplicaSets безпосередньо не підтримують rolling update.
Ізолювання Podʼів від ReplicaSet
Ви можете видалити Podʼи з ReplicaSet, змінивши їх мітки. Цей метод може бути використаний для вилучення Podʼів з обслуговування з метою налагодження, відновлення даних і т.д. Podʼи, які вилучаються цим способом, будуть автоматично замінені (за умови, що кількість реплік також не змінюється).
Масштабування ReplicaSet
ReplicaSet можна легко масштабувати вгору або вниз, просто оновивши поле .spec.replicas
. Контролер ReplicaSet забезпечує, що бажана кількість Podʼів з відповідним селектором міток доступна та працює.
При зменшенні масштабу ReplicaSet контролер ReplicaSet вибирає Podʼи для видалення, сортуючи доступні Podʼи, щоб визначити, які Podʼи видаляти в першу чергу, використовуючи наступний загальний алгоритм:
- Перш за все прибираються Podʼи, що перебувають в очікуванні.
- Якщо встановлено анотацію
controller.kubernetes.io/pod-deletion-cost
, то Pod із меншою вартістю буде видалено першим. - Podʼи на вузлах з більшою кількістю реплік йдуть перед Podʼами на вузлах з меншою кількістю реплік.
- Якщо часи створення Podʼів відрізняються, то Pod, створений недавно, йде перед старішим Podʼом (часи створення розділені на цілочисельний логарифмічний масштаб)
Якщо все вище вказане збігається, вибір випадковий.
Вартість видалення Podʼа
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.22 [beta]
За допомогою анотації controller.kubernetes.io/pod-deletion-cost
користувачі можуть встановити вподобання щодо порядку видалення Podʼів під час зменшення масштабу ReplicaSet.
Анотація повинна бути встановлена на Podʼі, діапазон — [-2147483648, 2147483647]. Вона представляє вартість видалення Podʼа порівняно з іншими Podʼами, які належать тому ж ReplicaSet. Podʼи з меншою вартістю видалення видаляються першими на відміну Podʼами з більшою вартістю видалення.
Неявне значення для цієї анотації для Podʼів, які його не мають, — 0; допустимі відʼємні значення. Неприпустимі значення будуть відхилені API-сервером.
Ця функція є бета-версією та увімкнена типово. Ви можете вимкнути її, використовуючи функціональну можливість PodDeletionCost
як в kube-apiserver, так і в kube-controller-manager.
Примітка:
- Цей підхід використовується як найкраще, тому він не пропонує жодних гарантій щодо порядку видалення Podʼів.
- Користувачам слід уникати частого оновлення анотації, такого як оновлення її на основі значення метрики, оскільки це призведе до значного числа оновлень Podʼів на apiserver.
Приклад Використання
Різні Podʼи застосунку можуть мати різний рівень використання. При зменшенні масштабу застосунок може віддавати перевагу видаленню Podʼів з меншим використанням. Щоб уникнути частого оновлення Podʼів, застосунок повинен оновити controller.kubernetes.io/pod-deletion-cost
один раз перед зменшенням масштабу
(встановлення анотації в значення, пропорційне рівню використання Podʼа). Це працює, якщо сам застосунок контролює масштабування вниз; наприклад, драйвер розгортання Spark.
ReplicaSet як ціль горизонтального автомасштабування Podʼа
ReplicaSet також може бути ціллю для Горизонтального Автомасштабування Podʼа (HPA). Іншими словами, ReplicaSet може автоматично масштабуватися за допомогою HPA. Ось приклад HPA, який застосовується до ReplicaSet, створеному у попередньому прикладі.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
Збереження цього маніфесту в hpa-rs.yaml
та його застосування до кластера Kubernetes повинно створити визначене HPA, яке автоматично змінює масштаб цільового ReplicaSet залежно від використання ЦП реплікованими Podʼами.
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
Або ви можете використовувати команду kubectl autoscale
для досягнення того ж самого (і це простіше!)
kubectl autoscale rs frontend --max=10 --min=3 --cpu-percent=50
Альтернативи ReplicaSet
Deployment (рекомендовано)
Deployment
— це обʼєкт, який може володіти ReplicaSets і оновлювати їх та їхні Podʼи через декларативні оновлення на стороні сервера. Хоча ReplicaSets можуть використовуватися незалежно, на сьогодні вони головним чином використовуються Deployments як механізм для
оркестрування створення, видалення та оновлення Podʼів. Коли ви використовуєте Deployments, вам не потрібно турбуватися про керування ReplicaSets, які вони створюють. Deployments володіють і керують своїми ReplicaSets. Таким чином, рекомендується використовувати Deployments, коли вам потрібні ReplicaSets.
Чисті Podʼи
На відміну від випадку, коли користувач безпосередньо створює Podʼи, ReplicaSet замінює Podʼи, які видаляються або завершуються з будь-якої причини, такої як випадок відмови вузла чи розбирання вузла, таке як оновлення ядра. З цього приводу ми рекомендуємо використовувати ReplicaSet навіть якщо ваш застосунок вимагає лише одного Podʼа. Подібно до наглядача процесів, він наглядає за кількома Podʼами на різних вузлах замість окремих процесів на одному вузлі. ReplicaSet делегує перезапуск локальних контейнерів до агента на вузлі, такого як Kubelet.
Job
Використовуйте Job
замість ReplicaSet для Podʼів, які повинні завершитися самостійно (тобто пакетні завдання).
DaemonSet
Використовуйте DaemonSet
замість ReplicaSet для Podʼів, які надають функції на рівні машини, такі як моніторинг стану машини або реєстрація машини. Ці Podʼи мають термін служби, який повʼязаний з терміном служби машини: Pod повинен працювати на машині перед тим, як інші Podʼи почнуть роботу, і можуть бути безпечно завершені, коли машина готова до перезавантаження/вимкнення.
ReplicationController
ReplicaSets — є наступниками ReplicationControllers. Обидва служать тому ж самому призначенню та поводяться схоже, за винятком того, що ReplicationController не підтримує вимоги
вибору на основі множини, як описано в посібнику про мітки. Таким чином, ReplicaSets має перевагу над ReplicationControllers.
Що далі
3 - StatefulSets
StatefulSet — це обʼєкт робочого навантаження API, який використовується для управління застосунками зі збереженням стану. Він запускає групу Podʼів і зберігає стійку ідентичність для кожного з цих Podʼів. Це корисно для керування застосвунками, які потребують постійного сховища або стабільної, унікальної мережевої ідентичності.
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} |
Примітка:
Кластерний домен буде встановлено як
cluster.local
, якщо не буде
інших налаштувань.
Стійке сховище
Для кожного вхідного запису 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.32 [stable]
(стандартно увімкнено: true)
Коли StatefulSet контролер створює Pod, новий Pod має мітку apps.kubernetes.io/pod-index
. Значення цієї мітки — це порядковий індекс Podʼа. Ця мітка дозволяє спрямовувати трафік до певного індексу під, фільтрувати логи/метрику за допомогою мітки індексу podʼа тощо. Зауважте, що стандартно функціональна можливість PodIndexLabel
увімкнена і заблокована для цієї функції, для того, щоб вимкнути її, користувачам доведеться використовувати емуляцію сервера версії v1.31.
Гарантії розгортання та масштабування
- Для 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.32 [stable]
(стандартно увімкнено: true)
Необовʼязкове поле .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
StatefulSet
є ресурсом верхнього рівня в API REST Kubernetes. Ознайомтесь з визначеням обʼєкта
StatefulSet для розуміння API.- Дізнайтеся про PodDisruptionBudget та як його можна використовувати для управління доступністю застосунків під час відключень.
4 - DaemonSet
DaemonSet визначає Podʼи, які забезпечують локальноі засоби вузла. Це може бути фундаментально важливим для роботи вашого кластера, таким як інструмент-помічник мережі, або бути частиною застосунку.
DaemonSet переконується, що всі (або деякі) вузли запускають копію Podʼа. При додаванні вузлів до кластера, на них додаються Podʼи. При видаленні вузлів з кластера ці Podʼи видаляються. Видалення DaemonSet призведе до очищення створених ним Podʼів.
Деякі типові використання DaemonSet включають:
- запуск демона кластерного сховища на кожному вузлі
- запуск демона збору логів на кожному вузлі
- запуск демона моніторингу вузла на кожному вузлі
У простому випадку один DaemonSet, який охоплює всі вузли, може використовуватися для кожного типу демона. Складніше налаштування може використовувати кілька DaemonSet для одного типу демона, але з різними прапорцями, або різними запитами памʼяті та CPU для різних типів обладнання.
Створення специфікації DaemonSet
Створення DaemonSet
Ви можете описати DaemonSet у файлі YAML. Наприклад, файл daemonset.yaml
нижче описує DaemonSet, який запускає Docker-образ fluentd-elasticsearch:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# ці tolerations дозволяють запускати DaemonSet на вузлах панелі управління
# видаліть їх, якщо ваші вузли панелі управління не повинні запускати Podʼи
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
# можливо, бажано встановити високий пріоритетний клас, щоб забезпечити, що Podʼи DaemonSetʼу
# витіснятимуть Podʼи, що виконуються
# priorityClassName: important
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
Створіть DaemonSet на основі файлу YAML:
kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml
Обовʼязкові поля
Як і з будь-якою іншою конфігурацією Kubernetes, DaemonSet потребує полів apiVersion
, kind
та metadata
. Для загальної інформації щодо роботи з файлами конфігурації, див. запуск stateless застосунків та управління обʼєктами за допомогою kubectl.
Назва обʼєкта DaemonSet повинна бути дійсним імʼям DNS-піддомену.
DaemonSet також потребує .spec
розділу.
Шаблон Podʼа
.spec.template
— одне з обовʼязкових полів в .spec
.
.spec.template
— це шаблон Podʼа. Він має ту саму схему, що і Pod, за винятком того, що він вкладений і не має apiVersion
або kind
.
Окрім обовʼязкових полів для Podʼа, шаблон Podʼа в DaemonSet повинен вказати відповідні мітки (див. вибір Podʼа).
Шаблон Pod в DaemonSet повинен мати RestartPolicy
рівну Always
або бути не вказаною, що типово рівнозначно Always
.
Селектор Podʼа
.spec.selector
— обовʼязкове поле в .spec
.
Поле .spec.selector
— це селектор Podʼа. Воно працює так само як і .spec.selector
в Job.
Ви повинні вказати селектор Podʼа, який відповідає міткам .spec.template
. Крім того, після створення DaemonSet, його .spec.selector
не може бути змінено. Зміна вибору Podʼа може призвести до навмисного залишення Podʼів сиротами, і це буде плутати користувачів.
.spec.selector
— це обʼєкт, що складається з двох полів:
matchLabels
- працює так само як і .spec.selector
у ReplicationController.matchExpressions
- дозволяє будувати складніші селектори, вказуючи ключ, список значень та оператор, який повʼязує ключ і значення.
Коли вказані обидва, результат є має мати збіг з обома.
.spec.selector
повинен відповідати .spec.template.metadata.labels
. Конфігурація з цими двома несумісними буде відхилена API.
Запуск Podʼів на вибраних вузлах
Якщо ви вказуєте .spec.template.spec.nodeSelector
, тоді контролер DaemonSet буде
створювати Podʼи на вузлах, які відповідають селектору вузла. Так само, якщо ви вказуєте .spec.template.spec.affinity
, тоді контролер DaemonSet буде створювати Podʼи на вузлах, які відповідають цій спорідненості вузла. Якщо ви не вказали жодного з них, контролер DaemonSet буде створювати Podʼи на всіх вузлах.
Як заплановані Daemon Podʼи
DaemonSet може бути використаний для того, щоб забезпечити, щоб всі придатні вузли запускали копію Podʼа. Контролер DaemonSet створює Pod для кожного придатного вузла та додає поле spec.affinity.nodeAffinity
Podʼа для відповідності цільовому хосту. Після створення Podʼа, зазвичай вступає в дію типовий планувальник і привʼязує Pod до цільового хосту, встановлюючи поле .spec.nodeName
. Якщо новий Pod не може поміститися на вузлі, типовий планувальник може здійснити перерозподіл (виселення) деяких наявних Podʼів на основі пріоритету нового Podʼа.
Примітка:
Якщо важливо, щоб Pod DaemonSet запускався на кожному вузлі, часто бажано встановити
.spec.template.spec.priorityClassName
DaemonSet на
PriorityClass з вищим пріоритетом, щоб переконатись, що таке виселення видбувається.
Користувач може вказати інший планувальник для Podʼів DaemonSet, встановивши поле .spec.template.spec.schedulerName
DaemonSet.
Оригінальна спорідненість вузла, вказана в полі .spec.template.spec.affinity.nodeAffinity
(якщо вказано), береться до уваги контролером DaemonSet при оцінці придатних вузлів, але замінюється на спорідненість вузла, що відповідає імені придатного вузла, на створеному Podʼі.
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
Taint та toleration
Контролер DaemonSet автоматично додає набір toleration до Podʼів DaemonSet:
Toleration для Podʼів DaemonSetКлюч толерантності | Ефект | Деталі |
---|
node.kubernetes.io/not-ready | NoExecute | Podʼи DaemonSet можуть бути заплановані на вузли, які не є справними або готовими приймати Podʼи. Будь-які Podʼи DaemonSet, які працюють на таких вузлах, не будуть виселені. |
node.kubernetes.io/unreachable | NoExecute | Podʼи DaemonSet можуть бути заплановані на вузли, які недоступні з контролера вузла. Будь-які Podʼи DaemonSet, які працюють на таких вузлах, не будуть виселені. |
node.kubernetes.io/disk-pressure | NoSchedule | Podʼи DaemonSet можуть бути заплановані на вузли із проблемами дискового тиску. |
node.kubernetes.io/memory-pressure | NoSchedule | Podʼи DaemonSet можуть бути заплановані на вузли із проблемами памʼяті. |
node.kubernetes.io/pid-pressure | NoSchedule | Podʼи DaemonSet можуть бути заплановані на вузли з проблемами процесів. |
node.kubernetes.io/unschedulable | NoSchedule | Podʼи DaemonSet можуть бути заплановані на вузли, які не можна планувати. |
node.kubernetes.io/network-unavailable | NoSchedule | Додається лише для Podʼів DaemonSet, які запитують мережу вузла, тобто Podʼи з spec.hostNetwork: true . Такі Podʼи DaemonSet можуть бути заплановані на вузли із недоступною мережею. |
Ви можете додавати свої толерантності до Podʼів DaemonSet, визначивши їх в шаблоні Podʼа DaemonSet.
Оскільки контролер DaemonSet автоматично встановлює толерантність node.kubernetes.io/unschedulable:NoSchedule
, Kubernetes може запускати Podʼи DaemonSet на вузлах, які відзначені як unschedulable.
Якщо ви використовуєте DaemonSet для надання важливої функції на рівні вузла, такої як мережа кластера, то корисно, що Kubernetes розміщує Podʼи DaemonSet на вузлах до того, як вони будуть готові. Наприклад, без цієї спеціальної толерантності ви можете опинитися в тупиковій ситуації, коли вузол не позначений як готовий, тому що мережевий втулок не працює там, і в той самий час мережевий втулок не працює на цьому вузлі, оскільки вузол ще не готовий.
Взаємодія з Daemon Podʼами
Деякі можливі шаблони для взаємодії з Podʼами у DaemonSet:
- Push: Podʼи в DaemonSet налаштовані надсилати оновлення до іншого сервісу, такого як база статистики. У них немає клієнтів.
- NodeIP та відомий порт: Podʼи в DaemonSet можуть використовувати
hostPort
, щоб їх можна було знайти за IP-адресою вузла. Клієнти певним чином знають стандартний список IP-адрес вузлів і порти. - DNS: Створіть headless сервіс за таким же вибором Podʼа, а потім виявіть DaemonSet, використовуючи ресурс
endpoints
або отримайте кілька записів A з DNS. - Сервіс: Створіть сервіс із тим самим вибором Podʼа та використовуйте сервіс для зʼєднання з демоном на випадковому вузлі. (Немає способу зʼєднатися напряму з конкретним Podʼом.)
Оновлення DaemonSet
Якщо мітки вузлів змінюються, DaemonSet негайно додає Podʼи на нові відповідні вузли та видаляє Podʼи на нових не відповідних вузлах.
Ви можете змінювати Podʼи, які створює DaemonSet. Проте Podʼи не дозволяють оновлювати всі поля. Крім того, контролер DaemonSet буде використовувати початковий шаблон при наступному створенні вузла (навіть з тим самим імʼям).
Ви можете видалити DaemonSet. Якщо ви вказали --cascade=orphan
з kubectl
, тоді Podʼи залишаться на вузлах. Якщо ви потім створите новий DaemonSet з тим самим селектором, новий DaemonSet прийме наявні Podʼи. Якщо потрібно замінити які-небудь Podʼи, DaemonSet їх замінює згідно з його updateStrategy
.
Ви можете виконати поетапне оновлення DaemonSet.
Альтернативи DaemonSet
Скрипти ініціалізації
Звичайно, можливо запускати процеси демонів, безпосередньо стартуючи їх на вузлі (наприклад, за допомогою init
, upstartd
або systemd
). Це абсолютно прийнятно. Однак існують кілька переваг запуску таких процесів через DaemonSet:
- Можливість моніторингу та управління логами для демонів так само як і для застосунків.
- Однакова мова конфігурації та інструменти (наприклад, шаблони Podʼа,
kubectl
) для демонів та застосунків. - Запуск демонів у контейнерах з обмеженням ресурсів підвищує ізоляцію між демонами та контейнерами застосунків. Однак це також можна досягти, запускаючи демонів у контейнері, але не в Podʼі.
Тільки Podʼи
Можливо створити Podʼи безпосередньо, вказуючи певний вузол для запуску. Проте DaemonSet замінює Podʼи, які видаляються або завершуються з будь-якої причини, такої як збій вузла або руйнівне обслуговування вузла, наприклад, оновлення ядра. З цієї причини слід використовувати DaemonSet замість створення тільки Podʼів.
Статичні Podʼи
Можливо створити Podʼи, записавши файл у певну теку, що спостерігається Kubelet. Їх називають статичними Podʼами. На відміну від DaemonSet, статичними Podʼами не можна управляти за допомогою kubectl
або інших клієнтів API Kubernetes. Статичні Podʼи не залежать від apiserver, що робить їх корисними в разі початкового налаштування кластера. Однак, статичні Podʼи можуть бути застарілими у майбутньому.
Deployments
DaemonSet схожий на Розгортання (Deployments) тим, що обидва створюють Podʼи, і ці Podʼи мають процеси, які не очікується, що завершаться (наприклад, вебсервери, сервери сховищ).
Використовуйте Розгортання для stateless служб, таких як фронтенди, де важливо збільшувати та зменшувати кількість реплік та розгортати оновлення. Використовуйте DaemonSet, коли важливо, щоб копія Podʼа завжди працювала на всіх або певних вузлах, якщо DaemonSet надає функціональність рівня вузла, яка дозволяє іншим Podʼам правильно працювати на цьому конкретному вузлі.
Наприклад, мережеві втулки часто включають компонент, який працює як DaemonSet. Цей компонент DaemonSet переконується, що вузол, де він працює, має справну кластерну мережу.
Що далі
5 - Job
Job – є одноразовим завданням, що виконується до моменту його завершення.
Завдання (Job) створює один або кілька Podʼів і буде продовжувати повторювати виконання Podʼів, доки не буде досягнуто вказану кількість успішних завершень. При успішному завершенні Podʼів завдання відстежує ці успішні завершення. Коли досягнута вказана кількість успішних завершень, завдання (тобто Job) завершується. Видалення завдання буде видаляти Podʼи, які воно створило. При призупиненні завдання буде видаляти активні Podʼи, доки завдання знову не буде відновлене.
У простому випадку можна створити один обʼєкт Job для надійного запуску одного Podʼа до завершення. Обʼєкт Job буде запускати новий Pod, якщо перший Pod зазнає невдачі або видаляється (наприклад, через відмову апаратного забезпечення вузла або перезавантаження вузла).
Також можна використовувати Job для запуску кількох Podʼів паралельно.
Якщо ви хочете запустити завдання (або одне завдання, або декілька паралельно) за розкладом, див. CronJob.
Запуск прикладу Job
Ось конфігурація прикладу Job. Тут обчислюється число π з точністю до 2000 знаків і виконується його вивід. Виконання зазвичай займає близько 10 секунд.
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
Ви можете запустити цей приклад за допомогою наступної команди:
kubectl apply -f https://kubernetes.io/examples/controllers/job.yaml
Вивід буде схожим на це:
job.batch/pi created
Перевірте статус Job за допомогою kubectl
:
Name: pi
Namespace: default
Selector: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
Labels: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name=pi
...
Annotations: batch.kubernetes.io/job-tracking: ""
Parallelism: 1
Completions: 1
Start Time: Mon, 02 Dec 2019 15:20:11 +0200
Completed At: Mon, 02 Dec 2019 15:21:16 +0200
Duration: 65s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: batch.kubernetes.io/controller-uid=c9948307-e56d-4b5d-8302-ae2d7b7da67c
batch.kubernetes.io/job-name=pi
Containers:
pi:
Image: perl:5.34.0
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 21s job-controller Created pod: pi-xf9p4
Normal Completed 18s job-controller Job completed
apiVersion: batch/v1
kind: Job
metadata:
annotations: batch.kubernetes.io/job-tracking: ""
...
creationTimestamp: "2022-11-10T17:53:53Z"
generation: 1
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
name: pi
namespace: default
resourceVersion: "4751"
uid: 204fb678-040b-497f-9266-35ffa8716d14
spec:
backoffLimit: 4
completionMode: NonIndexed
completions: 1
parallelism: 1
selector:
matchLabels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
suspend: false
template:
metadata:
creationTimestamp: null
labels:
batch.kubernetes.io/controller-uid: 863452e6-270d-420e-9b94-53a54146c223
batch.kubernetes.io/job-name: pi
spec:
containers:
- command:
- perl
- -Mbignum=bpi
- -wle
- print bpi(2000)
image: perl:5.34.0
imagePullPolicy: IfNotPresent
name: pi
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
restartPolicy: Never
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
status:
active: 1
ready: 0
startTime: "2022-11-10T17:53:57Z"
uncountedTerminatedPods: {}
Щоб переглянути завершені Podʼи Job, використовуйте kubectl get pods
.
Щоб вивести всі Podʼи, які належать Job у машинночитаній формі, ви можете використовувати таку команду:
pods=$(kubectl get pods --selector=batch.kubernetes.io/job-name=pi --output=jsonpath='{.items[*].metadata.name}')
echo $pods
Вивід буде схожим на це:
pi-5rwd7
Тут, селектор збігається з селектором, який використовується в Job. Параметр --output=jsonpath
зазначає вираз з назвою з кожного Pod зі списку.
Іншим варіантом є використання kubectl logs
для виводу логів з кожного Pod.
Вивід буде схожим на це:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Створення опису Job
Як і з будь-якою іншою конфігурацією Kubernetes, у Job мають бути вказані поля apiVersion
, kind
та metadata
.
При створенні панеллю управління нових Podʼів для Job, поле .metadata.name
Job є частиною основи для надання імен цим Podʼам. Імʼя Job повинно бути дійсним значенням DNS-піддомену, але це може призводити до неочікуваних результатів для імен хостів Podʼів. Для найкращої сумісності імʼя повинно відповідати більш обмеженим правилам для DNS-мітки. Навіть якщо імʼя є DNS-піддоменом, імʼя повинно бути не довше 63 символів.
Також у Job повинен бути розділ .spec
.
Мітки для Job
Мітки Job повинні мати префікс batch.kubernetes.io/
для job-name
та controller-uid
.
Шаблон Podʼа
.spec.template
— єдине обовʼязкове поле .spec
.
.spec.template
— це шаблон Podʼа. Він має точно таку ж схему, як Pod, окрім того, що він вкладений і не має apiVersion
чи kind
.
Окрім обовʼязкових полів для Podʼа , шаблон Podʼа в Job повинен вказати відповідні мітки (див. селектор Podʼа) та відповідну політику перезапуску.
Дозволяється лише RestartPolicy
, рівний Never
або OnFailure
.
Селектор Podʼа
Поле .spec.selector
є необовʼязковим. У майже всіх випадках ви не повинні його вказувати. Дивіться розділ вказування вашого власного селектора Podʼа.
Паралельне виконання для Jobs
Існують три основних типи завдань, які підходять для виконання в якості Job:
Непаралельні Jobs
- зазвичай запускається лише один Pod, якщо Pod не вдається.
- Job завершується, як тільки його Pod завершується успішно.
Паралельні Jobs із фіксованою кількістю завершень
- вкажіть ненульове позитивне значення для
.spec.completions
. - Job являє собою загальне завдання і завершується, коли є
.spec.completions
успішних Podʼів. - при використанні
.spec.completionMode="Indexed"
, кожен Pod отримує різний індекс у діапазоні від 0 до .spec.completions-1
.
Паралельні Jobs із чергою завдань
- не вказуйте
.spec.completions
, типово встановлюється .spec.parallelism
. - Podʼи повинні координувати серед себе або зовнішній сервіс для визначення над чим кожен з них має працювати. Наприклад, Pod може отримати набір з N елементів з черги завдань.
- кожен Pod може незалежно визначити, чи завершилися всі його партнери, і, таким чином, що весь Job завершений.
- коли будь-який Pod з Job завершується успішно, нові Podʼи не створюються.
- як тільки хоча б один Pod завершився успішно і всі Podʼи завершені, тоді Job завершується успішно.
- як тільки будь-який Pod завершився успішно, жоден інший Pod не повинен виконувати роботу для цього завдання чи записувати будь-який вивід. Вони всі мають бути в процесі завершення.
Для непаралельного Job ви можете залишити як .spec.completions
, так і .spec.parallelism
не встановленими. Коли обидва не встановлені, обидва типово встановлюються на 1.
Для Job із фіксованою кількістю завершень вам слід встановити .spec.completions
на кількість необхідних завершень. Ви можете встановити .spec.parallelism
чи залишити його не встановленим, і він буде встановлено типово на 1.
Для Job із чергою завдань ви повинні залишити .spec.completions
не встановленим і встановити .spec.parallelism
на не відʼємне ціле число.
За докладною інформацією про використання різних типів Job, див. розділ патерни Job.
Контроль паралелізму
Запитаний паралелізм (.spec.parallelism
) може бути встановлений на будь-яке не відʼємне значення. Якщо значення не вказано, стандартно воно дорівнює 1. Якщо вказано як 0, то Job ефективно призупинено до тих пір, поки воно не буде збільшене.
Фактична паралельність (кількість Podʼів, які працюють в будь-який момент) може бути більше чи менше, ніж запитаний паралелізм, з різних причин:
- Для Job із фіксованою кількістю завершень, фактична кількість Podʼів, які працюють паралельно, не буде перевищувати кількість залишених завершень. Значення
.spec.parallelism
більше чи менше ігнорується. - Для Job із чергою завдань, жоден новий Pod не запускається після успішного завершення будь-якого Podʼа — залишені Podʼи мають право завершити роботу.
- Якщо у контролера Job не було часу відреагувати.
- Якщо контролер Job не зміг створити Podʼи з будь-якої причини (нестача
ResourceQuota
, відсутність дозволу і т.д.), тоді може бути менше Podʼів, ніж запитано. - Контролер Job може обмежувати створення нових Podʼів через ексцесивні попередні відмови Podʼів у цьому ж Job.
- Коли Pod завершується відповідним чином, на його зупинку потрібен час.
Режим завершення
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.24 [stable]
Для завдань з фіксованою кількістю завершень — тобто завдань, які мають не нульове .spec.completions
— може бути встановлено режим завершення, який вказується в .spec.completionMode
:
NonIndexed
(стандартно): завдання вважається завершеним, коли є .spec.completions
успішно завершених Podʼів. Іншими словами, завершення кожного Podʼа гомологічне одне одному. Зверніть увагу, що завдання, у яких .spec.completions
дорівнює null, неявно є NonIndexed
.
Indexed
: Podʼи завдання отримують асоційований індекс завершення від 0 до .spec.completions-1
. Індекс доступний через чотири механізми:
- Анотація Podʼа
batch.kubernetes.io/job-completion-index
. - Мітка Podʼа
batch.kubernetes.io/job-completion-index
(для v1.28 і новіших). Зверніть увагу, що для використання цієї мітки механізм feature gate PodIndexLabel
повинен бути увімкнений, і він є типово увімкненим. - Як частина імені хоста Podʼа, за шаблоном
$(job-name)-$(index)
. Коли ви використовуєте Індексоване Завдання у поєднанні з Service, Podʼи всередині завдання можуть використовувати детерміністичні імена хостів для адресації одне одного через DNS. Докладні відомості щодо того, як налаштувати це, див. Завдання з комунікацією від Podʼа до Podʼа. - З контейнера завдання, в змінній середовища
JOB_COMPLETION_INDEX
.
Завдання вважається завершеним, коли є успішно завершений Pod для кожного індексу. Докладні відомості щодо того, як використовувати цей режим, див. Індексоване завдання для паралельної обробки зі статичним призначенням роботи.
Примітка:
Хоча це і рідко, може бути запущено більше одного Podʼа для одного і того ж індексу (з різних причин, таких як відмови вузла, перезапуски kubelet чи виселення Podʼа). У цьому випадку лише перший успішно завершений Pod буде враховуватися при підрахунку кількості завершень та оновленні статусу завдання. Інші Podʼи, які працюють чи завершили роботу для того ж самого індексу, будуть видалені контролером завдання, як тільки він їх виявлять.Обробка відмов Podʼа та контейнера
Контейнер у Podʼі може вийти з ладу з ряду причин, таких як завершення процесу з ненульовим кодом виходу або примусове припинення роботи контейнера через перевищення ліміту памʼяті та таке інше. Якщо це стається і .spec.template.spec.restartPolicy = "OnFailure"
, тоді Pod залишається на вузлі, але контейнер перезапускається. Отже, ваш застосунок повинен обробляти випадок, коли він
перезапускається локально, або вказувати .spec.template.spec.restartPolicy = "Never"
. Докладні відомості про restartPolicy
див. в розділі життєвий цикл Podʼа.
Весь Pod також може вийти з ладу з ряду причин, таких як коли Pod видаляється з вузла (вузол оновлюється, перезавантажується, видаляється тощо), або якщо контейнер Podʼа виходить з ладу і .spec.template.spec.restartPolicy = "Never"
. Коли Pod виходить з ладу, контролер завдання запускає новий Pod. Це означає, що ваш застосунок повинен обробляти випадок, коли він перезапускається у новому
Podʼі. Зокрема, він повинен обробляти тимчасові файли, блокування, неповний вивід та інше, викликане попередніми запусками.
Типово кожна відмова Podʼа враховується в ліміті .spec.backoffLimit
, див. політика відмови Podʼа. Однак ви можете налаштовувати обробку відмов Podʼа, встановлюючи [політику відмови Podʼа] (#pod-failure-policy) для завдання.
Додатково ви можете вирішити враховувати відмови Podʼа незалежно для кожного індексу в Індексованому Завданні, встановлюючи поле .spec.backoffLimitPerIndex
(докладні відомості див. ліміт затримки на індекс).
Зверніть увагу, що навіть якщо ви вказали .spec.parallelism = 1
і .spec.completions = 1
і .spec.template.spec.restartPolicy = "Never"
, той самий програмний код може іноді бути запущений двічі.
Якщо ви вказали як .spec.parallelism
, так і .spec.completions
більше ніж 1, то може бути запущено кілька Podʼів одночасно. Таким чином, ваші Podʼи також повинні бути стійкими до конкурентності.
Якщо ви вказуєте поле .spec.podFailurePolicy
, контролер Job не вважає Pod, який перебуває у стані завершення (Pod з встановленим полем .metadata.deletionTimestamp
), за помилку до того, як Pod стане термінальним (його .status.phase
є Failed
або Succeeded
). Однак контролер Job створює замінний Pod, як тільки стає очевидним, що Pod перебуває в процесі завершення. Після того як Pod завершиться, контролер Job оцінює .backoffLimit
і .podFailurePolicy
для відповідного Job, враховуючи тепер уже завершений Pod.
Якщо хоча б одна з цих вимог не виконана, контролер завдання рахує завершення Podʼа негайною відмовою, навіть якщо цей Pod пізніше завершить фазою "Succeeded"
.
Політика backoff відмови Podʼа
Є ситуації, коли ви хочете щоб завдання зазнало збою після певної кількості спроб
через логічну помилку в конфігурації тощо. Для цього встановіть .spec.backoffLimit
, щоб вказати кількість спроб перед тим, як вважати завдання таким, що не вдалось. Ліміт затримки стандартно встановлено на рівні 6. Помилкові Podʼи, повʼязані з завданням, відновлюються контролером завдань з експоненційною затримкою (10 с, 20 с, 40 с …) з верхнім обмеженням у шість хвилин.
Кількість спроб обчислюється двома способами:
- Кількість Podʼів з
.status.phase = "Failed"
. - При використанні
restartPolicy = "OnFailure"
кількість спроб у всіх контейнерах Podʼів з .status.phase
, що дорівнює Pending
або Running
.
Якщо хоча б один із розрахунків досягне значення .spec.backoffLimit
, завдання вважається невдалим.
Примітка:
Якщо ваше завдання має restartPolicy = "OnFailure"
, майте на увазі, що Pod, який виконує завдання, буде припинений, як тільки ліміт затримки завдання буде досягнуто. Це може ускладнити налагодження виконуваного завдання. Ми радимо встановлювати restartPolicy = "Never"
під час налагодження завдання або використовувати систему логування, щоб забезпечити, що вивід з невдалого завдання не буде втрачено випадково.Ліміт затримки для кожного індексу
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.29 [beta]
Примітка:
Ви можете налаштувати ліміт затримки для кожного індексу для завдання з
індексацією, якщо у вас увімкнено
функціональну можливість JobBackoffLimitPerIndex
в вашому кластері.
Коли ви запускаєте індексоване Завдання, ви можете вибрати обробку спроб для відмов Podʼа незалежно для кожного індексу. Для цього встановіть
.spec.backoffLimitPerIndex
, щоб вказати максимальну кількість невдалих спроб Podʼа
для кожного індексу.
Коли ліміт затримки для кожного індексу перевищується для певного індексу, Kubernetes вважає цей індекс невдалим і додає його до поля .status.failedIndexes
. Індекси, які виконались успішно, реєструються в полі .status.completedIndexes
, незалежно від того, чи ви встановили поле backoffLimitPerIndex
.
Зауважте, що невдалий індекс не перериває виконання інших індексів. Щойно всі індекси завершаться для завдання, в якому ви вказали ліміт затримки для кожного індексу, якщо хоча б один з цих індексів виявився невдалим, контролер завдань позначає загальне завдання як невдале, встановлюючи умову Failed
в статусі. Завдання отримує позначку "невдало", навіть якщо деякі, можливо, усі індекси були
оброблені успішно.
Ви також можете обмежити максимальну кількість позначених невдалих індексів, встановивши поле .spec.maxFailedIndexes
. Коли кількість невдалих індексів перевищує значення поля maxFailedIndexes
, контролер завдань запускає завершення всіх залишаються запущеними Podʼами для цього завдання. Щойно всі Podʼи будуть завершені, контролер завдань позначає все Завдання як невдале, встановлюючи умову Failed
в статусі Завдання.
Ось приклад маніфесту для завдання, яке визначає backoffLimitPerIndex
:
apiVersion: batch/v1
kind: Job
metadata:
name: job-backoff-limit-per-index-example
spec:
completions: 10
parallelism: 3
completionMode: Indexed # обов'язково для функціоналу
backoffLimitPerIndex: 1 # максимальна кількість невдач на один індекс
maxFailedIndexes: 5 # максимальна кількість невдалих індексів перед припиненням виконання Job
template:
spec:
restartPolicy: Never # обов'язково для функціоналу
containers:
- name: example
image: python
command: # Робота завершується невдачею, оскільки є принаймні один невдалий індекс
# (всі парні індекси невдаються), але всі індекси виконуються,
# оскільки не перевищено максимальну кількість невдалих індексів.
- python3
- -c
- |
import os, sys
print("Привіт, світ")
if int(os.environ.get("JOB_COMPLETION_INDEX")) % 2 == 0:
sys.exit(1)
У вищенаведеному прикладі контролер завдань дозволяє один перезапуск для кожного з індексів. Коли загальна кількість невдалих індексів перевищує 5, тоді все завдання припиняються.
Після завершення роботи стан завдання виглядає наступним чином:
kubectl get -o yaml job job-backoff-limit-per-index-example
status:
completedIndexes: 1,3,5,7,9
failedIndexes: 0,2,4,6,8
succeeded: 5 # 1 succeeded pod for each of 5 succeeded indexes
failed: 10 # 2 failed pods (1 retry) for each of 5 failed indexes
conditions:
- message: Job has failed indexes
reason: FailedIndexes
status: "True"
type: FailureTarget
- message: Job has failed indexes
reason: FailedIndexes
status: "True"
type: Failed
Контролер Job додає умову FailureTarget
до Job для запуску завершення та очищення Job. Коли всі Podʼи Job завершуються, контролер Job додає умову Failed
з тими ж значеннями для reason
і message
, що й у умови FailureTarget
. Для деталей дивіться Завершення Podʼів завдання.
Додатково ви можете використовувати ліміт затримки для кожного індексу разом з
політикою збоїв Podʼа. Коли використовується ліміт затримки для кожного індексу, доступний новій дії FailIndex
, який дозволяє вам уникати непотрібних повторів всередині індексу.
Політика збою Podʼа
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.31 [stable]
(стандартно увімкнено: true)
Політика збою Podʼа, визначена за допомогою поля .spec.podFailurePolicy
, дозволяє вашому кластеру обробляти відмови Podʼа на основі кодів виходу контейнера та умов Podʼа.
У деяких ситуаціях вам може знадобитися кращий контроль обробки відмов Podʼа, ніж контроль, який надає політика відмови Podʼа за допомогою затримки збою Podʼа, яка базується на .spec.backoffLimit
завдання. Ось деякі приклади використання:
- Для оптимізації витрат на виконання завдань, уникнення непотрібних перезапусків Podʼа, ви можете завершити завдання, як тільки один із його Podʼів відмовить із кодом виходу, що вказує на помилку програмного забезпечення.
- Щоб гарантувати, що ваше завдання завершиться, навіть якщо є розлади, ви можете ігнорувати відмови Podʼа, спричинені розладами (такими як випередження, виселення, ініційоване API або виселення на підставі маркування), щоб вони не враховувалися при досягненні
.spec.backoffLimit
ліміту спроб.
Ви можете налаштувати політику збою Podʼа в полі .spec.podFailurePolicy
, щоб відповідати вищенаведеним використанням. Ця політика може обробляти відмови Podʼа на основі кодів виходу контейнера та умов Podʼа.
Ось маніфест для завдання, яке визначає podFailurePolicy
:
apiVersion: batch/v1
kind: Job
metadata:
name: job-pod-failure-policy-example
spec:
completions: 12
parallelism: 3
template:
spec:
restartPolicy: Never
containers:
- name: main
image: docker.io/library/bash:5
command: ["bash"] # приклад команди, що емулює помилку, яка запускає дію FailJob
args:
- -c
- echo "Hello world!" && sleep 5 && exit 42
backoffLimit: 6
podFailurePolicy:
rules:
- action: FailJob
onExitCodes:
containerName: main # опціонально
operator: In # одне з: In, NotIn
values: [42]
- action: Ignore # одне з: Ignore, FailJob, Count
onPodConditions:
- type: DisruptionTarget # вказує на порушення роботи Podʼу
У вищенаведеному прикладі перше правило політики збою Podʼа вказує, що завдання слід позначити як невдале, якщо контейнер main
завершиться кодом виходу 42. Наступні правила стосуються саме контейнера main
:
- код виходу 0 означає, що контейнер виконався успішно
- код виходу 42 означає, що все завдання виконалося невдало
- будь-який інший код виходу вказує, що контейнер виконався невдало, і, отже, весь Pod буде створений заново, якщо загальна кількість перезапусків менше
backoffLimit
. Якщо backoffLimit
досягнуте, все завдання виконалося невдало.
Примітка:
Оскільки в шаблоні Podʼа вказано restartPolicy: Never
, kubelet не перезапускає контейнер main
в тому конкретному Podʼі.Друге правило політики збою Podʼа, що вказує дію Ignore
для невдалих Podʼів з умовою DisruptionTarget
, виключає Podʼи, які взяли участь в розладах, з хунок ліміту спроб .spec.backoffLimit
.
Примітка:
Якщо завдання виявилося невдалим, будь-то через політику збою Podʼа, чи через політику затримки збою Podʼа, і завдання виконується декількома Podʼами, Kubernetes завершує всі
Podʼи в цьому завданні, які все ще перебувають у статусах Pending або Running.Ось деякі вимоги та семантика API:
- якщо ви хочете використовувати поле
.spec.podFailurePolicy
для завдання Job, вам також слід визначити шаблон Podʼа цього завдання з .spec.restartPolicy
, встановленим на Never
. - правила політики збою Podʼа, які ви визначаєте у
spec.podFailurePolicy.rules
, оцінюються послідовно. Якщо одне з правил відповідає збою Podʼа, інші правила ігноруються. Якщо жодне правило не відповідає збою Podʼа, застосовується типова обробка. - ви можете бажати обмежити правило певним контейнером, вказавши його імʼя у
spec.podFailurePolicy.rules[*].onExitCodes.containerName
. Якщо не вказано, правило застосовується до всіх контейнерів. Якщо вказано, воно повинно відповідати імені одного з контейнерів або initContainer
у шаблоні Podʼа. - ви можете вказати дію, вживану при відповідності політиці збою Podʼа, у
spec.podFailurePolicy.rules[*].action
. Можливі значення:FailJob
: використовуйте це, щоб вказати, що завдання Podʼа має бути позначено як Failed та всі запущені Podʼи повинні бути завершені.Ignore
: використовуйте це, щоб вказати, що лічильник до .spec.backoffLimit
не повинен збільшуватися, і повинен бути створений замінюючий Pod.Count
: використовуйте це, щоб вказати, що Pod повинен бути оброблений типовим способом. Лічильник до .spec.backoffLimit
повинен збільшитися.FailIndex
: використовуйте цю дію разом із лімітом затримки на кожен індекс для уникнення непотрібних повторних спроб в межах індексу невдалого Podʼа.
Примітка:
Коли використовується
podFailurePolicy
, контролер завдань враховує лише Podʼи у фазі
Failed
. Podʼи з відміткою про видалення, які не знаходяться в термінальній фазі (
Failed
чи
Succeeded
), вважаються таким що примусово припиняють свою роботу. Це означає, що такі Podʼи зберігають
завершувачі відстеження доки не досягнуть термінальної фази. З Kubernetes 1.27 Kubelet переводить видалені Podʼи в термінальну фазу (див.:
Фаза Podʼа). Це забезпечує видалення завершувачів контролером Job.
Примітка:
Починаючи з Kubernetes v1.28, коли використовується політика збою Podʼа, контролер Job відтворює Podʼи, що припиняються примусово, лише тоді, коли ці Podʼи досягли термінальної фази
Failed
. Це подібно до політики заміщення Podʼа:
podReplacementPolicy: Failed
. Для отримання додаткової інформації див.
Політика заміщення Podʼа.
Коли ви використовуєте podFailurePolicy
, і Job зазнає невдачі через Pod, що відповідає правилу з дією FailJob
, контролер Job запускає процес завершення Job, додаючи умову FailureTarget
. Для деталей дивіться Завершення та очищення Job.
Політика успіху
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.31 [beta]
(стандартно увімкнено: true)
Примітка:
Ви можете налаштувати політику успіху лише для Індексованого Завдання, якщо у вас увімкнено
функціональну можливість JobSuccessPolicy
у вашому кластері.
При створенні Індексованого Завдання ви можете визначити, коли завдання може бути визнане успішним за допомогою .spec.successPolicy
, на основі успішних Podʼів.
Типово завдання вважається успішним, коли кількість успішних Podʼів дорівнює .spec.completions
. Існують ситуації, коли вам може знадобитися додатковий контроль для визначення завдання успішним:
- Під час виконання симуляцій з різними параметрами, вам можуть не знадобитися всі симуляції для успішного завершення загального завдання.
- При використанні шаблону лідер-робітник, успіх лідера визначає успіх чи невдачу завдання. Прикладами цього є фреймворки, такі як MPI та PyTorch тощо.
Ви можете налаштувати політику успіху у полі .spec.successPolicy
, щоб задовольнити вищезазначені випадки використання. Ця політика може керувати успіхом завдання на основі успішних Podʼів. Після того, як завдання відповідає політиці успіху, контролер завдань завершує залишкові Podʼи. Політика успіху визначається правилами. Кожне правило може мати одну з наступних форм:
- Коли ви вказуєте лише
succeededIndexes
, одразу після успішного завершення всіх індексів, вказаних у succeededIndexes
, контролер завдань позначає завдання як успішне. succeededIndexes
повинен бути списком інтервалів між 0 і .spec.completions-1
. - Коли ви вказуєте лише
succeededCount
, як тільки кількість успішних індексів досягне succeededCount
, контролер завдань позначає завдання як успішне. - Коли ви вказуєте як
succeededIndexes
, так і succeededCount
, як тільки кількість успішних індексів з підмножини індексів, вказаних у succeededIndexes
, досягне succeededCount
, контролер завдань позначає завдання як успішне.
Зверніть увагу, що коли ви вказуєте кілька правил у .spec.successPolicy.rules
, контролер завдань оцінює правила послідовно. Після того, як завдання задовольняє правило, контролер завдань ігнорує решту правил.
Ось приклад маніфеста для завдання із successPolicy
:
apiVersion: batch/v1
kind: Job
metadata:
name: job-success
spec:
parallelism: 10
completions: 10
completionMode: Indexed # Обовʼязково для іспішної політики
successPolicy:
rules:
- succeededIndexes: 0,2-3
succeededCount: 1
template:
spec:
containers:
- name: main
image: python
command: # З урахуванням того, що принаймні один із Podʼів з індексами 0, 2 та 3 успішно завершився,
# загальна задача вважатиметься успішною.
- python3
- -c
- |
import os, sys
if os.environ.get("JOB_COMPLETION_INDEX") == "2":
sys.exit(0)
else:
sys.exit(1)
restartPolicy: Never
У вищенаведеному прикладі були вказані як succeededIndexes
, так і succeededCount
. Тому контролер завдань позначить завдання як успішне і завершить залишкові Podʼи після успіху будь-яких зазначених індексів, 0, 2 або 3. Завдання, яке відповідає політиці успіху, отримує умову SuccessCriteriaMet
з причиною SuccessPolicy
. Після видалення залишкових Podʼів, завдання отримує стан Complete
.
Зверніть увагу, що succeededIndexes
представлено як інтервали, розділені дефісом. Номери перераховані у вигляді першого та останнього елементів серії, розділених дефісом.
Примітка:
Коли ви вказуєте як політику успіху, так і деякі політики завершення, такі як .spec.backoffLimit
і .spec.podFailurePolicy
, одного разу, коли завдання задовольняє будь-яку політику, контролер завдань дотримується політики завершення і ігнорує політику успіху.Завершення завдання та очищення
Коли завдання завершується, Podʼи більше не створюються, але Podʼи зазвичай також не видаляються. Тримання їх допомагає переглядати логи завершених Podʼів для перевірки наявності помилок, попереджень чи іншого діагностичного виводу. Обʼєкт завдання також залишається після завершення, щоб ви могли переглядати його статус. Користувачу слід видаляти старі завдання після перегляду їх статусу. Видаліть завдання за допомогою kubectl
(наприклад, kubectl delete jobs/pi
або kubectl delete -f ./job.yaml
). Коли ви видаляєте завдання за допомогою kubectl
, всі його створені Podʼи також видаляються.
Стандартно завдання буде виконуватися без перерви, поки Pod не вийде з ладу (restartPolicy=Never
) або контейнер не вийде з ладу з помилкою (restartPolicy=OnFailure
), після чого завдання дотримується .spec.backoffLimit
, описаного вище. Як тільки досягнуто .spec.backoffLimit
, завдання буде позначене як невдале, і будь-які запущені Podʼи будуть завершені.
Іншим способом завершити завдання є встановлення граничного терміну виконання. Це робиться шляхом встановлення поля .spec.activeDeadlineSeconds
завдання кількості секунд. activeDeadlineSeconds
застосовується до тривалості завдання, незалежно від кількості створених Podʼів. Як тільки Job досягає activeDeadlineSeconds
, всі його запущені Podʼи завершуються, і статус завдання стане type: Failed
з reason: DeadlineExceeded
.
Зауважте, що .spec.activeDeadlineSeconds
Job має пріоритет перед його .spec.backoffLimit
. Отже, завдання, яке повторює один або кілька невдал х Podʼів, не розпочне розгортання додаткових Podʼів, якщо activeDeadlineSeconds
вже досягнуто, навіть якщо backoffLimit
не досягнуто. Приклад:
apiVersion: batch/v1 kind: Job
metadata:
name: pi-with-timeout
Стандартноimit: 5
activeDeadlineSeconds: 100
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
Зверніть увагу, що як саме специфікація Job, так і специфікація шаблону Pod у межах завдання мають поле activeDeadlineSeconds
. Переконайтеся, що ви встановлюєте це поле на відповідному рівні.
Памʼятайте, що restartPolicy
застосовується до Podʼа, а не до самого завдання: автоматичного перезапуску завдання не відбудеться, якщо статус завдання type: Failed
. Іншими словами, механізми завершення завдання, активовані за допомогою .spec.activeDeadlineSeconds
і .spec.backoffLimit
, призводять до постійної невдачі завдання, що вимагає ручного втручання для вирішення.
Умови термінального завдання
Job має два можливих термінальних стани, кожен з яких має відповідну умову завдання:
- Успішне виконання: умова завдання
Complete
- Невдача: умова завдання
Failed
Завдання зазнають невдачі з наступних причин:
- Кількість невдач Podʼа перевищила вказане
.spec.backoffLimit
у специфікації завдання. Для деталей див. Політика відмови Podʼа. - Час виконання завдання перевищив вказане
.spec.activeDeadlineSeconds
. - Індексуєме завдання, яке використовує
.spec.backoffLimitPerIndex
, має невдалі індекси. Для деталей див. Ліміт затримки на індекс. - Кількість невдалих індексів у завданні перевищила вказане
spec.maxFailedIndexes
. Для деталей див. Ліміт затримки на індекс. - Невдалий Pod відповідає правилу у
.spec.podFailurePolicy
, яке має дію FailJob
. Для деталей про те, як правила політики невдач Podʼа можуть вплинути на оцінку невдачі, див. Політика невдач Podʼа.
Завдання успішні з наступних причин:
- Кількість успішних Podʼів досягла вказаного
.spec.completions
. - Виконані критерії, зазначені у
.spec.successPolicy
. Для деталей див. Політика успіху.
У Kubernetes v1.31 та пізніших версіях контролер завдань затримує додавання термінальних умов, Failed
або Complete
, поки всі Podʼи завдання не будуть завершені.
У Kubernetes v1.30 та раніших версіях контролер завдань додавав термінальні умови Complete
або Failed
відразу після того, як був запущений процес завершення завдання та всі завершувачі Podʼа були видалені. Однак деякі Podʼи все ще могли працювати або завершуватися в момент додавання термінальної умови.
У Kubernetes v1.31 та пізніших версіях контролер додає термінальні умови завдання лише після завершення всіх Podʼів. Ви можете увімкнути цю поведінку, використовуючи функціональні можливості JobManagedBy
та JobPodReplacementPolicy
(обидві стандартно увімкнені).
Завершення Podʼів завдання
Контролер Job додає умову FailureTarget
або умову SuccessCriteriaMet
до завдання, щоб запустити завершення Pod після того, як завдання відповідає критеріям успіху або невдачі.
Фактори, такі як terminationGracePeriodSeconds
, можуть збільшити час від моменту додавання контролером завдання умови FailureTarget
або умови SuccessCriteriaMet
до моменту, коли всі Pod завдання завершаться і контролер Job додасть термінальну умову (Failed
або Complete
).
Ви можете використовувати умову FailureTarget
або умову SuccessCriteriaMet
, щоб оцінити, чи завдання зазнало невдачі чи досягло успіху, без необхідності чекати, поки контролер додасть термінальну умову.
Наприклад, ви можете захотіти вирішити, коли створити замінний Job, що замінює невдалий. Якщо ви заміните невдале завдання, коли з’являється умова FailureTarget
, ваше замінне завдання запуститься раніше, але це може призвести до того, що Podʼи з невдалого та замінного завдання будуть працювати одночасно, використовуючи додаткові обчислювальні ресурси.
Альтернативно, якщо ваш кластер має обмежену ресурсну ємність, ви можете вибрати чекати, поки з’явиться умова Failed
на завданні, що затримає ваше замінне завдання, але забезпечить збереження ресурсів, чекаючи, поки всі невдалі Podʼи не будуть видалені.
Автоматичне очищення завершених завдань
Зазвичай завершені завданя вже не потрібні в системі. Зберігання їх в системі може створювати тиск на сервер API. Якщо завдання керується безпосередньо контролером вищого рівня, таким як CronJobs, завдання можна очищати за допомогою CronJobs на основі визначеної політики очищення з урахуванням місткості.
Механізм TTL для завершених завдань
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.23 [stable]
Ще один спосіб автоматично очищати завершені завдання (якщо вони Complete
або Failed
) — це використовувати механізм TTL, наданий
контролером TTL для завершених ресурсів, вказуючи поле .spec.ttlSecondsAfterFinished
у Job.
Коли контролер TTL очищує Job, він каскадно видаляє Job, тобто видаляє його залежні обʼєкти, такі як Podʼи, разом з Job. Зверніть увагу що при видаленні Job будуть дотримані гарантії його життєвого циклу, такі як завершувачі.
Наприклад:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-with-ttl
spec:
ttlSecondsAfterFinished: 100
template:
spec:
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
Job pi-with-ttl
буде призначено для автоматичного видалення через 100
секунд після завершення.
Якщо поле встановлено в 0
, Job буде призначено для автоматичного видалення негайно після завершення. Якщо поле не вказане, це Job не буде очищено контролером TTL після завершення.
Примітка:
Рекомендується встановлювати поле ttlSecondsAfterFinished
, оскільки завдання без нагляду (завдання, які ви створили безпосередньо, а не опосередковано через інші API робочого навантаження такі як CronJob) мають станадартну політику видалення orphanDependents
, що призводить до того, що Podʼи, створені некерованим Job, залишаються після того, як Job повністю видалено. Навіть якщо панель управління в кінцевому рахунку збирає сміття Podʼів з видаленого Job після того, як вони або не вдались, або завершились, іноді ці залишки Podʼів можуть призводити до погіршання продуктивності кластера або в найгіршому випадку можуть спричинити відключення кластера через це погіршення.
Ви можете використовувати LimitRanges та ResourceQuotas щоб обмежити кількість ресурсів, які певний простір імен може споживати.
Патерни використання завдань (Job)
Обʼєкт завдання (Job) може використовуватися для обробки набору незалежних, але повʼязаних робочих одиниць. Це можуть бути електронні листи для надсилання, кадри для відтворення, файли для транскодування, діапазони ключів у базі даних NoSQL для сканування і так далі.
У складній системі може бути кілька різних наборів робочих одиниць. Тут ми розглядаємо лише один набір робочих одиниць, якими користувач хоче управляти разом — пакетне завдання.
Існує кілька різних патернів для паралельних обчислень, кожен з власними перевагами та недоліками. Компроміси:
- Один обʼєкт Job для кожної робочої одиниці або один обʼєкт Job для всіх робочих одиниць. Один Job на кожну робочу одиницю створює деяку накладну роботу для користувача та системи при управлінні великою кількістю обʼєктів Job. Один Job для всіх робочих одиниць підходить краще для великої кількості одиниць.
- Кількість створених Podʼів дорівнює кількості робочих одиниць або кожен Pod може обробляти кілька робочих одиниць. Коли кількість Podʼів дорівнює кількості робочих одиниць, Podʼи зазвичай вимагають менше змін у наявному коді та контейнерах. Кожен Pod, що обробляє кілька робочих одиниць, підходить краще для великої кількості одиниць.
- Декілька підходів використовують робочу чергу. Це вимагає запуску служби черги та модифікацій існуючої програми чи контейнера, щоб зробити його сумісним із чергою роботи. Інші підходи легше адаптувати до наявного контейнеризованого застосунку.
- Коли Job повʼязаний із headless Service, ви можете дозволити Podʼам у межах Job спілкуватися один з одним для спільної обчислень.
Переваги та недоліки узагальнено у таблиці нижче, де стовпці з 2 по 4 відповідають зазначеним вище питанням. Імена патернів також є посиланнями на приклади та більш детальний опис.
Коли ви вказуєте завершення з .spec.completions
, кожний Pod, створений контролером Job, має ідентичний spec
. Це означає, що всі Podʼи для завдання матимуть однакову командну строку та один і той же шаблон, та (майже) ті ж самі змінні середовища. Ці патерни — це різні способи організації Podʼів для роботи над різними завданнями.
Ця таблиця показує обовʼязкові налаштування для .spec.parallelism
та .spec.completions
для кожного з патернів. Тут W
— це кількість робочих одиниць.
Розширене використання завдань (Job)
Відкладення завдання
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.24 [stable]
Коли створюється Job, контролер Job негайно починає створювати Podʼи, щоб відповісти вимогам Job і продовжує це робити, доки Job не завершиться. Однак іноді ви можете хотіти тимчасово призупинити виконання Job та відновити його пізніше, або створити Jobs у призупиненому стані та мати власний контролер, який вирішить, коли їх запустити.
Щоб призупинити Job, ви можете оновити поле .spec.suspend
Job на значення true; пізніше, коли ви захочете відновити його, оновіть його на значення false. Створення Job з .spec.suspend
встановленим в true створить його в призупиненому стані.
При відновленні Job з призупинення йому буде встановлено час початку .status.startTime
в поточний час. Це означає, що таймер .spec.activeDeadlineSeconds
буде зупинений і перезапущений, коли Job буде призупинено та відновлено.
Коли ви призупиняєте Job, будь-які запущені Podʼи, які не мають статусу Completed
, будуть завершені з сигналом SIGTERM. Буде дотримано період відповідного завершення ваших Podʼів, і вашим Podʼам слід обробити цей сигнал протягом цього періоду. Це може включати в себе збереження прогресу для майбутнього або скасування змін. Podʼи, завершені цим чином, не враховуватимуться при підрахунку completions
Job.
Приклад визначення Job в призупиненому стані може виглядати так:
kubectl get job myjob -o yaml
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
suspend: true
parallelism: 1
completions: 5
template:
spec:
...
Ви також можете перемикати призупинення Job, використовуючи командний рядок.
Призупиніть активний Job:
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":true}}'
Відновіть призупинений Job:
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":false}}'
Статус Job може бути використаний для визначення того, чи Job призупинено чи його було зупинено раніше:
kubectl get jobs/myjob -o yaml
apiVersion: batch/v1
kind: Job
# .metadata and .spec пропущено
status:
conditions:
- lastProbeTime: "2021-02-05T13:14:33Z"
lastTransitionTime: "2021-02-05T13:14:33Z"
status: "True"
type: Suspended
startTime: "2021-02-05T13:13:48Z"
Умова Job типу "Suspended" зі статусом "True" означає, що Job призупинено; поле lastTransitionTime
може бути використане для визначення того, як довго Job було призупинено. Якщо статус цієї умови є "False", то Job було раніше призупинено і зараз працює. Якщо такої умови не існує в статусі Job, то Job ніколи не був зупинений.
Також створюються події, коли Job призупинено та відновлено:
kubectl describe jobs/myjob
Name: myjob
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 12m job-controller Created pod: myjob-hlrpl
Normal SuccessfulDelete 11m job-controller Deleted pod: myjob-hlrpl
Normal Suspended 11m job-controller Job suspended
Normal SuccessfulCreate 3s job-controller Created pod: myjob-jvb44
Normal Resumed 3s job-controller Job resumed
Останні чотири події, зокрема події "Suspended" та "Resumed", є прямим наслідком перемикання поля .spec.suspend
. Протягом цього часу ми бачимо, що жоден Pods не був створений, але створення Pod розпочалося знову, як тільки Job було відновлено.
Змінні директиви планування
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.27 [stable]
У більшості випадків, паралелльні завдання вимагатимуть щоб їхні Podʼи запускались з певними обмеженнями, типу "всі в одній зоні" або "всі на GPU моделі x або y", але не комбінація обох.
Поле призупинення є першим кроком для досягнення цих семантик. Призупинення дозволяє власному контролеру черги вирішити, коли повинне початися завдання; Однак після того, як завдання престає бути призупиненим, власний контролер черги не впливає на те, де насправді буде розташований Pod завдання.
Ця функція дозволяє оновлювати директиви планування Job до запуску, що дає власному контролеру черги змогу впливати на розташування Podʼів, а в той самий час здійснювати власне призначення Podʼів вузлам в kube-scheduler. Це дозволяється тільки для призупинених Завдань, які ніколи не переставали бути призупиненими раніше.
Поля в шаблоні Podʼа Job, які можна оновити, це приналежність до вузла, селектор вузла, толерантності, мітки, анотації та вікно планування.
Вказування власного селектора Podʼа
Зазвичай, коли ви створюєте обʼєкт Job, ви не вказуєте .spec.selector
. Логіка системного визначення типових значень додає це поле під час створення Завдання. Вона обирає значення селектора, яке не буде перекриватися з будь-яким іншим завданням.
Однак у деяких випадках вам може знадобитися перевизначити цей автоматично встановлений селектор. Для цього ви можете вказати .spec.selector
Job.
Будьте дуже уважні при цьому. Якщо ви вказуєте селектор міток, який не є унікальним для Podʼів цього Завдання, і який відповідає неповʼязаним Podʼам, то Podʼи з неповʼязаним Завданням можуть бути видалені, або це Завдання може вважати інші Podʼи завершеними, або одне чи обидва Завдання можуть відмовитися від створення Podʼів або виконуватись до завершення роботи. Якщо вибираєте неунікальний селектор, то інші контролери (наприклад, ReplicationController) та їхні Podʼи можуть проявляти непередбачувану поведінку також. Kubernetes не зупинить вас від того, що ви можете зробити помилку при зазначені .spec.selector
.
Ось приклад ситуації, коли вам може знадобитися використовувати цю функцію.
Скажімо, Завдання old
вже запущене. Ви хочете, щоб наявні Podʼи продовжували працювати, але ви хочете, щоб решта Podʼів, які воно створює, використовували інший шаблон Pod і щоб у Завдання було нове імʼя. Ви не можете оновити Завдання, оскільки ці поля не можна оновлювати. Отже, ви видаляєте Завдання old
, але залишаєте її Podʼи запущеними, використовуючи kubectl delete jobs/old --cascade=orphan
. Перед видаленням ви робите помітку, який селектор використовувати:
kubectl get job old -o yaml
Виввід схожий на цей:
kind: Job
metadata:
name: old
...
spec:
selector:
matchLabels:
batch.kubernetes.io/controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
Потім ви створюєте нове Завдання з імʼям new
і явно вказуєте той самий селектор. Оскільки існуючі Podʼи мають мітку batch.kubernetes.io/controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002
, вони також контролюються Завданням new
.
Вам потрібно вказати manualSelector: true
в новому Завданні, оскільки ви не використовуєте селектор, який система зазвичай генерує автоматично.
kind: Job
metadata:
name: new
...
spec:
manualSelector: true
selector:
matchLabels:
batch.kubernetes.io/controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
...
Саме нове Завдання матиме інший uid від a8f3d00d-c6d2-11e5-9f87-42010af00002
. Встановлення manualSelector: true
говорить системі, що ви розумієте, що робите, і дозволяє це неспівпадіння.
Відстеження Завдання за допомогою завершувачів
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.26 [stable]
Панель управління стежить за Podʼами, які належать будь-якого Завдання, і виявляє, чи Pod був видалений з сервера API. Для цього контролер Job створює Podʼи з завершувачем batch.kubernetes.io/job-tracking
. Контролер видаляє завершувач тільки після того, як Pod був врахований в стані Завдання, що дозволяє видалити Pod іншими контролерами або користувачами.
Еластичні Індексовані Завдання
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.31 [stable]
(стандартно увімкнено: true)
Ви можете масштабувати Indexed Job вгору або вниз, змінюючи як .spec.parallelism
, так і .spec.completions
разом, так щоб .spec.parallelism == .spec.completions
. При масштабуванні вниз Kubernetes видаляє Podʼи з вищими індексами.
Сценарії використання для еластичних Індексованих Завдань включають пакетні робочі навантаження, які вимагають масштабування Індексованого Завдання, такі як MPI, Horovod, Ray, та PyTorch.
Відкладене створення замінних Podʼів
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.29 [beta]
Примітка:
Ви можете встановити
podReplacementPolicy
для Завдань тільки у випадку, якщо увімкнуто
функціональну можливість JobPodReplacementPolicy
(стандартно увімкнено).
Типово контролер Job створює Podʼи якнайшвидше, якщо вони або зазнають невдачі, або знаходяться в стані завершення (мають відмітку видалення). Це означає, що в певний момент часу, коли деякі з Podʼів знаходяться в стані завершення, кількість робочих Podʼів для Завдання може бути більшою, ніж parallelism
або більше, ніж один Pod на індекс (якщо ви використовуєте Індексоване Завданя).
Ви можете вибрати створення замінних Podʼів лише тоді, коли Podʼи, які знаходиться в стані завершення, повністю завершені (мають status.phase: Failed
). Для цього встановіть .spec.podReplacementPolicy: Failed
. Типова політика заміщення залежить від того, чи Завдання має встановлену політику відмови Podʼів. Якщо для Завдання не визначено політику відмови Podʼів, відсутність поля podReplacementPolicy
вибирає політику заміщення TerminatingOrFailed
: панель управління створює Podʼи заміни негайно після видалення Podʼів (як тільки панель управління бачить, що Pod для цього Завдання має встановлене значення deletionTimestamp
). Для Завдань із встановленою політикою відмови Podʼів стандартне значення podReplacementPolicy
— це Failed
, інших значень не передбачено. Докладніше про політики відмови Podʼів для Завдань можна дізнатися у розділі Політика відмови Podʼів.
kind: Job
metadata:
name: new
...
spec:
podReplacementPolicy: Failed
...
При увімкненому feature gate у вашому кластері ви можете перевірити поле .status.terminating
Завдання. Значення цього поля — це кількість Podʼів, якими володіє Завдання, які зараз перебувають у стані завершення.
kubectl get jobs/myjob -o yaml
apiVersion: batch/v1
kind: Job
# .metadata and .spec omitted
status:
terminating: 3 # три Podʼи, які перебувають у стані завершення і ще не досягли стану Failed
Делегування управління обʼєктом Job зовнішньому контролеру
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.32 [beta]
(стандартно увімкнено: false)
Примітка:
Ви можете встановити поле
managedBy
для Job лише в разі увімкнення
функціональної можливості JobManagedBy
(типово увімкнено).
Ця функція дозволяє вам вимкнути вбудований контролер Job для конкретного Завдання і делегувати узгодження цього Завдання зовнішньому контролеру.
Ви вказуєте контролер, який узгоджує Завдання, встановлюючи власне значення для поля spec.managedBy
— будь-яке значення окрім kubernetes.io/job-controller
. Значення поля є незмінним.
Примітка:
При використанні цієї функції переконайтеся, що контролер, вказаний у полі, встановлено, інакше Завдання може не бути узгоджене взагалі.Примітка:
При розробці зовнішнього контролера Job, будьте уважні: ваш контролер повинен працювати відповідно до визначень специфікації API та полів статусу обʼєкта Job.
Докладно ознайомтесь з ними в API Job. Ми також рекомендуємо запустити тести сумісності e2e для обʼєкта Job, щоб перевірити вашу реалізацію.
Нарешті, при розробці зовнішнього контролера Job переконайтеся, що він не використовує завершувач batch.kubernetes.io/job-tracking
, зарезервований для вбудованого контролера.
Попередження:
Якщо ви думаєте про вимкення JobManagedBy
, або зниження версії кластера до версії без увімкненого feature gate, перевірте, чи є у вас завдання з власним значенням поля spec.managedBy
. Якщо такі завдання існують, існує ризик
того, що після виконання операції вони можуть бути узгоджені двома контролерами: вбудованим контролером Job і зовнішнім контролером, вказаним значенням поля.Альтернативи
Тільки Podʼи
Коли вузол, на якому працює Pod, перезавантажується або виходить з ладу, Pod завершується і не буде перезапущений. Однак Завдання створить нові Podʼи для заміщення завершених. З цієї причини ми рекомендуємо використовувати Завдання замість тільки Podʼів, навіть якщо ваш застосунок вимагає тільки одного Podʼа.
Контролер реплікації
Завдання є компліментарними до контролера реплікації. Контролер реплікації керує Podʼами, які не повинні завершуватися (наприклад, вебсервери), а Завдання керує Podʼами, які очікують завершення (наприклад, пакетні задачі).
Якщо врахувати життєвий цикл Podʼа, Job
лише придатний для Podʼів з RestartPolicy
, рівним OnFailure
або Never
. (Примітка: Якщо RestartPolicy
не встановлено, стандартне значення — Always
.)
Один Job запускає контролер Podʼів
Ще один підхід — це те, що одне Завдання створює Podʼи, які своєю чергою створюють інші Podʼи, виступаючи як свого роду власний контролер для цих Podʼів. Це дає найбільшу гнучкість, але може бути дещо складним для початку використання та пропонує меншу інтеграцію з Kubernetes.
Один приклад такого підходу — це Завдання, яке створює Podʼи, яка виконує сценарій, який з свого боку запускає контролер Spark master (див. приклад Spark), запускає драйвер Spark, а потім робить очищення.
Перевагою цього підходу є те, що загальний процес отримує гарантію завершення обʼєкта Job, але при цьому повністю контролюється те, які Podʼи створюються і яке навантаження їм призначається.
Що далі
- Дізнайтеся про Podʼи.
- Дізнайтеся про різні способи запуску Завдань:
- Перейдіть за посиланням Автоматичне очищення завершених завдань, щоб дізнатися більше про те, як ваш кластер може очищати завершені та/або невдачливі завдання.
Job
є частиною REST API Kubernetes. Ознайомтесь з визначенням обʼєкта
Job, щоб зрозуміти API для завдань.- Прочитайте про
CronJob
, який ви можете використовувати для визначення серії Завдань, які будуть виконуватися за розкладом, схожим на інструмент UNIX cron
. - Попрактикуйтесь в налаштувані обробки відмовних і невідмовних збоїв Podʼів за допомогою
podFailurePolicy
на основі покрокових прикладів.
6 - Автоматичне очищення завершених задач
Механізм визначення часу життя для автоматичного очищення старих задач, які завершили виконання.
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.23 [stable]
Коли ваша задача завершилася, корисно залишити цю задачу в API (і не видаляти її відразу), щоб ви могли визначити, чи вдалося, чи не вдалося завдання.
Контролер Kubernetes часу життя після завершення забезпечує механізм TTL (time to live), щоб обмежити термін життя обʼєктів задачі, які завершили виконання.
Очищення завершених задач
Контролер часу життя після завершення підтримується лише для задач. Ви можете використовувати цей механізм для автоматичного очищення завершених завдань (як Complete
, так і Failed
), автоматично вказавши поле .spec.ttlSecondsAfterFinished
задачі, як у цьому прикладі.
Контролер часу життя після завершення передбачає, що задачу можна очистити через TTL секунд після завершення роботи. Відлік починається, коли умова статусу задачі змінюється, щоб показати, що задача є або Complete
, або Failed
; як тільки TTL закінчився, ця задача стає придатною для каскадного видалення. Коли контролер часу життя після завершення очищає задачу, він видалить її каскадно, іншими словами, він видалить її залежні обʼєкти разом з нею.
Kubernetes дотримується гарантій життєвого циклу обʼєкта для задачі, таких як очікування завершувачів.
Ви можете встановити TTL секунд у будь-який момент. Ось деякі приклади встановлення поля .spec.ttlSecondsAfterFinished
задачі:
- Вказуйте це поле в маніфесті задачі, щоб задачу можна було автоматично очистити через певний час після її завершення.
- Вручну встановлюйте це поле вже наявним завершеним завданням, щоб вони стали придатними для очищення.
- Використовуйте змінний вебхук доступу для динамічного встановлення цього поля під час створення задачі. Адміністратори кластера можуть використовувати це, щоб накладати політику TTL для завершених задач.
- Використовуйте змінний вебхук доступу для динамічного встановлення цього поля після завершення задачі та вибору різних значень TTL на основі статусу завдання, міток. У цьому випадку вебзапит повинен виявляти зміни в полі
.status
задачі та встановлювати TTL лише тоді, коли задача позначається як завершена. - Напишіть свій власний контролер для управління часом життя TTL для задач, які відповідають певному селектору.
Обмеження
Оновлення TTL для завершених задач
Ви можете змінювати період TTL, наприклад, поле .spec.ttlSecondsAfterFinished
для задач, після створення або завершення задачі. Якщо ви збільшуєте період TTL після закінчення поточного періоду ttlSecondsAfterFinished
, Kubernetes не гарантує збереження цієї задачі, навіть якщо оновлення для збільшення TTL повертає успішну API відповідь.
Зсув часу
Оскільки контролер часу життя після завершення використовує відмітки часу, збережені в задачах Kubernetes, для визначення того, чи TTL минув, чи ні, ця функція чутлива до зсуву часу в кластері, що може призвести до очищення обʼєктів задачі в неправильний час.
Годинники не завжди вірні, але різниця повинна бути дуже мала. Будь ласка, будьте уважні при встановленні ненульового TTL.
Що далі
7 - CronJob
Обʼєкт CronJob запускає Job за повторюваним графіком.
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.21 [stable]
CronJob створює Jobs за повторюваним графіком.
CronJob призначений для виконання регулярних запланованих дій, таких як резервне копіювання, генерація звітів та інше. Один обʼєкт CronJob подібний до одного рядка файлу crontab (таблиця cron) на системі Unix. Він запускає Job періодично за заданим графіком, записаним у форматі Cron.
У CronJob є обмеження та особливості. Наприклад, в певних обставинах один CronJob може створювати кілька одночасних Jobs. Див. обмеження нижче.
Коли планувальник створює нові Jobs і (відповідно) Podʼи для CronJob, .metadata.name
CronJob є частиною основи для імені цих Podʼів. Назва CronJob повинна бути дійсним значенням DNS-піддомену, але це може призводити до неочікуваних результатів для імен хостів Podʼів. Для найкращої сумісності назва повинна відповідати більш обмеженим правилам DNS-мітки. Навіть коли імʼя є DNS-піддоменом, імʼя не повинно бути довше 52 символів. Це тому, що контролер CronJob автоматично додає 11 символів до наданого вами імені, і існує обмеження на довжину імені Job, яке не повинно перевищувати 63 символи.
Приклад
У цьому прикладі маніфест CronJob виводить поточний час та вітання кожну хвилину:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
(Виконання автоматизованих завдань за допомогою CronJob докладніше описує цей приклад).
Написання специфікації CronJob
Синтаксис розкладу
Поле .spec.schedule
є обовʼязковим. Значення цього поля відповідає синтаксису Cron:
# ┌───────────── хвилина (0 - 59)
# │ ┌───────────── година (0 - 23)
# │ │ ┌───────────── день місяця (1 - 31)
# │ │ │ ┌───────────── місяць (1 - 12)
# │ │ │ │ ┌───────────── день тижня (0 - 6) (Неділя - Субота)
# │ │ │ │ │ АБО неділя, понеділок, вівторок, середа, четвер, пʼятниця, субота
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
Наприклад, 0 3 * * 1
означає, що це завдання планується запускати щотижня в понеділок о 3 ранку.
Формат також включає розширені значення кроків "Vixie cron". Як пояснено в документації FreeBSD:
Значення кроків можна використовувати разом із діапазонами. Після діапазону з / <number>
вказує пропуски значення числа через діапазон. Наприклад, 0-23/2
можна використовувати в годинах для вказівки виконання команди кожну другу годину (альтернативою в стандарті V7 є 0,2,4,6,8,10,12,14,16,18,20,22
). Після зірочки також допускаються кроки, тому, якщо ви хочете сказати "кожні дві години", просто використовуйте */2
.
Примітка:
Знак питання (?
) у розкладі має той же зміст, що й зірочка *
, тобто позначає будь-яке доступне значення для даного поля.Окрім стандартного синтаксису, також можна використовувати деякі макроси, такі як @monthly
:
Запис | Опис | Еквівалентно |
---|
@yearly (або @annually) | Виконувати один раз на рік о півночі 1 січня | 0 0 1 1 * |
@monthly | Виконувати один раз на місяць о півночі першого дня місяця | 0 0 1 * * |
@weekly | Виконувати один раз на тиждень о півночі в неділю | 0 0 * * 0 |
@daily (або @midnight) | Виконувати один раз на день о півночі | 0 0 * * * |
@hourly | Виконувати один раз на годину на початку години | 0 * * * * |
Для генерації виразів розкладу CronJob можна також використовувати вебінструменти, наприклад crontab.guru.
Шаблон завдання
Поле .spec.jobTemplate
визначає шаблон для завдань, які створює CronJob, і воно обовʼязкове. Воно має точно таку ж схему, як Job, за винятком того, що воно вкладене і не має apiVersion
або kind
. Ви можете вказати загальні метадані для завдань, створених за шаблоном, такі як labels або annotations. Щодо інформації щодо написання .spec
завдання, дивіться Написання специфікації завдання.
Термін відстрочення для відкладеного запуску завдання
Поле .spec.startingDeadlineSeconds
є необовʼязковим. Це поле визначає термін (в повних секундах) для запуску завдання, якщо це завдання пропускає свій запланований час з будь-якої причини.
Після пропуску терміну CronJob пропускає цей екземпляр завдання (майбутні випадки все ще заплановані). Наприклад, якщо у вас є завдання резервного копіювання, яке запускається двічі на день, ви можете дозволити йому запускатися з запізненням до 8 годин, але не пізніше, оскільки резервна копія, виконана пізніше, буде неактуальною: ви замість цього віддавали б перевагу чекати на наступний запланований запуск.
Для завдань, які пропускають свій термін, налаштований час відстрочення, Kubernetes вважає їх завданнями, що не вдалися. Якщо ви не вказали startingDeadlineSeconds
для CronJob, екземпляри завдань не мають терміну.
Якщо поле .spec.startingDeadlineSeconds
встановлено (не є нульовим), контролер CronJob вимірює час між тим, коли очікується створення завдання, і зараз. Якщо різниця вище за цей ліміт, він пропускає це виконання.
Наприклад, якщо воно встановлене на 200
, це дозволяє створити завдання протягом 200 секунд після фактичного часу.
Політика паралелізму
Також необовʼязкове поле .spec.concurrencyPolicy
. Воно визначає, як обробляти паралельні виконання завдання, яке створюється цим CronJob. Специфікація може вказувати лише одну з наступних політик паралельності:
Allow
(станадартно): CronJob дозволяє паралельні запуски завданьForbid
: CronJob не дозволяє паралельні запуски; якщо настав час для нового запуску завдання і попередній запуск завдання ще не завершився, CronJob пропускає новий запуск завдання. Також слід зауважити, що коли попередній запуск завдання завершиться, враховується .spec.startingDeadlineSeconds
і може призвести до нового запуску завдання.Replace
: Якщо час для нового запуску завдання і попередній запуск завдання ще не завершився, CronJob замінює поточний запуск завдання новим запуском завдання.
Зверніть увагу, що політика паралелізму застосовується лише до завдань, створених цим самим CronJob. Якщо є кілька CronJob, їхні відповідні завдання завжди можуть виконуватися паралельно.
Призупинення розкладу
Ви можете призупинити виконання завдань для CronJob, встановивши необовʼязкове поле .spec.suspend
в значення true. Стандартно поле має значення false.
Це налаштування не впливає на завдання, які CronJob вже розпочав.
Якщо ви встановите це поле в значення true, всі наступні виконання будуть призупинені (вони залишаються запланованими, але контролер CronJob не запускає завдання для виконання завдань), поки ви не призупините CronJob.
Увага:
Виконання, які призупинені під час запланованого часу, вважаються пропущеними завданнями. Коли
.spec.suspend
змінюється з
true
на
false
для наявного CronJob без
строку початку, пропущені завдання заплановані негайно.
Обмеження історії завдань
Поля .spec.successfulJobsHistoryLimit
та .spec.failedJobsHistoryLimit
вказують, скільки завершених успішних та невдалих завдань потрібно зберігати. Обидва поля є необовʼязковими.
.spec.successfulJobsHistoryLimit
: Це поле вказує кількість успішно завершених завдань, які слід зберігати. Стандартне значення — 3
. Встановлення цього поля на 0
не буде зберігати жодних успішних завдань.
.spec.failedJobsHistoryLimit
: Це поле вказує кількість невдало завершених завдань, які слід зберігати. Стандартне значення — 1
. Встановлення цього поля на 0
не буде зберігати жодних невдало завершених завдань.
Для іншого способу автоматичного прибирання завершених Завдань, дивіться Автоматичне прибирання завершених завдань.
Часові пояси
СТАН ФУНКЦІОНАЛУ:
Kubernetes v1.27 [stable]
Для CronJob без вказаного часового поясу kube-controller-manager інтерпретує розклад відносно свого локального часового поясу.
Ви можете вказати часовий пояс для CronJob, встановивши .spec.timeZone
на назву дійсного часового поясу. Наприклад, встановлення .spec.timeZone: "Etc/UTC"
вказує Kubernetes інтерпретувати графік відносно Координованого універсального часу.
В базових бінарниках включена база даних часових поясів зі стандартної бібліотеки Go і використовується як запасний варіант у разі, якщо зовнішня база даних недоступна на системі.
Обмеження CronJob
Непідтримувані специфікації часових поясів
Зазначення часового поясу за допомогою змінних CRON_TZ
або TZ
всередині .spec.schedule
офіційно не підтримується (і ніколи не підтримувалася).
Починаючи з Kubernetes 1.29, якщо ви намагаєтеся встановити розклад, який включає вказівку часового поясу TZ
або CRON_TZ
, Kubernetes не зможе створити ресурс і сповістить про помилку. Оновлення CronJobs, які вже використовують TZ
або CRON_TZ
, продовжать повідомляти клієнта про попередження.
Зміна параметрів CronJob
За концепцією, у CronJob є шаблоном для нових Jobs. Якщо ви модифікуєте наявний CronJob, зміни застосовуватимуться до нових Job, які почнуть виконуватися після завершення вашої модифікації. Job (і їх Podʼи), які вже почали виконуватися, продовжують працювати без змін. Іншими словами, CronJob не оновлює поточні Job, навіть якщо вони ще продовжують виконуватися.
Створення Job
CronJob створює обʼєкт Job приблизно один раз за час виконання свого розкладу. Запуск є приблизним через те, що є обставини, коли може бути створено два Job або жодного. Kubernetes намагається уникати таких ситуацій, але не повністю запобігає їм. Таким чином, Job, які ви визначаєте, повинні бути ідемпотентними.
Починаючи з Kubernetes v1.32, CronJobs застосовує анотацію batch.kubernetes.io/cronjob-scheduled-timestamp
до створених завдань. Ця анотація вказує початковий запланований час створення завдання і має формат RFC3339.
Якщо startingDeadlineSeconds
встановлено на велике значення або залишено не встановленим (типово), і якщо concurrencyPolicy
встановлено на Allow
, Jobs завжди будуть запускатися принаймні один раз.
Увага:
Якщо startingDeadlineSeconds
встановлено у значення менше ніж 10 секунд, CronJob може не бути заплановано. Це повʼязано з тим, що контролер CronJob перевіряє стан справ кожні 10 секунд.Для кожного CronJob контролер CronJob Контролер перевіряє, скільки розкладів він пропустив протягом часу від його останнього запланованого часу до теперішнього часу. Якщо пропущено понад 100 розкладів, то Job не запускається, і виводиться помилка в лог.
Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.
Важливо відзначити, що якщо поле startingDeadlineSeconds
встановлено (не є nil
), контролер враховує, скільки пропущених Job сталося від значення startingDeadlineSeconds
до теперішнього часу, а не від останнього запланованого часу до теперішнього часу. Наприклад, якщо startingDeadlineSeconds
дорівнює 200
, контролер враховує, скільки Job було пропущено за останні 200 секунд.
CronJob вважається пропущеним, якщо не вдалося створити Job в запланований час. Наприклад, якщо concurrencyPolicy
встановлено на Forbid
і CronJob було спробовано запланувати, коли попередній Job все ще працював, то це буде враховуватися як пропущено.
Наприклад, припустимо, що CronJob встановлено для запуску нового Job кожну хвилину, починаючи з 08:30:00
, і його поле startingDeadlineSeconds
не встановлено. Якщо контролер CronJob випадково був вимкнений з 08:29:00
по 10:21:00
, Job не буде запущено, оскільки кількість пропущених Jobs, які пропустили свій розклад, понад 100.
Для того, щоб краще проілюструвати цей концепт, припустимо, що CronJob встановлено для запуску нового Job кожну хвилину, починаючи з 08:30:00
, і його поле startingDeadlineSeconds
встановлено на 200 секунд. Якщо контролер CronJob випадково був вимкнений протягом того ж періоду, що й у попередньому прикладі (08:29:00
до 10:21:00
) Job все одно запуститься о 10:22:00. Це трапляється тому, що тепер контролер перевіряє, скільки пропущених розкладів сталося за останні 200 секунд (тобто 3 пропущені розклади), а не від останнього запланованого часу до теперішнього часу.
CronJob відповідає лише за створення Job, які відповідають його розкладу, а Job, зs свого боку, відповідає за управління Podʼами, які він представляє.
Що далі
- Дізнайтесь про Podʼи та Job, два поняття, які використовуються в CronJobs.
- Дізнайтеся більше про формат поля
.spec.schedule
в CronJob. - Щодо інструкцій зі створення та роботи з CronJobs, а також для прикладу маніфесту CronJob, дивіться Виконання автоматизованих завдань за допомогою CronJobs.
CronJob
є частиною Kubernetes REST API. Читайте
CronJob API посилання для отримання докладних деталей.
8 - ReplicationController
Застаріле API для управління навантаженням, яке може горизонтально масштабуватися. Замінено API Deployment та ReplicaSet.
Примітка:
Deployment
, який налаштовує
ReplicaSet
, тепер є рекомендованим способом налаштування реплікації.
ReplicationController гарантує, що завжди запущено зазначену кількість реплік Podʼів. Іншими словами, ReplicationController переконується, що Pod або однорідний набір Podʼів завжди працює та доступний.
Як працює ReplicationController
Якщо є занадто багато Podʼів, ReplicationController завершує зайві Podʼи. Якщо Podʼів замало, ReplicationController запускає додаткові. На відміну від вручну створених Podʼів, Podʼи, якими керує ReplicationController, автоматично замінюються, якщо вони відмовляють, видаляються або завершуються. Наприклад, ваші Podʼи перестворюються на вузлі після руйнівного обслуговування, такого як оновлення ядра. З цієї причини ви повинні використовувати ReplicationController навіть якщо ваша програма вимагає лише одного Podʼа. ReplicationController схожий на менеджер процесів, але замість того, щоб наглядати за окремими процесами на одному вузлі, ReplicationController наглядає за кількома Podʼами на різних вузлах.
ReplicationController часто скорочується до "rc" в обговореннях та як скорочення в командах kubectl.
Простим випадком є створення одного обʼєкта ReplicationController для надійного запуску одного екземпляра Pod нескінченно. Складніший випадок — це запуск кількох ідентичних реплік реплікованої служби, такої як вебсервери.
Запуск прикладу ReplicationController
Цей приклад конфігурації ReplicationController запускає три копії вебсервера nginx.
kubectl apply -f https://k8s.io/examples/controllers/replication.yaml
Вивід подібний до такого:
replicationcontroller/nginx created
Перевірте стан ReplicationController за допомогою цієї команди:
kubectl describe replicationcontrollers/nginx
Вивід подібний до такого:
Name: nginx
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 0 Running / 3 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- ---- ------ -------
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-qrm3m
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-3ntk0
20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-4ok8v
Тут створено три Podʼи, але жоден ще не працює, можливо, через те, що виконується витягування образу. Трохи пізніше та ж команда може показати:
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Щоб перелічити всі Podʼи, які належать ReplicationController у формі, придатній для машинного читання, можна використовувати команду на зразок:
pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items..metadata.name})
echo $pods
Вивід подібний до такого:
nginx-3ntk0 nginx-4ok8v nginx-qrm3m
Тут селектор такий самий, як і селектор для ReplicationController (бачимо у виводі kubectl describe
), і в іншій формі у replication.yaml
. Опція --output=jsonpath
вказує вираз з іменем кожного Podʼа в отриманому списку.
Створення маніфесту ReplicationController
Як і з усіма іншими конфігураціями Kubernetes, для ReplicationController потрібні поля apiVersion
, kind
і metadata
.
Коли панель управління створює нові Podʼи для ReplicationController, .metadata.name
ReplicationController є частиною основи для найменування цих Podʼів. Назва ReplicationController повинна бути дійсним значенням DNS-піддомену, але це може призводити до неочікуваних результатів для імен хостів Podʼів. Для забезпечення найкращої сумісності імʼя повинно відповідати більш обмеженим правилам для DNS-мітки.
Для загальної інформації про роботу з файлами конфігурації дивіться управління обʼєктами.
ReplicationController також потребує розділу .spec
.
Шаблон Pod
.spec.template
— єдине обовʼязкове поле в розділі .spec
.
.spec.template
— це шаблон pod. Він має точно таку ж схему, як і Pod, за винятком того, що він вкладений і не має apiVersion
або kind
.
Окрім обовʼязкових полів для Pod, шаблон pod в ReplicationController повинен вказати відповідні мітки та відповідну політику перезапуску. Щодо міток, переконайтеся, що вони не перекриваються з іншими контролерами. Див. селектор pod.
Дозволяється лише .spec.template.spec.restartPolicy
, рівна Always
, якщо не вказано інше, що є стандартним значенням.
Для локальних перезапусків контейнерів ReplicationControllers делегують агентові на вузлі, наприклад, Kubelet.
Мітки на ReplicationController
ReplicationController може мати власні мітки (.metadata.labels
). Зазвичай ви встановлюєте їх так само, як і .spec.template.metadata.labels
; якщо .metadata.labels
не вказано, то вони cnfylfhnyj встановлюються як .spec.template.metadata.labels
. Однак вони можуть бути різними, і .metadata.labels
не впливають на поведінку ReplicationController.
Селектор Pod
Поле .spec.selector
є селектором міток. ReplicationController керує всіма Podʼами з мітками, які відповідають селектору. Він не робить різниці між Podʼами, які він створив чи видалив, і Podʼами, які створив чи видалив інший процес чи особа. Це дозволяє замінити ReplicationController без впливу на робочі Podʼи.
Якщо вказано, то .spec.template.metadata.labels
повинні бути рівні .spec.selector
, або вони буде відхилені API. Якщо .spec.selector
не вказано, він буде встановлений типово як .spec.template.metadata.labels
.
Також, як правило, ви не повинні створювати жодних Podʼів, мітки яких відповідають цьому селектору, безпосередньо, з іншим ReplicationController або з іншим контролером, таким як Job. Якщо ви це зробите, то ReplicationController вважатиме, що він створив інші Podʼами. Kubernetes не забороняє вам це робити.
Якщо у вас все-таки виникає кілька контролерів з однаковими селекторами, вам доведеться керувати видаленням самостійно (див. нижче).
Декілька Реплік
Ви можете вказати, скільки Podʼів повинно працювати одночасно, встановивши .spec.replicas
рівним кількості Podʼів, які ви хочете мати одночасно. Кількість, що працює в будь-який момент, може бути більшою або меншою, наприклад, якщо репліки тільки що були збільшені або зменшені, чи якщо Pod коректно зупинено, і запускається його заміна.
Якщо ви не вказали .spec.replicas
, то типово встановлюється 1.
Робота з ReplicationControllers
Видалення ReplicationController та його Podʼів
Щоб видалити ReplicationController та всі його Podʼи, використовуйте команду kubectl delete
. Kubectl масштабує ReplicationController до нуля і чекає, доки кожний Pod буде видалено, перед видаленням самого ReplicationController. Якщо цю команду kubectl перервати, її можна перезапустити.
При використанні REST API або бібліотеки клієнта, вам потрібно виконати кроки явно (масштабування реплік до 0, очікування видалення Podʼів, а потім видалення самого ReplicationController).
Видалення лише ReplicationController
Ви можете видалити ReplicationController, не впливаючи на його Podʼи.
При використанні kubectl вкажіть опцію --cascade=orphan
команді kubectl delete
.
При використанні REST API або бібліотеки клієнта ви можете видалити обʼєкт ReplicationController.
Після видалення оригіналу ви можете створити новий ReplicationController, щоб замінити його. Поки старий та новий .spec.selector
однакові, то новий прийме старі Podʼи. Однак він не буде вживати жодних зусиль, щоб наявні Podʼи відповідали новому, відмінному від оригінального, шаблону Podʼа. Щоб оновити Podʼи за новою специфікацією у керований спосіб, використовуйте кероване оновлення.
Ізолювання Podʼів від ReplicationController
Podʼи можуть бути вилучені із цільового набору ReplicationController, зміною їх мітки. Цей метод може бути використаний для відокремлення Podʼів від служби для налагодження та відновлення даних. Podʼи, які були виокремлені цим способом, будуть автоматично замінені (за умови, що кількість реплік також не змінюється).
Загальні патерни використання
Перепланування
Як було зазначено вище, чи у вас є 1 Pod, який вам потрібно тримати в роботі, чи 1000, ReplicationController гарантує, що зазначена кількість Podʼів існує, навіть у випадку відмови вузла або завершення Podʼа (наприклад, через дію іншого агента управління).
Масштабування
ReplicationController дозволяє масштабувати кількість реплік вгору або вниз, як вручну, так і за допомогою агента автомасштабування, оновлюючи поле replicas
.
Поступові оновлення
ReplicationController призначений для полегшення поступового оновлення служби за допомогою заміни Podʼів один за одним.
Як пояснено в #1353, рекомендований підхід — створити новий ReplicationController з 1 реплікою, масштабувати нові (+1) та старі (-1) контролери по одному, а потім видалити старий контролер після досягнення 0 реплік. Це передбачувано оновлює набір Podʼів незалежно від неочікуваних відмов.
В ідеалі, контролер поступового оновлення мав би враховувати готовність застосунків і гарантувати, що достатня кількість Podʼів завжди працює.
Два ReplicationController повинні створювати Podʼи із принаймні однією відмінною міткою, такою як теґ образу основного контейнера Podʼа, оскільки це зазвичай оновлення образу, що мотивує поступові оновлення.
Кілька треків випуску
Крім того, щоб запустити кілька випусків застосунку під час процесу поступового оновлення, часто використовують кілька треків випуску протягом тривалого періоду часу або навіть постійно, використовуючи кілька треків випуску. Треки можуть бути розрізнені за допомогою міток.
Наприклад, служба може охоплювати всі Podʼи з tier in (frontend), environment in (prod)
. Тепер скажімо, у вас є 10 реплікованих Podʼів, які складають цей рівень. Але ви хочете мати можливість 'канаркову' нову версію цього компонента. Ви можете налаштувати ReplicationController із replicas
, встановленим на 9 для більшості реплік, з мітками tier=frontend, environment=prod, track=stable
, та інший ReplicationController із replicas
, встановленим на 1 для канарки, з мітками tier=frontend, environment=prod, track=canary
. Тепер служба охоплює як канаркові, так і не канаркові Podʼи. Але ви можете окремо взаємодіяти з ReplicationControllers, щоб тестувати речі, відстежувати результати і т.д.
Використання ReplicationControllers з Service
Декілька ReplicationControllers можуть бути розміщені поза одним Service, так що, наприклад, частина трафіку іде до старої версії, а частина до нової.
ReplicationController ніколи не завершиться самостійно, але не очікується, що він буде таким тривалим, як Service. Service можуть складатися з Podʼів, які контролюються кількома ReplicationControllers, і передбачається, що протягом життя Service (наприклад, для виконання оновлення Podʼів, які виконують Service) буде створено і знищено багато ReplicationControllers. Як самі Service, так і їх клієнти повинні залишатися осторонь від ReplicationControllers, які утримують Podʼи Service.
Написання програм для Replication
Створені ReplicationController'ом Podʼи призначені бути взаємозамінними та семантично ідентичними, хоча їх конфігурації можуть ставати різноманітними з часом. Це очевидний вибір для реплікованих stateless серверів, але ReplicationControllers також можна використовувати для забезпечення доступності застосунків, які вибирають майстра, або мають розподілені, або пул робочих задач. Такі застосунки повинні використовувати механізми динамічного призначення роботи, такі як черги роботи RabbitMQ, на відміну від статичної / одноразової настроюваної конфігурації кожного Podʼа, що вважається анти-патерном. Будь-яке настроювання Podʼа, таке як вертикальне автоматичне масштабування ресурсів (наприклад, процесора чи памʼяті), повинно виконуватися іншим процесом контролю в режимі реального часу, подібним до самого ReplicationController.
Обовʼязки ReplicationController
ReplicationController забезпечує відповідність бажаної кількості Podʼів його селектору міток та їхню функціональність. Наразі з його підрахунку виключаються лише завершені Podʼи. У майбутньому можливо буде враховувати інформацію про готовність та інші дані, доступні від системи, можливо буде додано більше елементів керування над політикою заміщення, і планується генерація подій, які можуть використовуватися зовнішніми клієнтами для впровадження довільних складних політик заміщення та / або масштабування вниз.
ReplicationController завжди обмежується цією вузькою відповідальністю. Він самостійно не буде виконувати перевірки готовності або тестів на життєздатність. Замість автоматичного масштабування він призначений для управління зовнішнім автомасштабувальником (як обговорюється в #492), який буде змінювати його поле replicas
. Ми не будемо додавати політик планування (наприклад, розподілення) до ReplicationController. Він також не повинен перевіряти, чи відповідають контрольовані Podʼи поточному зазначеному шаблону, оскільки це може заважати автоматичному зміщенню розміру та іншим автоматизованим процесам. Також термінові строки виконання, залежності від порядку, розширення конфігурації та інші функції належать іншим місцям. Навіть планується виділити механізм масового створення Podʼів (#170).
ReplicationController призначений бути базовим примітивом для побудови композиційних структур. Ми очікуємо, що на його основі та інших взаємодіючих примітивів у майбутньому буде побудовано високорівневі API та / або інструменти для зручності користувачів. "Макро" операції, які наразі підтримуються kubectl (run, scale), є прикладами концепції. Наприклад, можемо уявити щось на зразок Asgard, що управляє ReplicationControllers, автомасштабувальниками, сервісами, політиками планування, канарковими розгортаннями та іншими аспектами.
Обʼєкт API
ReplicationController є ресурсом верхнього рівня в Kubernetes REST API. Докладніша інформація про обʼєкт API може бути знайдена за посиланням: Обʼєкт API ReplicationController.
Альтернативи ReplicationController
ReplicaSet
ReplicaSet
— це ReplicationController нового покоління, який підтримує нові вимоги щодо вибору міток на основі множин. Він використовується головним чином Deployment як механізм для оркестрування створення, видалення та оновлення Podʼів. Зауважте, що ми рекомендуємо використовувати Deployments замість безпосереднього використання Replica Sets, якщо вам потрібна власне оркестрування оновлення або взагалі не потрібні оновлення.
Deployment (Рекомендовано)
Deployment
— це обʼєкт API вищого рівня, який оновлює свої базові Replica Sets та їхні Podʼи. Deployments рекомендуються, якщо вам потрібна функціональність плавного оновлення, оскільки вони є декларативними, виконуються на сервері та мають додаткові функції.
Тільки Podʼи
На відміну від випадку, коли користувач створює Podʼи безпосередньо, ReplicationController замінює Podʼи, які видаляються або завершуються з будь-якого приводу, такого як випадок відмови вузла або руйнівне технічне обслуговування вузла, таке як оновлення ядра. З цієї причини ми рекомендуємо використовувати ReplicationController навіть якщо ваша програма вимагає лише одного Podʼа. Вважайте це подібним наглядачу процесів, тільки він наглядає за кількома Podʼами на кількох вузлах, а не за окремими процесами на одному вузлі. ReplicationController делегує перезапуск контейнерів локальній системі, наприклад Kubelet.
Job
Використовуйте Job
замість ReplicationController для Podʼів, які мають завершуватись самі по собі (іншими словами, пакетні завдання).
DaemonSet
Використовуйте DaemonSet
замість ReplicationController для Podʼів, які забезпечують функцію рівня машини, таку як моніторинг машини або ведення логу машини. Ці Podʼи мають термін служби, який повʼязаний із терміном служби машини: Pod повинty працювати на машині перед тим, як інші Podʼи почнуть працювати, і може бути безпечно завершений, коли машина готова до перезавантаження або вимкнення.
Що далі
- Більше про Podʼи.
- Дізнайтеся більше про Deployment, альтернативу ReplicationController.
ReplicationController
— це частина Kubernetes REST API. Ознайомтесь з визначенням обʼєкта
ReplicationController, щоб зрозуміти API для контролерів реплікації.