Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.

Повернутися до звичайного перегляду сторінки.

Робочі навантаження

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

Робоче навантаження є застосунком, який запущено в Kubernetes. Неважливо, чи є ваше робоче навантаження одним компонентом, чи кількома, які працюють разом, в Kubernetes ви запускаєте його всередині набору Podʼів. У Kubernetes Pod представляє набір з одного чи більше запущених контейнерів у вашому кластері.

Podʼи Kubernetes мають визначений життєвий цикл. Наприклад, як тільки Pod запущено у вашому кластері, будь-яка критична помилка на вузлі, де запущено цей Pod, означає, що всі Podʼи на цьому вузлі зазнають збою. Kubernetes розглядає цей рівень збою як кінцевий: вам потрібно створити новий Pod, щоб відновити роботу, навіть якщо вузол пізніше стане справним.

Однак, щоб значно полегшити роботу, вам не потрібно керувати кожним Podʼом окремо. Натомість ви можете використовувати ресурси робочого навантаження, які керують набором Podʼів за вас. Ці ресурси налаштовують контролери, які стежать за тим, щоб працювала правильна кількість Podʼів потрібного типу, яка відповідає вказаному вами стану.

Kubernetes надає кілька вбудованих ресурсів робочого навантаження:

  • Deployment та ReplicaSet (що є заміною застарілого типу ресурсу ReplicationController). Deployment є хорошим вибором для керування робочим навантаженням, яке не зберігає стану, де будь-який Pod у Deployment є взаємозамінним і може бути замінений, якщо це потрібно.
  • StatefulSet дозволяє вам запускати один або кілька повʼязаних Podʼів, які відстежують стан певним чином. Наприклад, якщо ваше робоче навантаження зберігає дані в постійному сховищі, ви можете запустити StatefulSet, який поєднує кожен Pod з PersistentVolume. Ваш код, який працює в Podʼах цього StatefulSet, може реплікувати дані на інші Podʼи того самого StatefulSet, щоб покращити загальну стійкість.
  • DaemonSet визначає Podʼи, які надають можливості, що є локальними для вузлів. Кожного разу, коли ви додаєте вузол до свого кластера, який відповідає специфікації в DaemonSet, панель управління планує Pod для цього DaemonSet на новому вузлі. Кожен Pod в DaemonSet виконує роботу, схожу на роботу системного демона на класичному сервері Unix/POSIX. DaemonSet може бути фундаментальним для роботи вашого кластера, як, наприклад, втулок для роботи мережі кластера, він може допомогти вам керувати вузлом, або надати необовʼязкову поведінку, яка покращує платформу контейнерів, яку ви використовуєте.
  • Job та CronJob надають різні способи визначення завдань, які виконуються до завершення та зупиняються. Ви можете використовувати Job для визначення завдання, яке виконується до завершення, тільки один раз. Ви можете використовувати CronJob для запуску того самого Job кілька разів згідно з розкладом.

У ширшій екосистемі Kubernetes ви можете знайти ресурси робочого навантаження від сторонніх розробників, які надають додаткові можливості. Використовуючи визначення власних ресурсів, ви можете додати ресурс робочого навантаження від стороннього розробника, якщо ви хочете використовувати конкретну функцію, яка не є частиною основної функціональності Kubernetes. Наприклад, якщо ви хочете запустити групу Podʼів для вашого застосунку, але зупинити роботу, якщо не всі Podʼи доступні (можливо, для якогось високопродуктивного розподіленого завдання), ви можете реалізувати або встановити розширення, яке надає цю функцію.

Розміщення робочих навантажень

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Хоча стандартні ресурси робочого навантаження (наприклад, Deployments та Jobs) керують життєвим циклом Podʼів, ви можете мати складні вимоги до планування, де групи Podʼів мають розглядатися як єдине ціле.

Workload API дозволяє визначати PodGroupTemplates для групування Podʼів та застосування до них розширених політик планування, таких як групове планування. Контролери створюють обʼєкти PodGroup з цих шаблонів під час виконання, а Pods посилаються на свій PodGroup через поле spec.schedulingGroup. Це особливо корисно для пакетної обробки та робочих навантажень машинного навчання, де необхідне розміщення "все або нічого".

Що далі

Окрім читання про кожен вид API для керування робочими навантаженнями, ви можете дізнатися, як виконувати конкретні завдання:

Щоб дізнатись про механізми Kubernetes для відокремлення коду від конфігурації, відвідайте сторінку Конфігурація.

Є дві допоміжні концепції, які пояснюють, як Kubernetes керує Podʼами застосунків:

  • Збір сміття прибирає обʼєкти з вашого кластера після видалення їхнього ресурсу-власника.
  • Контролер time-to-live after finished видаляє Jobs після того, як минув визначений час з моменту їх завершення.

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

1 - Podʼи

Podʼи — найменші придатні для розгортання обчислювальні одиниці, які ви можете створювати в Kubernetes і якими можете керувати.

Pod (ім. чол. рід; як у випадку з групою китів або гороховим стручком) — це група з одного або кількох контейнерів, які мають спільні ресурси зберігання та мережі, а також специфікацію щодо того, як запускати контейнери. Вміст Podʼа завжди розміщується та планується разом і працює в спільному контексті. Pod моделює «логічний хост» конкретного застосунку: він містить один або кілька контейнерів застосунку, які відносно тісно повʼязані між собою. Поза хмарним середовищем застосунки, що виконуються на одній фізичній або віртуальній машині, аналогічні хмарним застосункам, що виконуються на одному логічному хості.

Окрім контейнерів застосунків, Pod може містити init-контейнери, які запускаються під час старту Podʼа. Ви також можете впровадити ефемерні контейнери для налагодження запущеного Podʼа.

Що таке Pod?

Примітка:

Вам потрібно встановити середовище виконання контейнерів на кожному вузлі кластера, щоб Podʼи могли там працювати.

Спільний контекст Podʼа — це набір просторів імен Linux, cgroups та, можливо, інших аспектів ізоляції — тих самих речей, що забезпечують ізоляцію контейнера. В межах контексту Podʼа окремі застосунки можуть мати додаткові рівні ізоляції.

Pod схожий на набір контейнерів зі спільними просторами імен та спільними томами файлової системи.

Podʼи в кластері Kubernetes використовуються двома основними способами:

  • Podʼи, що запускають один контейнер. Модель «один контейнер на Pod» є найпоширенішим сценарієм використання Kubernetes. У цьому випадку Pod можна розглядати як обгортку навколо одного контейнера; Kubernetes керує Podʼами, а не контейнерами безпосередньо.
  • Podʼи, що запускають кілька контейнерів, які мають працювати разом. Pod може інкапсулювати застосунок, який складається з кількох розміщених разом контейнерів, що тісно повʼязані та мають спільно використовувати ресурси. Ці розміщені разом контейнери утворюють єдину цілісну одиницю.

Групування в одному Podʼі кількох контейнерів, які розміщені разом і керуються спільно, — відносно складний сценарій використання. Використовуйте цей підхід лише в тих конкретних випадках, коли ваші контейнери тісно повʼязані.

Для забезпечення реплікації (з метою підвищення відмовостійкості або розширення потужності) не потрібно запускати кілька контейнерів; якщо вам потрібно кілька реплік, дивіться Керування навантаженням.

Використання Podʼів

Нижче наведено приклад Podʼа, який складається з контейнера, що запускає образ nginx:1.14.2.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Для створення Podʼа, показаного вище, виконайте таку команду:

kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml

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

Ресурси робочих навантажень для керування Podʼами

Зазвичай вам не потрібно створювати Podʼи напряму, навіть одиничні Podʼи. Натомість створюйте їх за допомогою ресурсів робочих навантажень, таких як Deployment або Job. Якщо ваші Podʼи потребують відстеження стану, розгляньте використання ресурсу StatefulSet.

Кожен Pod призначений для запуску одного екземпляра певного застосунку. Якщо ви хочете масштабувати свій застосунок горизонтально (щоб надати більше ресурсів загалом, запустивши більше екземплярів), вам слід використовувати кілька Podʼів, по одному для кожного екземпляра. У Kubernetes це зазвичай називається реплікацією. Репліковані Podʼи зазвичай створюються ресурсом робочого навантаження та його контролером, які й керують ними як групою.

Ознайомтесь з розділом Podʼи та контролери для отримання додаткової інформації про те, як Kubernetes використовує ресурси робочих навантажень та їх контролери для реалізації масштабування та автоматичного відновлення роботи застосунку.

Podʼи мають вбудовану підтримку двох видів спільних ресурсів для контейнерів, що входять до їх складу: мережі та зберігання.

Робота з Podʼами

Ви навряд чи створюватимете окремі Podʼи напряму в Kubernetes, навіть одиничні Podʼи. Це тому, що Podʼи спроєктовано як відносно ефемерні, одноразові сутності. Коли Pod створено (безпосередньо вами або опосередковано контролером), новий Pod планується до запуску на вузлі вашого кластера. Pod залишається на цьому вузлі, доки не завершить виконання, доки обʼєкт Pod не буде видалено, доки Pod не буде виселено через брак ресурсів або доки вузол не зазнає збою.

Примітка:

Перезапуск контейнера в Podʼі не слід плутати з перезапуском Podʼа. Pod — це не процес, а середовище для запуску контейнерів. Pod існує до тих пір, поки його не видалено.

Назва Podʼа має бути дійсним DNS-піддоменом, але це може призвести до неочікуваних результатів для імені хоста Podʼа. Для найкращої сумісності назва має відповідати суворішим правилам для DNS-мітки.

Операційна система Podʼа

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.25

Ви маєте встановити значення поля .spec.os.name як windows або linux, щоб визначити операційну систему, яку потребують контейнери в цьому Podʼі. Наразі це єдині операційні системи, які підтримує Kubernetes. У майбутньому цей список може бути розширено.

kubelet відмовляється запускати Pod, якщо значення .spec.os.name не збігається з операційною системою вузла. Однак у Kubernetes v1.37 значення .spec.os.name не впливає на те, як kube-scheduler обирає вузол для запуску Podʼа. У будь-якому кластері, де вузли працюють під керуванням більш ніж однієї операційної системи, слід правильно встановити мітку kubernetes.io/os на кожному вузлі та визначати Podʼи з nodeSelector на основі мітки операційної системи. Якщо ви не вкажете nodeSelector на основі ОС, kube-scheduler може призначити Pod на вузол, ОС якого не підходить для його контейнерів. Стандарти безпеки Podʼів також використовують поле .spec.os.name, щоб уникнути застосування політик, які не стосуються цієї операційної системи.

Podʼи та контролери

Ви можете використовувати ресурси робочих навантажень, щоб створювати кілька Podʼів і керувати ними. Контролер ресурсу опікується реплікацією, розгортанням та автоматичним відновленням у разі збою Podʼа. Наприклад, якщо вузол зазнає збою, контролер помічає, що Podʼи на цьому вузлі перестали працювати, і створює Pod-замінник. Планувальник розміщує Pod-замінник на справному вузлі.

Ось кілька прикладів ресурсів робочих навантажень, які керують одним чи більше Podʼами:

Визначення групи планування

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Стандартно Kubernetes планує кожний Pod окремо. Однак деякі тісно повʼязані застосунки потребують одночасного планування групи Podʼів для коректної роботи.

Ви можете повʼязати Pod з PodGroup за допомогою поля групи планування (spec.schedulingGroup). Це повідомляє kube-scheduler, що Pod належить до певної групи, і дає йому змогу застосовувати скоординовані рішення щодо розміщення на рівні групи одразу для всієї групи.

Шаблони Podʼів

Контролери ресурсів робочих навантажень створюють Podʼи із шаблону Podʼа (pod template) та керують цими Podʼами від вашого імені.

PodTemplate — це специфікації для створення Podʼів, які входять до складу ресурсів робочих навантажень, таких як Deployments, Jobs та DaemonSets.

Кожен контролер ресурсу робочого навантаження використовує PodTemplate всередині обʼєкта робочого навантаження для створення фактичних Podʼів. PodTemplate є частиною бажаного стану будь-якого ресурсу робочого навантаження, який ви використовуєте для запуску вашого застосунку.

Коли ви створюєте Pod, ви можете додати змінні середовища до шаблону Podʼа для контейнерів, які запускаються в Podʼі.

Нижче наведено маніфест простого Job із template, який запускає один контейнер. Контейнер в цьому Podʼі виводить повідомлення, а потім призупиняється.

apiVersion: batch/v1
kind: Job
metadata:
  name: hello
spec:
  template:
    # Це шаблон Podʼа
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    # Кінець шаблону Podʼа

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

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

Кожен ресурс робочого навантаження реалізує власні правила для обробки змін у шаблоні Podʼа. Якщо ви хочете дізнатися більше саме про StatefulSet, прочитайте розділ Стратегія оновлення у навчальному матеріалі «Основи StatefulSet».

На вузлах kubelet безпосередньо не спостерігає за жодними деталями шаблонів Podʼів та оновлень і не керує ними; ці деталі абстраговані. Ця абстракція та розділення відповідальностей спрощує семантику системи та робить можливим розширення поведінки кластера без зміни наявного коду.

Оновлення та заміна Podʼів

Як зазначено в попередньому розділі, коли шаблон Podʼа для ресурсу робочого навантаження змінюється, контролер створює нові Podʼи на основі оновленого шаблону замість оновлення наявних Podʼів або застосування до них патчів.

Kubernetes не забороняє вам керувати Podʼами напряму. Ви можете оновлювати деякі поля запущеного Podʼа на місці. Однак операції оновлення Podʼа, такі як patch та replace, мають деякі обмеження:

  • Більшість метаданих Podʼа є незмінними. Наприклад, ви не можете змінити поля namespace, name, uid або creationTimestamp.
  • Якщо metadata.deletionTimestamp встановлено, новий запис не може бути доданий до списку metadata.finalizers.
  • Оновлення Podʼа не можуть змінювати поля, крім spec.containers[*].image, spec.initContainers[*].image, spec.activeDeadlineSeconds, spec.terminationGracePeriodSeconds, spec.tolerations або spec.schedulingGates. Для spec.tolerations ви можете додавати лише нові записи.
  • Під час оновлення поля spec.activeDeadlineSeconds дозволені два типи оновлень:
    1. присвоєння незаданому полю додатного числа;
    2. зміна значення поля з додатного числа на менше невідʼємне число.

Субресурси Podʼів

Наведені вище правила оновлення застосовуються до звичайних оновлень Podʼів, але інші поля Podʼа можна оновлювати через субресурси.

  • Resize: Субресурс resize дозволяє оновлювати ресурси контейнерів (spec.containers[*].resources). Дивіться Зміна розміру ресурсів контейнера для більш детальної інформації.
  • Ефемерні контейнери: Субресурс ephemeralContainers дозволяє додавати ефемерні контейнери до Podʼа. Дивіться Ефемерні контейнери для більш детальної інформації.
  • Status: Субресурс status дозволяє оновлювати статус Podʼа. Зазвичай його використовують лише kubelet та інші системні контролери.
  • Binding: Субресурс binding дозволяє встановити spec.nodeName Podʼа за допомогою запиту Binding. Зазвичай його використовує лише планувальник.

Покоління Podʼа

  • Поле metadata.generation є унікальним. Воно автоматично встановлюється системою таким чином, що нові Podʼи мають значення metadata.generation, рівне 1, і кожне оновлення змінюваних полів у специфікації Podʼа збільшуватиме значення metadata.generation на 1.
СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.35
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.33 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate PodObservedGenerationTracking, Kubernetes ignores it but does not report any error.

  • observedGeneration — це поле, яке фіксується в розділі status обʼєкта Pod. kubelet встановлює status.observedGeneration, щоб повʼязати стан Podʼа з його поточним статусом. Поле status.observedGeneration Podʼа відображатиме metadata.generation Podʼа в момент, коли повідомляється про статус Podʼа.

Примітка:

Полем status.observedGeneration керує kubelet, і зовнішні контролери не повинні його змінювати.

Різні поля статусу можуть бути повʼязані або з metadata.generation поточного циклу синхронізації, або з metadata.generation попереднього циклу синхронізації. Ключова відмінність полягає в тому, чи зміна в spec відображається безпосередньо в status, чи є опосередкованим результатом запущеного процесу.

Безпосередні оновлення статусу

Для полів статусу, у яких безпосередньо відображається виділена специфікація, observedGeneration буде повʼязано з поточним metadata.generation (покоління N).

Ця поведінка застосовується до:

  • Статусу Resize: Статус операції зміни розміру ресурсу.
  • Виділених ресурсів: Ресурси, виділені Podʼу після зміни розміру.
  • Ефемерних контейнерів: Коли додається новий ефемерний контейнер, і він перебуває у стані Waiting.

Опосередковані оновлення статусу

Для полів статусу, які є опосередкованим результатом виконання специфікації, observedGeneration буде повʼязано з metadata.generation попереднього циклу синхронізації (покоління N-1).

Ця поведінка застосовується до:

  • Образу контейнера: ContainerStatus.ImageID показує образ з попереднього покоління, поки новий образ не буде завантажено, а контейнер не буде оновлено.
  • Фактичних ресурсів: Під час незавершеної зміни розміру фактичні ресурси, що використовуються, все ще належать запиту попереднього покоління.
  • Стану контейнера: Під час незавершеної зміни розміру стан контейнера з політикою, що вимагає перезапуску, відображає запит попереднього покоління.
  • activeDeadlineSeconds, terminationGracePeriodSeconds та deletionTimestamp: Вплив цих полів на статус Podʼа є результатом раніше отриманої специфікації.

Спільні ресурси та комунікація

Podʼи дають змогу контейнерам, що входять до їх складу, спільно використовувати дані та взаємодіяти між собою.

Зберігання в Podʼах

Pod може визначати набір спільних томів. Всі контейнери в Podʼі можуть отримати доступ до спільних томів, що дозволяє цим контейнерам спільно використовувати дані. Також томи дають змогу постійним даним у Podʼі зберегтися, якщо один із його контейнерів доведеться перезапустити. Дивіться розділ Зберігання для отримання додаткової інформації про те, як Kubernetes реалізує спільне зберігання та робить його доступним для Podʼів.

Мережеві можливості Podʼа

Кожному Podʼу присвоюється унікальна IP-адреса для кожного сімейства адрес. Кожен контейнер у Podʼі використовує спільний мережевий простір імен, що включає IP-адресу та мережеві порти. Всередині Podʼа (і тільки там) контейнери, що належать до Podʼа, можуть спілкуватися один з одним за допомогою localhost. Коли контейнери в Podʼі спілкуються із сутностями поза межами Podʼа, вони повинні координувати використання спільних мережевих ресурсів (таких як порти). Всередині Podʼа контейнери використовують спільну IP-адресу та простір портів і можуть знаходити один одного через localhost. Контейнери в Podʼі також можуть спілкуватися між собою, використовуючи стандартні засоби міжпроцесної комунікації, такі як семафори SystemV або спільну памʼять POSIX. Контейнери в різних Podʼах мають різні IP-адреси і не можуть спілкуватися за допомогою IPC на рівні ОС без спеціальної конфігурації. Контейнери, які хочуть взаємодіяти з контейнером, що працює в іншому Podʼі, можуть використовувати IP-мережу для спілкування.

Контейнери в межах Podʼа сприймають імʼя хоста системи як імʼя, що збігається з налаштованим name для Podʼа. Більше інформації про це можна знайти в розділі Мережа в кластері.

Налаштування безпеки Podʼів

Щоб встановити обмеження безпеки для Podʼів і контейнерів, використовуйте поле securityContext у специфікації Podʼа. Це поле дає вам можливість детально контролювати, що може робити Pod або окремі контейнери. Докладнішу інформацію див. у розділі Розширена конфігурація Podʼів.

Для базової конфігурації безпеки слід дотримуватися стандарту безпеки Podʼів Baseline та запускати контейнери з правами, відмінними від root. Ви можете налаштувати прості контексти безпеки:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: ["sh", "-c", "sleep 1h"]

Щоб дізнатися про розширені налаштування контексту безпеки, зокрема про можливості (capabilities), профілі seccomp та детальні параметри безпеки, перейдіть до розділу Концепції безпеки.

Запити та обмеження ресурсів

Коли ви визначаєте Pod, ви можете за бажанням вказати, скільки кожного ресурсу потрібно контейнеру. Найчастіше вказують CPU та памʼять (RAM).

Коли ви вказуєте запит ресурсу (request) для контейнерів у Podʼі, kube-scheduler використовує цю інформацію щоб визначити, на якому вузлі розмістити Pod. Коли ви вказуєте обмеження ресурсу (limit) для контейнера, kubelet забезпечує дотримання цих обмежень, щоб запущений контейнер не міг використовувати більше цього ресурсу, ніж встановлене вами обмеження.

Обмеження CPU застосовуються через тротлінг CPU. Коли контейнер наближається до свого обмеження CPU, ядро обмежує його доступ до CPU. Обмеження памʼяті застосовуються ядром через завершення процесів за нестачі памʼяті (OOM kills), коли контейнер перевищує своє обмеження.

Примітка:

Встановлення обмежень CPU повʼязане з компромісами. Обмеження CPU допомагають запобігти проблемам «шумного сусіда», коли одне робоче навантаження позбавляє ресурсів інші на тому ж вузлі. Це особливо важливо в багатокористувацьких середовищах. Однак обмеження CPU можуть призводити до тротлінгу навіть тоді, коли на вузлі є вільні ресурси CPU, що потенційно погіршує продуктивність робочих навантажень, чутливих до затримок. Рішення про встановлення обмежень CPU залежить від вашого середовища, характеристик робочого навантаження та вимог до ізоляції.

Детальнішу інформацію про одиниці ресурсів, механізми застосування обмежень та приклади конфігурації дивіться у розділі Керування ресурсами Podʼів та контейнерів.

Статичні Podʼи

Статичні Podʼи керуються безпосередньо демоном kubelet на конкретному вузлі, без спостереження за ними з боку API-сервера. У той час як більшістю Podʼів керує панель управління (наприклад, Deployment), для статичних Podʼів kubelet безпосередньо наглядає за кожним статичним Podʼом (та перезапускає його, якщо він зазнає збою).

Статичні Podʼи завжди привʼязані до одного kubelet на конкретному вузлі. Основне призначення статичних Podʼів — запуск самостійно розміщеної панелі управління: іншими словами, використання kubelet для нагляду за окремими компонентами панелі управління.

За докладнішою інформацією звертайтесь до розділу Статичні Podʼи.

Podʼи з кількома контейнерами

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

Podʼи в кластері Kubernetes використовуються двома основними способами:

  • Podʼи, що запускають один контейнер. Модель «один контейнер на Pod» є найпоширенішим сценарієм використання Kubernetes. У цьому випадку Pod можна розглядати як обгортку навколо одного контейнера; Kubernetes керує Podʼами, а не контейнерами безпосередньо.
  • Podʼи, що запускають кілька контейнерів, які мають працювати разом. Pod може інкапсулювати застосунок, який складається з кількох розміщених разом контейнерів, що тісно повʼязані та мають спільно використовувати ресурси. Ці розміщені разом контейнери утворюють єдину цілісну одиницю сервісу — наприклад, один контейнер надає публічний доступ до даних, збережених у спільному томі, тоді як окремий sidecar-контейнер оновлює ці файли. Pod обгортає ці контейнери, ресурси зберігання та ефемерну мережеву ідентичність в єдину одиницю.

Наприклад, у вас може бути контейнер, який виконує функції вебсервера для файлів у спільному томі, та окремий sidecar-контейнер, який оновлює ці файли з віддаленого джерела, як показано на цій діаграмі:

Діаграма створення Podʼа

Деякі Podʼи мають init-контейнери та контейнери застосунку. Стандартно init-контейнери запускаються та завершують роботу до запуску контейнерів застосунку.

У вас також можуть бути sidecar-контейнери, які надають допоміжні сервіси основному Podʼу застосунку (наприклад, service mesh).

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.33
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.33. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate SidecarContainers, Kubernetes ignores it but does not report any error.

Стандартно увімкнена функціональна можливість SidecarContainers дозволяє вказати restartPolicy: Always для init-контейнерів. Встановлення політики перезапуску Always гарантує, що контейнери, для яких ви її встановили, вважатимуться sidecar-контейнерами, що працюють протягом усього життєвого циклу Podʼа. Контейнери, які ви явно визначаєте як sidecar-контейнери, запускаються перед основним Podʼом застосунку та працюють, доки Pod не завершить роботу.

Проби контейнерів

Проба — це діагностика, яку kubelet періодично виконує для контейнера. Для виконання діагностики kubelet може використовувати різні дії:

  • ExecAction (виконується за допомогою середовища виконання контейнерів)
  • TCPSocketAction (перевіряється безпосередньо kubelet)
  • HTTPGetAction (перевіряється безпосередньо kubelet)

Ви можете дізнатися більше про проби в документації про життєвий цикл Podʼа.

Що далі

  • Дізнайтесь про життєвий цикл Podʼа.
  • Дізнайтесь про PodDisruptionBudget та як ви можете використовувати його для керування доступністю застосунку під час порушень.
  • Pod є ресурсом найвищого рівня в REST API Kubernetes. Визначення обʼєкта Pod детально описує цей обʼєкт.
  • Допис в блозі The Distributed System Toolkit: Patterns for Composite Containers пояснює типові конфігурації Podʼів з більш ніж одним контейнером.
  • Дізнайтесь про Обмеження топології розміщення Podʼів
  • Прочитайте про Розширену конфігурацію Podʼів, щоб дізнатися про цю тему докладніше. На цій сторінці висвітлюються аспекти конфігурації Podʼів, що виходять за межі основних положень, зокрема:
    • PriorityClasses
    • RuntimeClasses
    • розширені способи налаштування планування: того, як Kubernetes вирішує, на якому вузлі має працювати Pod.

Для розуміння контексту того, чому Kubernetes обгортає загальний API Pod іншими ресурсами (такими як StatefulSets або Deployments), ви можете ознайомитися з попередніми розробками, зокрема:

1.1 - Життєвий цикл Podʼа

Ця сторінка описує життєвий цикл Podʼа. Podʼи проходять визначений життєвий цикл, починаючи з фази Pending, переходячи до Running, якщо принаймні один з основних контейнерів успішно запускається, а потім до фази Succeeded або Failed, залежно від того, чи завершився будь-який контейнер у Podʼі зі збоєм.

Поки Pod працює, kubelet керує контейнерами та перетворює специфікацію Podʼа для середовища виконання контейнерів. Kubelet також керує виконанням проб, які відстежують справність вашого застосунку.

Podʼи, подібно до окремих контейнерів застосунків, вважаються відносно ефемерними (а не довговічними) сутностями. Podʼи створюються, отримують унікальний ідентифікатор (UID) і плануються до запуску на вузлах, де залишаються до завершення (відповідно до політики перезапуску) або видалення. Якщо вузол виходить з ладу, Podʼи, які працюють на ньому (або заплановані на нього), позначаються для видалення. Панель управління позначає Podʼи для вилучення після закінчення періоду очікування.

Час життя Podʼа

Поки Pod працює, kubelet може перезапускати контейнери, щоб усунути певні види несправностей. У межах Podʼа Kubernetes відстежує різні стани контейнера і визначає, які дії вжити, щоб Pod знову став справним. Це робиться в циклі опитування, який періодично узгоджує бажаний стан (специфікацію Podʼа) з фактичним станом запущених контейнерів.

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

Podʼи плануються лише один раз за час свого життя; призначення Podʼа на певний вузол називається привʼязкою, а процес вибору вузла — плануванням. Після того, як Pod було заплановано і привʼязано до вузла, Kubernetes намагається запустити цей Pod на цьому вузлі. Pod працює на цьому вузлі, доки не зупиниться або доки його не буде завершено; якщо Kubernetes не може запустити Pod на вибраному вузлі (наприклад, якщо вузол аварійно завершить роботу до запуску Podʼа), то цей конкретний Pod ніколи не запуститься.

Ви можете використати готовність Podʼів до планування, щоб затримати планування Podʼа, доки не буде видалено всі його шлюзи планування (scheduling gates). Наприклад, ви можете визначити набір Podʼів, але запустити планування лише після того, як всі Podʼи будуть створені.

Podʼи та відновлення після збоїв

Якщо один з контейнерів у Podʼі виходить з ладу, Kubernetes може спробувати перезапустити саме цей контейнер. Щоб дізнатися більше, прочитайте «Як Podʼи вирішують проблеми з контейнерами».

Однак Podʼи можуть вийти з ладу так, що кластер не зможе цього виправити, і в такому разі Kubernetes не намагається далі відновлювати Pod; натомість Kubernetes видаляє Pod і покладається на інші компоненти, які забезпечують автоматичне відновлення.

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

У Kubernetes використовується абстракція вищого рівня, яка називається контролер, яка виконує роботу з керування відносно одноразовими екземплярами Podʼів.

Конкретний Pod (визначений UID) ніколи не «переплановується» на інший вузол; натомість цей Pod може бути замінений новим, майже ідентичним Podʼом. Якщо ви створюєте Pod-замінник, він може навіть мати ту саму назву (як у .metadata.name), що й старий Pod, але замінник матиме інший .metadata.uid, ніж старий Pod.

Kubernetes не гарантує, що заміну наявного Podʼа буде заплановано на той самий вузол, де був старий Pod, який замінюється.

Повʼязаний час життя

Коли говорять, що щось має такий самий час життя, як і Pod, наприклад том, це означає, що ця річ існує стільки часу, скільки існує цей конкретний Pod (саме з цим UID). Якщо цей Pod буде видалений з будь-якої причини, і навіть якщо буде створений ідентичний замінник, повʼязана річ (у цьому прикладі — том) також буде знищена і створена знову.

Багатоконтейнерний Pod, який містить sidecar-контейнер для завантаження файлів і вебсервер. Pod використовує ефемерний том emptyDir як спільне сховище для контейнерів.

Малюнок 1.

Багатоконтейнерний Pod, який містить sidecar-контейнер для завантаження файлів і вебсервер. Pod використовує ефемерний том emptyDir як спільне сховище для контейнерів.

Фаза Podʼа

Поле status Podʼа — це обʼєкт PodStatus, який має поле phase.

Фаза Podʼа — це простий, високорівневий підсумок того, на якому етапі свого життєвого циклу перебуває Pod. Фаза не призначена ні бути всеосяжним зведенням спостережень за станом контейнера чи Podʼа, ні бути всеосяжним скінченним автоматом.

Кількість і значення фаз Podʼа суворо контролюються. Окрім того, що задокументовано тут, не слід нічого припускати про Podʼи з певним значенням phase.

Ось можливі значення для phase:

ЗначенняОпис
PendingPod прийнято кластером Kubernetes, але один чи кілька контейнерів ще не налаштовано й не підготовлено до запуску. Це включає час, який Pod витрачає на очікування планування, а також час, який витрачається на завантаження образів контейнерів з мережі.
RunningPod привʼязаний до вузла, і всі контейнери створені. Принаймні один контейнер все ще працює або перебуває у процесі запуску чи перезапуску.
SucceededВсі контейнери в Podʼі завершили роботу успішно і не будуть перезапущені.
FailedВсі контейнери в Podʼі завершили роботу, і принаймні один контейнер завершився зі збоєм. Іншими словами, контейнер вийшов зі статусом, відмінним від нуля, або його роботу завершила система, і контейнер не налаштований на автоматичний перезапуск.
UnknownЗ якоїсь причини не вдалося отримати стан Podʼа. Ця фаза, як правило, виникає через помилку у звʼязку з вузлом, де повинен виконуватися Pod.

Примітка:

Якщо Podʼу раз у раз не вдається запуститися, у полі Status деяких команд kubectl може зʼявитися CrashLoopBackOff. Аналогічно, під час видалення Podʼа у полі Status деяких команд kubectl може зʼявитися Terminating.

Не плутайте Status, поле відображення kubectl, призначене для зручності користувача, з phase Podʼа. Фаза Podʼа є явною частиною моделі даних Kubernetes і API Pod.

  NAMESPACE               NAME               READY   STATUS             RESTARTS   AGE
  alessandras-namespace   alessandras-pod    0/1     CrashLoopBackOff   200        2d9h

Pod отримує час на коректне завершення, який стандартно становить 30 секунд. Ви можете використовувати прапорець --force для примусового завершення роботи Podʼа.

Починаючи з Kubernetes 1.27, kubelet переводить видалені Podʼи в термінальну фазу (Failed або Succeeded залежно від статусів завершення роботи контейнерів Podʼа) перед їх видаленням з API-сервера, за винятком двох випадків:

Якщо вузол виходить з ладу або втрачає звʼязок з рештою кластера, Kubernetes застосовує політику встановлення phase всіх Podʼів на втраченому вузлі у Failed.

Стани контейнера

Окрім фази Podʼа загалом, Kubernetes відстежує стан кожного контейнера всередині Podʼа. Ви можете використовувати хуки життєвого циклу контейнера, щоб запускати події на певних етапах життєвого циклу контейнера.

Як тільки планувальник призначає Pod вузлу, kubelet починає створювати контейнери для цього Podʼа, використовуючи середовище виконання контейнерів. Існує три можливі стани контейнера: Waiting (Очікування), Running (Виконання) та Terminated (Завершено).

Щоб перевірити стан контейнерів Podʼа, ви можете використовувати kubectl describe pod <name-of-pod>. Вивід показує стан для кожного контейнера в межах цього Podʼа.

Кожен стан має конкретне значення:

Waiting

Якщо контейнер не перебуває ні в стані Running, ні в стані Terminated, то він перебуває в стані Waiting. Контейнер у стані Waiting усе ще виконує операції, необхідні для завершення запуску: наприклад, завантажує образ контейнера з реєстру образів контейнерів або застосовує дані Secret. Коли ви використовуєте kubectl для опитування Podʼа із контейнером, який перебуває в стані Waiting, ви також бачите поле Reason, яке стисло пояснює, чому контейнер перебуває в цьому стані.

Running

Статус Running вказує на те, що виконання контейнера відбувається без проблем. Якщо було налаштовано хук postStart, він уже виконався і завершився. Коли ви використовуєте kubectl для опитування Podʼа із контейнером, який перебуває в стані Running, ви також бачите інформацію про те, коли контейнер перейшов у стан Running.

Terminated

Контейнер у стані Terminated розпочав виконання і потім або виконався до кінця, або зазнав збою з певної причини. Коли ви використовуєте kubectl для опитування Podʼа із контейнером, який перебуває в стані Terminated, ви бачите причину, код виходу та час початку та завершення періоду виконання цього контейнера.

Якщо у контейнера є налаштований хук preStop, цей хук запускається перед тим, як контейнер перейде в стан Terminated.

Як Podʼи вирішують проблеми з контейнерами

Kubernetes обробляє збої контейнерів у межах Podʼів за допомогою політики restartPolicy, визначеної в spec Podʼа. Ця політика визначає, як Kubernetes реагує на завершення контейнерів через помилки або з інших причин, у такій послідовності:

  1. Початковий збій: Kubernetes намагається негайно перезапустити контейнер на основі restartPolicy Podʼа.
  2. Повторні збої: Після початкового збою Kubernetes застосовує експоненційну затримку для наступних перезапусків, описану в restartPolicy. Це запобігає перевантаженню системи швидкими повторними спробами перезапуску.
  3. Стан CrashLoopBackOff: Це означає, що для певного контейнера зараз діє механізм затримки, бо цей контейнер перебуває в циклі збоїв: він раз у раз зазнає збою та перезапускається.
  4. Скидання затримки: Якщо контейнер успішно працює протягом певного часу (наприклад, 10 хвилин), Kubernetes скидає затримку, розглядаючи будь-який новий збій як перший.

На практиці, CrashLoopBackOff — це стан або подія, яку можна помітити у виводі команди kubectl під час отримання опису або перегляду списку Podʼів, коли контейнер в Podʼі не запускається належним чином, а потім безперервно намагається запуститися, але безуспішно.

Іншими словами, коли контейнер потрапляє в цикл збоїв, Kubernetes застосовує експоненційну затримку, про яку було згадано в політиці перезапуску контейнера. Цей механізм не дає несправному контейнеру перевантажувати систему безперервними невдалими спробами запуску.

CrashLoopBackOff може бути спричинений такими проблемами:

  • Помилки застосунків, які призводять до завершення контейнера.
  • Помилки конфігурації, такі як неправильні змінні середовища або відсутність конфігураційних файлів.
  • Обмеження ресурсів, коли контейнеру може бракувати памʼяті або CPU для правильного запуску.
  • Невдалі перевірки справності, якщо застосунок не починає обслуговувати запити у передбачений час.
  • Проби життєздатності або проби запуску контейнера, що повертають результат Failure, як зазначено в розділі про проби.

Щоб розібратися у причинах проблеми CrashLoopBackOff, користувач може:

  1. Перевірити логи: Використовуйте kubectl logs <name-of-pod>, щоб перевірити логи контейнера. Часто це найпряміший спосіб діагностики проблеми, що спричиняє збої.
  2. Перевірити події: Використовуйте kubectl describe pod <name-of-pod> для перегляду подій для Podʼа, які можуть надати підказки про проблеми конфігурації або ресурсів.
  3. Перевірити конфігурацію: Переконайтеся, що конфігурація Podʼа, включаючи змінні середовища та змонтовані томи, є правильною і що всі необхідні зовнішні ресурси доступні.
  4. Перевірити обмеження ресурсів: Переконайтеся, що контейнеру виділено достатньо CPU та памʼяті. Іноді збільшення ресурсів у визначенні Podʼа може вирішити проблему.
  5. Налагодити застосунок: У коді застосунку можуть бути помилки або неправильні налаштування. Запуск цього образу контейнера локально або в середовищі розробки може допомогти діагностувати проблеми, специфічні для застосунку.

Перезапуск контейнера

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

Перезапуск контейнера та відмовостійкість

Проєкт Kubernetes рекомендує дотримуватися принципів cloud native, включаючи відмовостійкий дизайн, який враховує неоголошені або довільні перезапуски. Ви можете досягти цього або завершивши Pod зі збоєм і покладаючись на автоматичну заміну, або спроєктувавши відмовостійкість на рівні контейнера. Обидва підходи допомагають забезпечити доступність вашого робочого навантаження загалом, незважаючи на часткові збої.

Політика перезапуску контейнера на рівні Podʼа

spec Podʼа має поле restartPolicy із можливими значеннями Always, OnFailure та Never. Стандартне значення — Always.

restartPolicy для Podʼа застосовується до контейнерів застосунків в Podʼі та до звичайних init-контейнерів. Sidecar-контейнери не враховують поле restartPolicy на рівні Podʼа: у Kubernetes sidecar визначається як запис всередині initContainers, у якого restartPolicy на рівні контейнера встановлено в Always. Для init-контейнерів, які завершують роботу з помилкою, kubelet виконує їх перезапуск, якщо restartPolicy на рівні Podʼа — OnFailure або Always:

  • Always: автоматично перезапускає контейнер після будь-якого завершення.
  • OnFailure: перезапускає контейнер тільки після його завершення з помилкою (код виходу відмінний від нуля).
  • Never: ніколи автоматично не перезапускає контейнер, що завершив роботу.
Порівняння поведінки перезапуску

Наступна таблиця показує, як контейнери поводяться за різних політик перезапуску та кодів виходу:

Код виходуrestartPolicy: AlwaysrestartPolicy: OnFailurerestartPolicy: NeverSidecar-контейнери
0 (Успіх)ПерезапускаєтьсяНе перезапускаєтьсяНе перезапускаєтьсяЗавжди перезапускається
Ненульовий (Збій)ПерезапускаєтьсяПерезапускаєтьсяНе перезапускаєтьсяЗавжди перезапускається

Примітка:

Поведінка перезапуску особливо важлива під час вибору між Deployments та Jobs:

  • Deployments зазвичай використовують restartPolicy: Always (єдине дозволене значення) для безперервної роботи застосунків.
  • Jobs зазвичай використовують restartPolicy: OnFailure або restartPolicy: Never для належного оброблення завдань пакетної обробки.
  • Sidecar-контейнери є init-контейнерами, які завжди перезапускаються незалежно від restartPolicy Podʼа, оскільки вони мають власну політику перезапуску на рівні контейнера restartPolicy: Always.
Приклади сценаріїв

Ось конкретні приклади, що демонструють різну поведінку перезапуску:

Приклад 1: Вебсервер з restartPolicy: Always (типово для Deployments)

apiVersion: v1
kind: Pod
metadata:
  name: web-server
spec:
  restartPolicy: Always  # Контейнер перезапускається незалежно від коду виходу
  containers:
  - name: nginx
    image: nginx:1.14.2
    # Якщо цей контейнер аварійно завершить роботу або завершиться з будь-якої причини, його буде перезапущено

Приклад 2: Завдання пакетної обробки з restartPolicy: OnFailure

apiVersion: batch/v1
kind: Job
metadata:
  name: data-processor
spec:
  template:
    spec:
      restartPolicy: OnFailure  # Перезапускається лише за ненульового коду виходу
      containers:
      - name: processor
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Processing data..."; exit 0']
        # Код виходу 0: Job успішно завершено, перезапуск не відбувається
        # Код виходу 1+: Контейнер перезапускається для повторної спроби завдання

Приклад 3: Одноразове завдання з restartPolicy: Never

apiVersion: v1
kind: Pod
metadata:
  name: migration-task
spec:
  restartPolicy: Never  # Ніколи не перезапускається, незалежно від коду виходу
  containers:
  - name: migrate
    image: busybox:1.28
    command: ['sh', '-c', 'echo "Running migration..."; exit 1']
    # Навіть із кодом виходу 1 (збій) контейнер не буде перезапущено
    # Pod залишиться в стані Failed
Sidecar-контейнери та політики перезапуску

Sidecar-контейнери мають особливу поведінку перезапуску, яка відрізняється від звичайних контейнерів застосунків:

  • Sidecar-контейнери ігнорують restartPolicy на рівні Podʼа: Вони використовують власне поле restartPolicy на рівні контейнера, яке завжди встановлено в Always
  • Незалежний життєвий цикл: Sidecar-контейнери можуть перезапускатися незалежно від основного контейнера застосунку
  • Постійна робота: Sidecar-контейнери продовжують працювати протягом усього часу життя Podʼа, надаючи допоміжні сервіси

Приклад: Pod із sidecar-контейнером

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  restartPolicy: OnFailure  # Застосовується лише до основного контейнера
  initContainers:
  - name: logging-sidecar    # Це sidecar-контейнер
    image: fluent/fluent-bit:1.8
    restartPolicy: Always    # Sidecar завжди перезапускається незалежно від коду виходу
    # Надає сервіси логування протягом усього часу життя Podʼа
  containers:
  - name: main-app          # Дотримується політики перезапуску на рівні Podʼа
    image: nginx:1.14.2
    # Перезапускається лише у разі помилки (ненульовий код виходу) через політику OnFailure Podʼа

Примітка:

Хоча основний контейнер застосунку дотримується політики restartPolicy: OnFailure на рівні Podʼа, sidecar-контейнер буде перезапущений незалежно від його коду виходу, оскільки sidecar-контейнери завжди мають restartPolicy: Always на рівні контейнера.

Коли kubelet обробляє перезапуск контейнера згідно з налаштованою політикою перезапуску, це стосується лише перезапусків, які призводять до заміни контейнерів всередині того ж Podʼа та на тому ж вузлі. Після завершення контейнерів у Podʼі kubelet перезапускає їх із затримкою, що зростає експоненційно (10 с, 20 с, 40 с, …), і обмеженою пʼятьма хвилинами (300 секунд). Якщо контейнер виконується протягом 10 хвилин без проблем, kubelet скидає таймер затримки перезапуску для цього контейнера. У розділі Sidecar-контейнери та життєвий цикл Podʼа пояснюється поведінка init containers, коли для них вказано поле restartPolicy.

Політика та правила перезапуску окремих контейнерів

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.35; (стандартно увімкнено)

Якщо у вашому кластері увімкнено функціональну можливість ContainerRestartRules, ви можете вказати restartPolicy та restartPolicyRules для окремих контейнерів, щоб перевизначити політику перезапуску Podʼа. Політика перезапуску контейнера та правила застосовуються до контейнерів застосунків в Podʼі та до звичайних init-контейнерів.

Нативний для Kubernetes sidecar-контейнер має restartPolicy на рівні контейнера, встановлену в Always.

Перезапуски контейнерів відбуватимуться з такою ж експоненційною затримкою, як і за політики перезапуску Podʼа, описаної вище. Підтримувані політики перезапуску контейнерів:

  • Always: автоматично перезапускає контейнер після будь-якого завершення.
  • OnFailure: перезапускає контейнер тільки після його завершення з помилкою (код виходу відмінний від нуля).
  • Never: ніколи автоматично не перезапускає контейнер, що завершив роботу.

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

Наприклад, Pod з політикою перезапуску OnFailure, який має контейнер try-once. Це дозволяє Podʼу перезапускати лише певні контейнери:

apiVersion: v1
kind: Pod
metadata:
  name: on-failure-pod
spec:
  restartPolicy: OnFailure
  containers:
  - name: try-once-container    # Цей контейнер буде запущено лише один раз, оскільки політика перезапуску — Never.
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'echo "Only running once" && sleep 10 && exit 1']
    restartPolicy: Never
  - name: on-failure-container  # Цей контейнер буде перезапущено у разі збою.
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'echo "Keep restarting" && sleep 1800 && exit 1']

Pod з політикою перезапуску Always, який має init-контейнер, що виконується лише один раз. Якщо init-контейнер зазнає збою, Pod зазнає збою. Це дозволяє Podʼу завершитися зі збоєм, якщо ініціалізація не вдалася, але продовжувати працювати після успішної ініціалізації:

apiVersion: v1
kind: Pod
metadata:
  name: fail-pod-if-init-fails
spec:
  restartPolicy: Always
  initContainers:
  - name: init-once      # Цей init-контейнер спробує запуститися лише один раз. Якщо він зазнає збою, Pod зазнає збою.
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'echo "Failing initialization" && sleep 10 && exit 1']
    restartPolicy: Never
  containers:
  - name: main-container # Цей контейнер завжди перезапускатиметься після успішної ініціалізації.
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'sleep 1800 && exit 0']

Pod з політикою перезапуску Never, який має контейнер, що ігнорує одні коди виходу та перезапускається на конкретних кодах виходу. Це корисно для розрізнення між помилками, після яких контейнер можна перезапустити, і тими, які не дозволяють зробити перезапуск:

apiVersion: v1
kind: Pod
metadata:
  name: restart-on-exit-codes
spec:
  restartPolicy: Never
  containers:
  - name: restart-on-exit-codes
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'sleep 60 && exit 0']
    restartPolicy: Never     # Політика перезапуску контейнера повинна бути вказана, якщо вказані правила
    restartPolicyRules:      # Перезапускати контейнер, лише якщо він завершується з кодом 42
    - action: Restart
      exitCodes:
        operator: In
        values: [42]

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

Перезапуск усіх контейнерів

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.36; (стандартно увімкнено)

Якщо у вашому кластері увімкнено функціональну можливість RestartAllContainersOnContainerExits, ви можете вказати RestartAllContainers як дію в restartPolicyRules на рівні контейнера. Коли завершення контейнера відповідає правилу з цією дією, весь Pod завершується і перезапускається на місці.

Такий перезапуск «на місці» є ефективнішим способом скидання стану Podʼа порівняно з повним видаленням і повторним створенням. Це особливо цінно для робочих навантажень, де перепланування є дорогим, наприклад, для пакетних завдань або завдань навчання AI/ML.

Як працюють перезапуски Podʼів на місці

Коли спрацьовує дія RestartAllContainers, kubelet виконує такі кроки:

  1. Швидке завершення: Усі запущені контейнери в Podʼі завершуються. Налаштований параметр terminationGracePeriodSeconds не враховується, а налаштовані хуки preStop не виконуються. Це забезпечує швидке вимкнення.
  2. Збереження ресурсів Podʼа: Основні ресурси Podʼа зберігаються:
    • UID Podʼа, IP-адреса та мережевий простір імен
    • Пісочниця Podʼа та будь-які підключені пристрої
    • Усі томи, включаючи томи emptyDir та змонтовані томи
  3. Оновлення статусу Podʼа: Статус Podʼа оновлюється: стан PodRestartInPlace встановлюється в True. Це робить процес перезапуску спостережуваним.
  4. Повна послідовність перезапуску: Після завершення роботи всіх контейнерів стан PodRestartInPlace встановлюється в False, і Pod починає стандартний процес запуску:
    • Init-контейнери запускаються повторно по черзі.
    • Запускаються sidecar-контейнери та звичайні контейнери.

Ключовим аспектом цієї можливості є те, що всі контейнери перезапускаються, включаючи ті, які раніше успішно завершилися або зазнали збою. Дія RestartAllContainers перевизначає будь-яку налаштовану restartPolicy на рівні контейнера або Podʼа.

Цей механізм корисний у сценаріях, коли всім контейнерам потрібно почати з чистого аркуша, наприклад:

  • Коли init-контейнер налаштовує середовище, яке може бути пошкоджено, ця можливість забезпечує повторне виконання процесу налаштування.
  • Sidecar-контейнер може контролювати стан основного застосунку та запускати повний перезапуск Podʼа, якщо застосунок переходить у стан, з якого неможливо відновити роботу.

Розглянемо робоче навантаження, де sidecar-спостерігач відповідає за перезапуск основного застосунку з відомого справного стану, якщо той натрапляє на помилку. Спостерігач може завершитися з певним кодом, щоб ініціювати повний перезапуск робочого Podʼа на місці.

apiVersion: v1
kind: Pod
metadata:
  name: ml-worker
spec:
  restartPolicy: Never # The pod itself should not restart unless explicitly told to.
  initContainers:
  - name: setup-environment
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'echo "Setting up environment"']
    # This init container runs once to prepare the environment.
    # It will run again after a RestartAllContainers action.
  - name: watcher-sidecar
    image: registry.k8s.io/busybox:1.27.2
    # In a real-world scenario, this would be a dedicated watcher image.
    # This command simulates the watcher exiting with a special code.
    command: ['sh', '-c', 'sleep 60; exit 88']
    restartPolicy: Always
    restartPolicyRules:
    - action: RestartAllContainers
      exitCodes:
        # Exit code 88 triggers a full pod restart.
        operator: In
        values: [88]
  containers:
  - name: main-application
    image: registry.k8s.io/busybox:1.27.2
    command: ['sh', '-c', 'echo "Application is running"; sleep 3600']

У цьому прикладі:

  • Загальна політика перезапуску Podʼа — Never.
  • watcher-sidecar виконує команду, а потім завершується з кодом 88.
  • Код завершення відповідає правилу, що запускає дію RestartAllContainers.
  • Потім весь Pod, включаючи init-контейнер setup-environment і контейнер main-application, перезапускається на місці. Pod зберігає свій UID, пісочницю, IP-адресу та томи.

Зменшена затримка перезапуску контейнера

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.33; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the ReduceDefaultCrashLoopBackOffDecay feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

З увімкненою альфа-функціональною можливістю ReduceDefaultCrashLoopBackOffDecay затримка повторних спроб запуску контейнера у вашому кластері починатиметься з 1 с (замість 10 с) і експоненційно зростатиме у 2 рази з кожним перезапуском до максимальної затримки 60 с (замість 300 с, тобто 5 хвилин).

Якщо ви використовуєте цю можливість з альфа-можливістю KubeletCrashLoopBackOffMax (описано нижче), окремі вузли можуть мати різні значення максимальної затримки.

Налаштовувана затримка перезапуску контейнера

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.35; (стандартно увімкнено)

З увімкненою функціональною можливістю KubeletCrashLoopBackOffMax ви можете змінити максимальну затримку між повторними спробами запуску контейнера, яка стандартно становить 300 секунд (5 хвилин). Ця конфігурація встановлюється для кожного вузла за допомогою конфігурації kubelet. У вашій конфігурації kubelet у полі crashLoopBackOff встановіть значення поля maxContainerRestartPeriod між "1s" і "300s". Як описано вище у Політиці перезапуску контейнерів, затримки на цьому вузлі все одно починатимуться з 10 секунд і збільшуватимуться експоненційно у 2 рази з кожним перезапуском, але тепер вони будуть обмежені вашим налаштованим максимумом. Якщо значення maxContainerRestartPeriod, яке ви налаштували, менше початкового стандартного значення у 10 секунд, початкову затримку буде встановлено на налаштоване максимальне значення.

Дивіться такі приклади налаштування kubelet:

# затримки перезапуску контейнерів починаються з 10 секунд і збільшуються
# у 2 рази з кожним перезапуском, максимум до 100 с
kind: KubeletConfiguration
crashLoopBackOff:
    maxContainerRestartPeriod: "100s"
# затримки між перезапусками контейнера завжди будуть дорівнювати 2 с
kind: KubeletConfiguration
crashLoopBackOff:
    maxContainerRestartPeriod: "2s"

Якщо ви використовуєте цю можливість разом з альфа-можливістю ReduceDefaultCrashLoopBackOffDecay (описано вище), стандартні значення кластера для початкової та максимальної затримки будуть уже не 10 і 300 секунд, а 1 і 60 секунд. Конфігурація для кожного вузла має пріоритет над стандартними значеннями, встановленими ReduceDefaultCrashLoopBackOffDecay, навіть якщо це призведе до того, що вузол матиме довшу максимальну затримку, ніж інші вузли у кластері.

Стани Podʼа

Pod має PodStatus, який містить масив PodConditions, через які Pod пройшов або не пройшов. Kubelet керує такими PodConditions:

  • PodScheduled: Pod заплановано на вузол.
  • PodReadyToStartContainers: пісочницю Podʼа успішно створено, мережу налаштовано, томи зберігання змонтовано, а будь-які динамічні ресурси (якщо їх запитано) виділено.
  • ContainersReady: всі контейнери в Podʼі готові.
  • Initialized: всі init-контейнери успішно завершили виконання.
  • Ready: Pod може обслуговувати запити і його слід додати до пулів балансування навантаження всіх відповідних Services.
  • DisruptionTarget: Pod скоро буде завершено через порушення (наприклад, витіснення, виселення або збір сміття).
  • PodResizePending: було запитано зміну розміру Podʼа, але її неможливо застосувати. Дивіться Статус зміни розміру Podʼа.
  • PodResizeInProgress: Pod перебуває в процесі зміни розміру. Дивіться Статус зміни розміру Podʼа.
Назва поляОпис
typeНазва цього стану Podʼа.
statusВказує, чи застосовується цей стан, з можливими значеннями "True", "False" або "Unknown".
lastProbeTimeМітка часу останньої перевірки стану Podʼа.
lastTransitionTimeМітка часу останнього переходу Podʼа з одного статусу в інший.
reasonМашиночитаний текст у форматі UpperCamelCase, який вказує причину останнього переходу стану.
messageЗрозуміле людині повідомлення з подробицями щодо останнього переходу статусу.

Готовність Podʼа

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.14

Ваш застосунок може внести додатковий зворотний звʼязок або сигнали в PodStatus: готовність Podʼа. Щоб використовувати це, встановіть readinessGates в spec Podʼа, щоб вказати список додаткових станів, які kubelet оцінює для визначення готовності Podʼа.

Шлюзи готовності (readiness gates) визначаються поточним станом полів status.condition Podʼа. Якщо Kubernetes не може знайти такий стан у полі status.conditions Podʼа, статус цього стану стандартно вважається "False".

Наприклад:

kind: Pod
...
spec:
  readinessGates:
    - conditionType: "www.example.com/feature-1"
status:
  conditions:
    - type: Ready                              # вбудований стан Podʼа
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
    - type: "www.example.com/feature-1"        # додатковий стан Podʼа
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
  containerStatuses:
    - containerID: docker://abcd...
      ready: true
...

Стани Podʼа, які ви додаєте, повинні мати назви, що відповідають формату ключа міток Kubernetes.

Статус для готовності Podʼа

Команда kubectl patch не підтримує зміну статусу обʼєкта накладанням патчів. Щоб встановити ці status.conditions для Podʼа, застосунки та оператори повинні використовувати дію PATCH. Ви можете використовувати клієнтську бібліотеку Kubernetes для написання коду, який встановлює власні стани Podʼа для готовності Podʼа.

Pod, який використовує власні стани, оцінюється як готовий лише тоді, коли істинні обидва такі твердження:

  • Всі контейнери в Podʼі готові.
  • Усі стани, вказані в readinessGates, мають значення True.

Коли контейнери Podʼа перебувають у стані Ready, але принаймні один власний стан відсутній або має значення False, kubelet встановлює стан Podʼа в ContainersReady.

Готовність Podʼа до запуску контейнерів

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.37

Примітка:

На ранніх етапах розробки цей стан називали PodHasNetwork.

Після того, як Pod заплановано на вузол, kubelet має його допустити, а всі необхідні томи зберігання мають бути змонтовані. Щойно ці фази завершаться, kubelet працює із середовищем виконання контейнерів (використовуючи Container Runtime Interface (CRI)), щоб налаштувати пісочницю середовища виконання та мережу для Podʼа. Якщо Pod використовує Динамічне виділення ресурсів, ці ресурси також виділяються під час цієї фази. Стан PodReadyToStartContainers додається до поля status.conditions Podʼа.

Kubelet встановлює цей стан в False, коли виявляє, що Pod не має пісочниці середовища виконання з налаштованою мережею. Це трапляється в таких випадках:

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

Після створення пісочниці, налаштування мережі, монтування томів та (якщо запитано) динамічного виділення ресурсів kubelet встановлює стан PodReadyToStartContainers в True. Завантаження образу та створення контейнера відбуваються після цього.

Для Podʼа з init-контейнерами kubelet встановлює стан Initialized в True після успішного завершення init-контейнерів (що відбувається після успішного створення пісочниці та налаштування мережі втулком середовища виконання). Для Podʼа без init-контейнерів kubelet встановлює стан Initialized в True перед початком створення пісочниці та налаштування мережі.

Зміна розміру Podʼів

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.35
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate InPlacePodVerticalScaling, Kubernetes ignores it but does not report any error.

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.36; (стандартно увімкнено)

Kubernetes підтримує зміну ресурсів CPU та памʼяті, виділених для Podʼів, після їх створення. (Для інших ресурсів інфраструктури потрібно використовувати інші методи, специфічні для цих ресурсів.) Існує два основні підходи до зміни розміру CPU та памʼяті:

Зміна розміру Podʼа на місці

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

Якщо ви вказали ресурси на рівні Podʼа, ви також можете змінювати їх на місці. Для отримання додаткової інформації див. Зміна розміру CPU та памʼяті, призначених Podʼам.

Щоб виконати зміну розміру на місці, оновіть бажаний стан Podʼа за допомогою субресурсу /resize. Kubelet спробує застосувати нові значення ресурсів до контейнерів, що працюють. Стани Podʼа PodResizePending та PodResizeInProgress (описані в розділі Стани Podʼа) вказують на статус операції зміни розміру. Для отримання додаткової інформації про статус зміни розміру див. Статус зміни розміру контейнера.

Основні моменти, які слід враховувати під час зміни розміру на місці:

  • На місці можна змінювати розмір лише ресурсів CPU та памʼяті.
  • Клас якості обслуговування (QoS) Podʼа визначається під час створення і не може бути змінений шляхом зміни розміру.
  • Ви можете налаштувати, чи потрібно перезапускати контейнер для зміни розміру, використовуючи resizePolicy у специфікації контейнера.

Детальні інструкції щодо зміни розміру на місці див. Зміна розміру CPU та памʼяті, призначених контейнерам.

Зміна розміру шляхом запуску Podʼів-замінників

Більш cloud native підхід до зміни ресурсів Podʼа полягає у використанні ресурсу робочого навантаження, який ним керує (наприклад, Deployment або StatefulSet). Коли ви оновлюєте специфікації ресурсів у шаблоні Podʼа, контролер робочого навантаження створює нові Podʼи з оновленими ресурсами та завершує старі Podʼи відповідно до своєї стратегії оновлення.

Цей підхід:

  • Працює з будь-якою версією Kubernetes.
  • Може змінювати будь-яку специфікацію Podʼа, а не тільки ресурси.
  • Призводить до заміни Podʼа, тому вам слід спроєктувати робоче навантаження таким чином, щоб воно могло обробляти заплановані порушення. Розгляньте можливість використання PodDisruptionBudget для контролю доступності.
  • Вимагає, щоб вашими Podʼами керував ресурс робочого навантаження.

Ви також можете використовувати VerticalPodAutoscaler для автоматичного керування рекомендаціями та оновленнями ресурсів Podʼів.

Проби контейнерів

Kubernetes дозволяє визначати проби для безперервного моніторингу стану контейнерів у Podʼі. Проба — це діагностика, яку періодично виконує kubelet для контейнера. Для виконання діагностики kubelet або виконує код всередині контейнера, або виконує мережевий запит.

На основі результатів проб Kubernetes може перезапускати несправні контейнери або припиняти надсилання трафіку до контейнерів, які не готові.

Kubelet може за бажанням виконувати три типи проб для запущених контейнерів і реагувати на них, кожен із цих типів має своє призначення. Для механізмів проб (exec, grpc, httpGet, tcpSocket), полів конфігурації та детальних рекомендацій щодо використання дивіться Проби життєздатності, готовності та запуску.

Проба запуску

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

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

Якщо проба запуску не вдається, kubelet завершує контейнер, і до контейнера застосовується його політика перезапуску.

Проба життєздатності

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

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

Проба готовності

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

Якщо проба готовності повертає невдалий результат, контролер EndpointSlice видаляє IP-адресу Podʼа з EndpointSlices усіх Services, які відповідають Podʼу.

Проби готовності виконуються в контейнері протягом усього його життєвого циклу.

Завершення роботи Podʼів

Оскільки Podʼи представляють процеси, які виконуються на вузлах кластера, важливо дозволити цим процесам коректно завершувати роботу, коли вони більше не потрібні (а не зупиняти їх раптово сигналом KILL, не даючи можливості прибрати за собою).

Мета дизайну полягає в тому, щоб ви могли запитувати видалення і знати, коли процеси завершуються, а також мати можливість гарантувати, що видалення врешті-решт завершиться. Коли ви запитуєте видалення Podʼа, кластер реєструє та відстежує призначений період коректного завершення до того, як буде дозволено примусово знищити Pod. Завдяки цьому відстеженню примусового вимкнення kubelet намагається виконати коректне вимкнення.

Зазвичай під час такого коректного завершення роботи Podʼа kubelet надсилає запити до середовища виконання контейнерів, щоб спробувати зупинити контейнери в Podʼі, спочатку надсилаючи сигнал TERM (також відомий як SIGTERM) основному процесу в кожному контейнері з тайм-аутом періоду коректного завершення. Запити на зупинку контейнерів обробляються середовищем виконання контейнерів асинхронно. Порядок обробки цих запитів не гарантується. Багато середовищ виконання контейнерів враховують значення STOPSIGNAL, визначене в образі контейнера і, якщо воно відрізняється, надсилають значення STOPSIGNAL, визначене в образі контейнера, замість TERM. Після закінчення періоду коректного завершення сигнал KILL надсилається всім залишковим процесам, а потім Pod видаляється з API-сервера. Якщо kubelet або сервіс керування середовищем виконання контейнерів перезапускається під час очікування завершення процесів, кластер повторює спробу спочатку, включаючи повний початковий період коректного завершення.

Сигнали зупинки

Сигнал зупинки, який використовується для завершення роботи контейнера, може бути визначено в образі контейнера за допомогою інструкції STOPSIGNAL. Якщо в образі контейнера не визначено жодного сигналу зупинки, для завершення роботи контейнера буде використано стандартний сигнал середовища виконання контейнерів (SIGTERM як для containerd, так і для CRI-O).

Визначення власних сигналів зупинки

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.33; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the ContainerStopSignals feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Якщо увімкнено функціональну можливість ContainerStopSignals, ви можете налаштувати власний сигнал зупинки для ваших контейнерів з життєвого циклу контейнера. Щоб визначати сигнали зупинки в життєвому циклі контейнера, поле spec.os.name Podʼа має бути заданим. Перелік допустимих сигналів залежить від ОС, на яку заплановано Pod. Для Podʼів, запланованих на вузли Windows, ми підтримуємо тільки SIGTERM і SIGKILL як допустимі сигнали.

Ось приклад специфікації Podʼа, що визначає власний сигнал зупинки:

spec:
  os:
    name: linux
  containers:
    - name: my-container
      image: container-image:latest
      lifecycle:
        stopSignal: SIGUSR1

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

Порядок завершення роботи Podʼа

Порядок завершення роботи Podʼа на прикладі:

  1. Ви використовуєте інструмент kubectl, щоб вручну видалити певний Pod, зі стандартним періодом коректного завершення (30 секунд).

  2. Pod в API-сервері оновлюється: записується час, після якого Pod вважається «мертвим», разом із періодом коректного завершення. Якщо ви використовуєте kubectl describe для перевірки Podʼа, який ви видаляєте, цей Pod показується як «Terminating». На вузлі, де працює Pod: щойно kubelet бачить, що Pod позначено як такий, що завершує роботу (встановлено тривалість коректного вимкнення), kubelet розпочинає локальний процес вимкнення Podʼа.

    1. Якщо один із контейнерів Podʼа має визначений хук preStop і terminationGracePeriodSeconds у специфікації Podʼа не встановлено в 0, kubelet виконує цей хук всередині контейнера. Стандартне значення terminationGracePeriodSeconds — 30 секунд.

      Якщо хук preStop все ще виконується після закінчення періоду коректного завершення, kubelet запитує невелике одноразове подовження цього періоду на 2 секунди.

      Примітка:

      Якщо хуку preStop потрібно більше часу для завершення, ніж дозволяє стандартний період коректного завершення, вам слід змінити terminationGracePeriodSeconds відповідно до цього.
    2. Kubelet ініціює надсилання середовищем виконання контейнерів сигналу TERM процесу 1 всередині кожного контейнера.

      Є спеціальний порядок, якщо для Podʼа вказані будь-які sidecar-контейнери. В іншому випадку контейнери в Podʼі отримують сигнал TERM у різний час і в довільному порядку. Якщо порядок завершення роботи має значення, розгляньте можливість використання хука preStop для синхронізації (або перейдіть на використання sidecar-контейнерів).

  3. Одночасно з тим, як kubelet розпочинає коректне вимкнення Podʼа, панель управління оцінює, чи слід вилучити цей Pod, що вимикається, з обʼєктів EndpointSlice, де ці обʼєкти представляють Service із налаштованим селектором. ReplicaSets та інші ресурси робочого навантаження більше не вважають такий Pod дійсною реплікою, що обслуговує запити.

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

    Будь-які точки доступу, які представляють Podʼи, що завершують роботу, не вилучаються негайно з EndpointSlices, а статус, який вказує на стан завершення, надається через API EndpointSlice. Точки доступу, що завершують роботу, завжди мають статус ready зі значенням false (для зворотної сумісності з версіями до 1.26), тому балансувальники навантаження не використовуватимуть їх для звичайного трафіку.

    Якщо потрібне очищення трафіку на Podʼі, що завершує роботу, фактичну готовність можна перевірити за станом serving. Докладніше про те, як реалізувати очищення зʼєднань, можна дізнатися в навчальному матеріалі Порядок завершення роботи Podʼів та Endpointʼів

  4. kubelet забезпечує завершення та вимкнення Podʼа.

    1. Коли період коректного завершення спливає, а в Podʼі все ще працює якийсь контейнер, kubelet ініціює примусове вимкнення. Середовище виконання контейнерів надсилає SIGKILL усім процесам, які ще працюють у будь-якому контейнері в Podʼі. Kubelet також прибирає прихований контейнер pause, якщо це середовище виконання контейнерів його використовує.
    2. kubelet переводить Pod у термінальну фазу (Failed або Succeeded залежно від кінцевого стану його контейнерів).
    3. kubelet ініціює примусове видалення обʼєкта Pod з API-сервера, встановлюючи період коректного завершення в 0 (негайне видалення).
    4. API-сервер видаляє API-обʼєкт Podʼа, який після цього більше не видимий для жодного клієнта.

Примусове завершення Podʼів

Увага:

Примусове видалення може потенційно порушити роботу деяких робочих навантажень та їхніх Podʼів.

Стандартно всі видалення є коректними протягом 30 секунд. Команда kubectl delete підтримує опцію --grace-period=<seconds>, яка дозволяє перевизначити стандартне значення власним.

Встановлення періоду коректного завершення в 0 примусово та негайно видаляє Pod з API-сервера. Якщо Pod все ще працював на вузлі, це примусове видалення змушує kubelet негайно розпочати прибирання.

Використовуючи kubectl, ви повинні вказати додатковий прапорець --force разом із --grace-period=0, щоб виконати примусове видалення.

Під час примусового видалення API-сервер не чекає підтвердження від kubelet, що Pod завершено на вузлі, на якому він працював. Він негайно видаляє Pod в API, щоб можна було створити новий Pod із такою самою назвою. На вузлі Podʼи, налаштовані на негайне завершення, все ще отримують невеликий період коректного завершення перед примусовим знищенням.

Увага:

Негайне видалення не чекає підтвердження того, що запущений ресурс було завершено. Ресурс може продовжувати працювати в кластері нескінченно.

Якщо вам потрібно примусово видалити Podʼи, які є частиною StatefulSet, дивіться документацію для видалення Podʼів з StatefulSet.

Завершення роботи Podʼа та sidecar-контейнери

Якщо ваш Pod містить один або більше sidecar-контейнерів (init-контейнерів з політикою перезапуску Always), kubelet затримає надсилання сигналу TERM цим sidecar-контейнерам, доки останній основний контейнер повністю не завершить роботу. Sidecar-контейнери будуть завершені у зворотному порядку, в якому вони визначені в специфікації Podʼа. Це забезпечує продовження обслуговування sidecar-контейнерами інших контейнерів у Podʼі, доки вони не стануть непотрібними.

Це означає, що повільне завершення роботи основного контейнера також затримає завершення роботи sidecar-контейнерів. Якщо період коректного завершення спливе до закінчення процесу завершення роботи, Pod може перейти до примусового завершення. У цьому випадку всі залишкові контейнери в Podʼі будуть завершені одночасно з коротким періодом коректного завершення.

Аналогічно, якщо Pod має хук preStop, який перевищує період коректного завершення, може статися аварійне завершення. Загалом, якщо ви використовували хуки preStop для керування порядком завершення без sidecar-контейнерів, тепер ви можете видалити їх і дозволити kubelet автоматично керувати завершенням роботи sidecar-контейнерів.

Збір сміття Podʼів

Для Podʼів, що завершилися зі збоєм, обʼєкти API залишаються в API кластера, поки людина чи контролер явно їх не видалять.

Збирач сміття Podʼів (PodGC), який є контролером панелі управління, прибирає завершені Podʼи (з фазою Succeeded або Failed), коли кількість Podʼів перевищує налаштований поріг (визначений параметром terminated-pod-gc-threshold в kube-controller-manager). Це запобігає витоку ресурсів під час створення та завершення Podʼів з часом.

Крім того, PodGC очищує будь-які Podʼи, які відповідають одній з таких умов:

  1. є осиротілими Podʼами — привʼязаними до вузла, якого вже не існує,
  2. є незапланованими Podʼами у стані завершення,
  3. є Podʼами у стані завершення, привʼязаними до неготового вузла з taint node.kubernetes.io/out-of-service.

Разом із прибиранням Podʼів PodGC також позначає їх як такі, що зазнали збою, якщо вони перебувають у нетермінальній фазі. Крім того, PodGC додає стан порушення роботи Podʼа під час прибирання осиротілого Podʼа. Дивіться стани порушення роботи Podʼа, щоб дізнатися більше.

Поведінка Podʼа під час перезапуску kubelet

Якщо ви перезапускаєте kubelet, Podʼи (та їхні контейнери) продовжують працювати навіть під час перезапуску. Коли на вузлі працюють Podʼи, зупинка або перезапуск kubelet на цьому вузлі не призводить до того, що kubelet зупиняє всі локальні Podʼи перед тим, як зупинитися сам. Щоб зупинити Podʼи на вузлі, ви можете використовувати kubectl drain.

Виявлення перезапусків kubelet

СТАН ФУНКЦІОНАЛУ: Deprecated since Kubernetes v1.35; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the ChangeContainerStatusOnKubeletRestart feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли kubelet запускається, він перевіряє, чи є вже вузол із привʼязаними Podʼами. Якщо стан Ready вузла залишається незмінним, тобто стан не змінився з true на false, Kubernetes виявляє це як перезапуск kubelet. (Можна перезапустити kubelet іншими способами, наприклад, щоб виправити помилку вузла, але в таких випадках Kubernetes вибирає безпечний варіант і розглядає це як зупинку kubelet, а потім його запуск).

Коли kubelet перезапускається, статусами контейнерів керують по-різному залежно від налаштування функціональної можливості:

  • Стандартно kubelet не змінює статуси контейнерів після перезапуску. Контейнери, для яких було встановлено ready: true, залишаються готовими.

    Якщо ви зупините kubelet на достатньо довгий час, щоб він не пройшов серію перевірок пульсу вузла, а потім зачекаєте, перш ніж знову запустити kubelet, Kubernetes може почати виселяти Podʼи з цього вузла. Однак, навіть якщо виселення Podʼів починається, Kubernetes не позначає окремі контейнери в цих Podʼах як ready: false. Виселення на рівні Podʼа відбувається після того, як панель управління додає вузлу taint node.kubernetes.io/not-ready (через провал перевірок пульсу).

  • У Kubernetes 1.37 ви можете вибрати стару поведінку, за якої kubelet завжди змінює значення контейнерів ready після перезапуску kubelet на false.

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

Що далі

1.2 - Стани Podʼа

У Kubernetes багато обʼєктів мають стани (conditions). Стан — це показник певного аспекту фактичного становища того, що представляє обʼєкт. Podʼи мають стани, і стани Podʼів у Kubernetes є важливим аспектом, що дозволяє контролерам (а також тим, хто займається усуненням несправностей) оцінювати справність Podʼів.

Фаза Podʼа надає високорівневий огляд того, на якому етапі життєвого циклу перебуває Pod, але одне значення не може показати повну картину. Наприклад, Pod може перебувати у фазі Running, але не бути готовим до обслуговування трафіку. Стани Podʼа доповнюють фазу, відстежуючи незалежно один від одного різні аспекти статусу Podʼа, наприклад, чи було його заплановано, чи готові його контейнери, чи триває зміна розміру, або чи буде робота Podʼа незабаром порушена через taint.

Структура стану Podʼа

Статус Podʼа включає масив PodConditions, які вказують, чи пройшов Pod певні контрольні точки.

Кожен елемент масиву PodCondition має такі поля:

Поля PodCondition
ПолеОпис
typeНазва стану Podʼа.
statusВказує, чи застосовний цей стан, з можливими значеннями "True", "False" або "Unknown".
lastProbeTimeЧас останньої перевірки стану Podʼа.
lastTransitionTimeЧас останнього переходу Podʼа з одного стану в інший.
reasonТекст у форматі UpperCamelCase, придатний для машинного зчитування, що вказує причину останнього переходу стану.
messageПовідомлення, придатне для сприйняття людиною, що містить детальну інформацію про останній перехід стану.
observedGeneration.metadata.generation Podʼа на момент запису стану. Див. Генерація Podʼа.

Вбудовані стани Podʼа

Kubernetes керує такими станами Podʼа:

Стани життєвого циклу: встановлюються під час проходження Podʼом свого життєвого циклу, приблизно в такому порядку: PodScheduled, PodReadyToStartContainers, Initialized, ContainersReady, Ready.

Інші стани: встановлюються у відповідь на конкретні операції або події: DisruptionTarget, PodResizePending, PodResizeInProgress.

Крім вбудованих станів, ви можете визначати власні стани за допомогою шлюзів готовності Podʼа (readiness gates).

Стани життєвого циклу Podʼа

У міру проходження Podʼом свого життєвого циклу kubelet встановлює такі стани приблизно в такому порядку:

  1. PodScheduled: Pod було заплановано на вузол.
  2. PodReadyToStartContainers: пісочницю Podʼа було успішно створено та налаштовано мережу. Пісочницю та мережу налаштовують середовище виконання контейнерів та втулок CNI.
  3. Initialized: всі init-контейнери успішно завершилися. Для Podʼа без init-контейнерів встановлюється в True перед створенням пісочниці.
  4. ContainersReady: всі контейнери в Podʼі готові. Готовність контейнера визначається його пробою готовності, якщо вона налаштована.
  5. Ready: Pod здатний обслуговувати запити і повинен бути доданий до пулів балансування навантаження всіх відповідних Services. Podʼи, які не є Ready, видаляються з точок доступу Service.

Примітка:

Стан Ready залежить не лише від ContainersReady. Якщо Pod вказує readinessGates, всі ці власні стани також повинні бути True, щоб Pod був Ready. Див. Готовність Podʼа для деталей.

Ви можете перевірити стани Podʼа за допомогою kubectl:

kubectl get pod <pod-name> -o yaml

Цей вивід показує, як виглядає поле status.conditions для запущеного Podʼа:

status:
  conditions:
    - type: PodScheduled
      status: "True"
      lastProbeTime: null
      lastTransitionTime: "2026-03-29T08:52:21Z"
      observedGeneration: 1
    - type: PodReadyToStartContainers
      status: "True"
      lastProbeTime: null
      lastTransitionTime: "2026-04-11T06:02:16Z"
      observedGeneration: 1
    - type: Initialized
      status: "True"
      lastProbeTime: null
      lastTransitionTime: "2026-03-29T08:52:21Z"
      observedGeneration: 1
    - type: ContainersReady
      status: "True"
      lastProbeTime: null
      lastTransitionTime: "2026-04-11T06:02:45Z"
      observedGeneration: 1
    - type: Ready
      status: "True"
      lastProbeTime: null
      lastTransitionTime: "2026-04-11T06:02:45Z"
      observedGeneration: 1

PodReadyToStartContainers

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.37
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.37. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate PodReadyToStartContainersCondition, Kubernetes ignores it but does not report any error.

Примітка:

Під час ранньої розробки цей стан називався PodHasNetwork.

Після того, як Pod заплановано на вузол, kubelet має його допустити, а всі необхідні томи зберігання мають бути змонтовані. Після завершення цих фаз kubelet працює із середовищем виконання контейнерів (використовуючи Container Runtime Interface, CRI), щоб налаштувати пісочницю середовища виконання та мережу для Podʼа. Стан PodReadyToStartContainers додається до поля status.conditions Podʼа.

Kubelet встановлює цей стан в False, коли виявляє, що Pod не має пісочниці середовища виконання з налаштованою мережею. Це відбувається в таких сценаріях:

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

Kubelet встановлює стан PodReadyToStartContainers в True після того, як втулок середовища виконання успішно завершить створення пісочниці та налаштування мережі для Podʼа. Після встановлення стану PodReadyToStartContainers в True kubelet може почати завантаження образів контейнерів та створення контейнерів.

Для Podʼа з init-контейнерами kubelet встановлює стан Initialized в True після успішного завершення init-контейнерів (що відбувається після успішного створення пісочниці та налаштування мережі втулком середовища виконання). Для Podʼа без init-контейнерів kubelet встановлює стан Initialized в True перед початком створення пісочниці та налаштування мережі.

Інші стани Podʼа

Такі стани не є частиною нормального проходження життєвого циклу Podʼа. Вони встановлюються у відповідь на конкретні операції або події.

DisruptionTarget

Спеціальний стан Podʼа DisruptionTarget додається для того, щоб вказати, що Pod буде видалено через порушення. Поле reason цього стану додатково вказує одну з таких причин завершення Podʼа:

PreemptionByScheduler
Pod підлягає витісненню планувальником, щоб звільнити місце для нового Podʼа з вищим пріоритетом. Для отримання додаткової інформації див. Пріоритет та витіснення Podʼів.
DeletionByTaintManager
Pod підлягає видаленню менеджером Taint (який є частиною контролера життєвого циклу вузла в kube-controller-manager) через NoExecute taint, який Pod не толерує; див. виселення на основі taint.
EvictionByEvictionAPI
Pod підлягає виселенню за допомогою API Kubernetes.
DeletionByPodGC
Pod, який привʼязаний до вузла, що більше не існує, підлягає видаленню за допомогою механізму збору сміття Podʼів.
TerminationByKubelet
Pod було завершено kubelet через виселення внаслідок тиску на вузол, коректне вимкнення вузла або витіснення заради системно критичних Podʼів.

У всіх інших сценаріях порушення, таких як виселення через перевищення обмежень контейнерів Podʼа, Podʼи не отримують стан DisruptionTarget, оскільки ці порушення, ймовірно, були спричинені самим Podʼом і повторилися б під час повторної спроби.

Примітка:

Процес порушення роботи Podʼа може бути зупинено. Панель управління може повторно спробувати продовжити порушення роботи того самого Podʼа, але це не гарантовано. В результаті стан DisruptionTarget може бути додано до Podʼа, але цей Pod може фактично не бути видаленим. У такій ситуації через деякий час стан порушення роботи Podʼа буде очищено.

Разом з очищенням Podʼів, механізм збору сміття Podʼів (PodGC) також позначає їх як невдалі, якщо вони перебувають у нетермінальній фазі (див. також збір сміття Podʼів).

Під час використання Job (або CronJob) ви можете використовувати ці стани порушення роботи Podʼів як частину політики збоїв Podʼа вашого Job.

Для отримання додаткової інформації див. Порушення.

PodResizePending та PodResizeInProgress

Kubelet оновлює стани Podʼа, щоб вказати статус запиту на зміну розміру:

  • type: PodResizePending: Kubelet не може негайно виконати запит. Поле message надає пояснення, чому.
    • reason: Infeasible: Запитана зміна розміру неможлива на поточному вузлі (наприклад, запит більше ресурсів, ніж є на вузлі).
    • reason: Deferred: Запитана зміна розміру наразі неможлива, але може стати можливою пізніше (наприклад, якщо інший Pod буде видалено). Kubelet повторно спробує зміну розміру.
  • type: PodResizeInProgress: Kubelet прийняв зміну розміру та виділив ресурси, але зміни ще застосовуються. Зазвичай це триває недовго, але може зайняти більше часу залежно від типу ресурсу та поведінки середовища виконання. Будь-які помилки під час виконання повідомляються у полі message (разом з reason: Error).

Якщо запитана зміна розміру є Deferred, kubelet періодично повторно намагатиметься виконати зміну розміру, наприклад, коли інший Pod буде видалено або зменшено масштаб.

Докладніше див. Зміна розміру CPU та памʼяті, призначених контейнерам.

Розширена готовність Podʼів

Ваш застосунок може додавати додаткові відгуки або сигнали в .status Podʼа; це відомо як розширена готовність Podʼів. Щоб використовувати це, встановіть readinessGates у spec Podʼа, щоб вказати список додаткових станів, які kubelet оцінює для готовності Podʼа. Потім ви реалізуєте або встановлюєте контролер, який керує цими власними станами, і kubelet використовує це як додаткове вхідне значення для визначення готовності Podʼа.

Шлюзи готовності (readiness gates) визначаються поточним станом полів status.condition для Podʼа. Якщо Kubernetes не може знайти такий стан у полі status.conditions Podʼа, його статус стандартно дорівнює "False".

kind: Pod
...
spec:
  readinessGates:
    - conditionType: "www.example.com/feature-1"
status:
  conditions:
    - type: Ready                              # вбудована PodCondition
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
    - type: "www.example.com/feature-1"        # додаткова PodCondition
      status: "False"
      lastProbeTime: null
      lastTransitionTime: 2018-01-01T00:00:00Z
  containerStatuses:
    - containerID: docker://abcd...
      ready: true
...

Стани Podʼа, які ви додаєте, повинні мати назви, що відповідають формату ключів міток Kubernetes.

Статус готовності Podʼа

Щоб встановити ці status.conditions для Podʼа, застосунки та оператори повинні використовувати дію PATCH на субресурсі статусу Podʼа. Ви можете використовувати kubectl patch з --subresource=status, або бібліотеку клієнта Kubernetes, щоб написати код, який встановлює власні стани Podʼа для готовності Podʼа.

Pod, який використовує власні стани, вважається готовим тільки тоді, коли виконуються обидва такі твердження:

  • Всі контейнери в Podʼі готові.
  • Усі стани, зазначені в readinessGates, мають значення True.

Коли контейнери Podʼа готові, але принаймні один власний стан відсутній або має значення False, kubelet встановлює стан Ready Podʼа в status: "False" з reason: ReadinessGatesNotReady.

Що далі

1.3 - Init-контейнери

Ця сторінка надає загальний огляд init-контейнерів: спеціалізованих контейнерів, які запускаються перед запуском контейнерів застосунків в Podʼі. Init-контейнери можуть містити утиліти або сценарії налаштування, які відсутні в образі застосунку.

Ви можете вказати init-контейнери в специфікації Podʼа разом із масивом containers (який описує контейнери застосунку).

У Kubernetes sidecar-контейнер — це контейнер, який запускається перед основним контейнером застосунку і продовжує працювати. Цей документ стосується init-контейнерів — контейнерів, які виконуються до завершення під час ініціалізації Podʼа.

Що таке init-контейнери

У Podʼі може бути кілька контейнерів, які виконують застосунки, але також може бути один чи кілька init-контейнерів, які виконуються до того, як стартують контейнери застосунків.

Init-контейнери точно такі самі, як і звичайні контейнери, за винятком того, що:

  • Init-контейнери завжди виконуються до завершення.
  • Кожен init-контейнер повинен успішно завершити свою роботу, перш ніж почне роботу наступний.

Якщо init-контейнер Podʼа зазнає збою, kubelet повторно перезапускає цей init-контейнер, доки він не завершиться успішно. Однак якщо restartPolicy Podʼа дорівнює Never, і init-контейнер зазнає збою під час запуску цього Podʼа, Kubernetes вважає весь Pod невдалим.

Щоб вказати init-контейнер для Podʼа, додайте поле initContainers у специфікацію Podʼа, у вигляді масиву обʼєктів container (аналогічно полю containers застосунку та його вмісту). Дивіться Container в довідці API для отримання докладнішої інформації.

Статус init-контейнерів повертається у полі .status.initContainerStatuses у вигляді масиву статусів контейнерів (аналогічно полю .status.containerStatuses).

Відмінності від звичайних контейнерів

Init-контейнери підтримують всі поля та можливості контейнерів застосунків, включаючи обмеження ресурсів, томи та налаштування безпеки. Однак запити та обмеження ресурсів для init-контейнера обробляються по-іншому, як описано в розділі Спільне використання ресурсів всередині контейнерів.

Звичайні init-контейнери (іншими словами, виключаючи sidecar-контейнери) не підтримують поля lifecycle, livenessProbe, readinessProbe чи startupProbe. Init-контейнери повинні успішно завершити свою роботу перед тим, як Pod може бути готовий; sidecar-контейнери продовжують працювати протягом життєвого циклу Podʼа і підтримують деякі проби. Дивіться sidecar-контейнер для отримання додаткової інформації про ці контейнери.

Якщо ви вказали кілька init-контейнерів для Podʼа, kubelet виконує кожен такий контейнер послідовно. Кожен init-контейнер повинен успішно завершити свою роботу, перш ніж може бути запущено наступний. Коли всі init-контейнери завершать свою роботу, kubelet ініціалізує контейнери застосунків для Podʼа та запускає їх як зазвичай.

Відмінності від sidecar-контейнерів

Init-контейнери запускаються і завершують свої завдання до того, як розпочнеться робота основного контейнера застосунку. На відміну від sidecar-контейнерів, init-контейнери не продовжують працювати паралельно з основними контейнерами.

Init-контейнери запускаються і завершують свою роботу послідовно, і основний контейнер не починає свою роботу, доки всі init-контейнери успішно не завершать свою роботу.

Init-контейнери не підтримують lifecycle, livenessProbe, readinessProbe чи startupProbe, у той час, як sidecar-контейнери підтримують всі ці проби, щоб керувати своїм життєвим циклом.

Init-контейнери використовують ті самі ресурси (CPU, памʼять, мережу), що й основні контейнери застосунків, але не взаємодіють з ними напряму. Однак вони можуть використовувати спільні томи для обміну даними.

Використання init-контейнерів

Оскільки init-контейнери мають образи, окремі від контейнерів застосунків, вони мають кілька переваг для коду, повʼязаного із запуском:

  • Init-контейнери можуть містити утиліти або власний код для налаштування, які відсутні в образі застосунку. Наприклад, немає потреби створювати образ FROM іншого образу лише для використання інструменту, такого як sed, awk, python чи dig під час налаштування.
  • Ролі створення та розгортання образу застосунку можуть працювати незалежно одна від одної без необхідності спільного створення єдиного образу застосунку.
  • Init-контейнери можуть працювати з іншим поданням файлової системи, ніж контейнери застосунків у тому самому Podʼі. Отже, їм можна надати доступ до Secrets, до яких контейнери застосунків не мають доступу.
  • Оскільки init-контейнери завершують свою роботу, перш ніж будь-які контейнери застосунків розпочнуть свою роботу, вони пропонують механізм блокування або затримки запуску контейнера застосунку до виконання певних умов. Після того, як умови виконані, всі контейнери застосунків у Podʼі можуть стартувати паралельно.
  • Init-контейнери можуть безпечно виконувати утиліти або власний код, який інакше зробив би образ контейнера застосунку менш безпечним. Відокремлюючи непотрібні інструменти, ви можете обмежити поверхню атаки вашого образу контейнера застосунку.

Приклади

Ось кілька ідей, як використовувати init-контейнери:

  • Очікування на створення Service, використовуючи команду оболонки у вигляді одного рядка, наприклад:

    for i in {1..100}; do sleep 1; if nslookup myservice; then exit 0; fi; done; exit 1
    
  • Реєстрація Podʼа на віддаленому сервері зі значеннями, отриманими з Downward API за допомогою команди, подібної цій:

    curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
    
  • Очікування певного часу перед запуском контейнера застосунку за допомогою команди, подібної цій:

    sleep 60
    
  • Клонування репозиторію Git у том

  • Додавання значень у файл конфігурації та виклик інструменту шаблонування для динамічного створення файлу конфігурації для основного контейнера застосунку. Наприклад, додайте значення POD_IP у конфігурацію та створіть основний файл конфігурації застосунку за допомогою Jinja.

Init-контейнери в роботі

У цьому прикладі визначається простий Pod, який має два init-контейнери. Перший чекає на myservice, а другий — на mydb. Як тільки обидва init-контейнери завершаться, Pod запускає контейнер застосунку зі свого розділу spec.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app.kubernetes.io/name: MyApp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

Ви можете запустити цей Pod, виконавши:

kubectl apply -f myapp.yaml

Вивід буде подібний до цього:

pod/myapp-pod created

І перевірте його статус за допомогою:

kubectl get -f myapp.yaml

Вивід буде подібний до цього:

NAME        READY     STATUS     RESTARTS   AGE
myapp-pod   0/1       Init:0/2   0          6m

або докладніше:

kubectl describe -f myapp.yaml

Вивід буде подібний до цього:

Name:          myapp-pod
Namespace:     default
[...]
Labels:        app.kubernetes.io/name=MyApp
Status:        Pending
[...]
Init Containers:
  init-myservice:
[...]
    State:         Running
[...]
  init-mydb:
[...]
    State:         Waiting
      Reason:      PodInitializing
    Ready:         False
[...]
Containers:
  myapp-container:
[...]
    State:         Waiting
      Reason:      PodInitializing
    Ready:         False
[...]
Events:
  FirstSeen    LastSeen    Count    From                      SubObjectPath                           Type          Reason        Message
  ---------    --------    -----    ----                      -------------                           --------      ------        -------
  16s          16s         1        {default-scheduler }                                              Normal        Scheduled     Successfully assigned myapp-pod to 172.17.4.201
  16s          16s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Pulling       pulling image "busybox"
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Pulled        Successfully pulled image "busybox"
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Created       Created container init-myservice
  13s          13s         1        {kubelet 172.17.4.201}    spec.initContainers{init-myservice}     Normal        Started       Started container init-myservice

Щоб переглянути логи init-контейнерів у цьому Podʼі, виконайте:

kubectl logs myapp-pod -c init-myservice # Огляд першого init-контейнера
kubectl logs myapp-pod -c init-mydb      # Огляд другого init-контейнера

На цей момент ці init-контейнери будуть чекати виявлення Services з назвами mydb та myservice.

Ось конфігурація, яку ви можете використовувати для того, щоб ці Services зʼявилися:

---
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9377

Щоб створити Services mydb та myservice:

kubectl apply -f services.yaml

Вивід буде подібний до цього:

service/myservice created
service/mydb created

Потім ви побачите, що ці init-контейнери завершаться, і Pod myapp-pod переходить у стан Running:

kubectl get -f myapp.yaml

Вивід буде подібний до цього:

NAME        READY     STATUS    RESTARTS   AGE
myapp-pod   1/1       Running   0          9m

Цей простий приклад повинен дати вам натхнення для створення ваших власних init-контейнерів. У розділі Що далі є посилання на більш детальний приклад.

Докладний опис поведінки

Під час запуску Podʼа kubelet затримує виконання init-контейнерів, доки мережа та сховище не будуть готові. Після цього kubelet виконує init-контейнери Podʼа в порядку, в якому вони зазначені в специфікації Podʼа.

Кожен init-контейнер має успішно завершитися перед тим, як буде запущений наступний контейнер. Якщо контейнер не вдалося запустити через помилку середовища виконання або він завершується з помилкою, його перезапускають згідно з політикою перезапуску Podʼа (restartPolicy). Однак якщо політика перезапуску Podʼа (restartPolicy) встановлена на Always, init-контейнери використовують політику перезапуску OnFailure.

Pod не може бути Ready, поки всі init-контейнери не завершаться успішно. Порти init-контейнерів не агрегуються в Service. Pod, що ініціалізується, перебуває в стані Pending, але повинен мати умову Initialized, встановлену на false.

Якщо Pod перезапускається або був перезапущений, всі init-контейнери мають виконатися знову.

Зміни в специфікації init-контейнерів обмежуються полем образу контейнера. Безпосередня зміна поля image init-контейнера не призводить до перезапуску Podʼа або його перестворення. Якщо Pod ще не було запущено, ці зміни можуть вплинути на те, як він завантажиться.

Для шаблону Podʼа ви зазвичай можете змінити будь-яке поле init-контейнера; наслідки цієї зміни залежать від того, де використовується шаблон Podʼа.

Оскільки init-контейнери можуть бути перезапущені, повторно виконані або виконані заново, код init-контейнерів повинен бути ідемпотентним. Зокрема, код, що записує дані в будь-який том emptyDir, має бути підготовлений до того, що файл виводу вже може існувати.

Init-контейнери мають усі поля контейнера застосунку. Проте Kubernetes забороняє використання readinessProbe, оскільки init-контейнери не можуть визначати готовність окремо від завершення. Це забезпечується під час валідації.

Використовуйте activeDeadlineSeconds в Podʼі, щоб запобігти нескінченним збоям init-контейнерів. Активний крайній термін охоплює init-контейнери. Однак рекомендується використовувати activeDeadlineSeconds лише якщо команди розгортають свій застосунок як Job, оскільки activeDeadlineSeconds впливає навіть після завершення роботи init-контейнера. Pod, який вже працює правильно, буде завершено через activeDeadlineSeconds, якщо ви його налаштуєте.

Назва кожного контейнера застосунку та init-контейнера в Podʼі має бути унікальною; для контейнера, назва якого збігається з назвою іншого, буде згенеровано помилку валідації.

Спільне використання ресурсів всередині контейнерів

З урахуванням порядку виконання init-контейнерів, sidecar-контейнерів і контейнерів застосунків застосовуються такі правила використання ресурсів:

  • Найвищий запит чи обмеження будь-якого конкретного ресурсу, визначеного у всіх init-контейнерах, вважається ефективним запитом/обмеженням ініціалізації. Якщо для будь-якого ресурсу не вказано обмеження, це вважається найвищим обмеженням.
  • Ефективний запит/обмеження Podʼа для ресурсу — це більше з:
    • суми запитів/обмежень усіх контейнерів застосунків для ресурсу
    • ефективного запиту/обмеження ініціалізації для ресурсу
  • Планування виконується на основі ефективних запитів/обмежень, що означає, що init-контейнери можуть резервувати ресурси для ініціалізації, які не використовуються протягом життя Podʼа.
  • Рівень якості обслуговування (QoS), ефективний рівень QoS Podʼа, — це рівень QoS як для init-контейнерів, так і для контейнерів застосунків.

Квоти та обмеження застосовуються на основі ефективного запиту та обмеження Podʼа.

Init-контейнери та cgroups Linux

У Linux розподіл ресурсів для контрольних груп (cgroups) рівня Podʼа ґрунтується на ефективному запиті та обмеженні Podʼа, так само як і для планувальника.

Причини перезапуску Podʼа

Pod може перезапускатися, що призводить до повторного виконання init-контейнерів, з таких причин:

  • Перезапускається контейнер інфраструктури Podʼа. Це трапляється рідко, і це мав би зробити хтось із root-доступом до вузлів.
  • Всі контейнери в Podʼі завершуються, коли restartPolicy встановлено в Always, що примушує до перезапуску, а запис про завершення init-контейнера було втрачено через збір сміття.

Pod не буде перезапущено, коли змінюється образ init-контейнера, або запис про завершення init-контейнера було втрачено через збір сміття. Це стосується Kubernetes v1.20 і пізніших версій. Якщо ви використовуєте старішу версію Kubernetes, ознайомтеся з документацією версії, яку ви використовуєте.

Що далі

Дізнайтеся більше про таке:

1.4 - Sidecar-контейнери

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.33
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.33. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate SidecarContainers, Kubernetes ignores it but does not report any error.

Sidecar-контейнери — це додаткові контейнери, які працюють разом з основним контейнером застосунку всередині одного Podʼа. Ці контейнери використовуються для розширення чи покращення функціональності основного контейнера застосунку, надаючи додаткові сервіси чи функціональність, таку як логування, моніторинг, безпеку або синхронізацію даних, не змінюючи безпосередньо код основного застосунку.

Зазвичай в одному Podʼі є лише один контейнер застосунку. Наприклад, якщо у вас є вебзастосунок, який потребує локального вебсервера, локальний вебсервер буде sidecar-контейнером, а сам вебзастосунок — це контейнер застосунку.

Sidecar-контейнери в Kubernetes

Kubernetes реалізує sidecar-контейнери як особливий випадок init-контейнерів; sidecar-контейнери залишаються запущеними після запуску Podʼа. У цьому документі термін звичайні init-контейнери використовується для чіткого посилання на контейнери, які працюють лише під час запуску Podʼа.

За умови, що у вашому кластері увімкнено функціональну можливість SidecarContainers (стандартно активна починаючи з Kubernetes v1.29), ви можете вказати restartPolicy для контейнерів, вказаних у полі initContainers Podʼа. Ці sidecar-контейнери, які перезапускаються, є незалежними від інших init-контейнерів та від основних контейнерів застосунку у тому ж Podʼі, і можуть бути запущені, зупинені або перезапущені без впливу на основний контейнер застосунку та інші init-контейнери.

Ви також можете запустити Pod із декількома контейнерами, які не позначені як init-контейнери або sidecar. Це доцільно, якщо контейнери в межах Podʼа необхідні для його роботи в цілому, але вам не потрібно керувати тим, які контейнери спочатку запускаються або зупиняються. Ви також можете це зробити, якщо вам потрібно підтримувати старі версії Kubernetes, які не підтримують поле restartPolicy на рівні контейнера.

Приклад застосунку

Нижче наведено приклад Deployment з двома контейнерами, один з яких є sidecar:

Примітка:

У цьому прикладі sidecar-контейнер навмисно визначений в initContainers з restartPolicy: Always. Kubernetes розглядає такі контейнери як sidecar-контейнери, які продовжують працювати впродовж усього терміну існування Podʼа.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: alpine:latest
          command: ['sh', '-c', 'while true; do echo "logging" >> /opt/logs.txt; sleep 1; done']
          volumeMounts:
            - name: data
              mountPath: /opt
      initContainers:
        - name: logshipper
          image: alpine:latest
          # Setting restartPolicy: Always makes this a sidecar container.
          restartPolicy: Always
          command: ['sh', '-c', 'tail -F /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      volumes:
        - name: data
          emptyDir: {}

Sidecar-контейнери та життєвий цикл Podʼа

Якщо init-контейнер створено з параметром restartPolicy, встановленим на Always, він розпочне роботу і залишиться запущеним протягом усього життя Podʼа. Це може бути корисно для запуску допоміжних сервісів, відокремлених від основних контейнерів застосунку.

Якщо для цього init-контейнера вказано readinessProbe, результат буде використовуватися для визначення стану ready Podʼа.

Оскільки ці контейнери визначені як init-контейнери, вони користуються тими самими гарантіями порядку та послідовності, що й звичайні init-контейнери, що дозволяє змішувати sidecar-контейнери зі звичайними init-контейнерами у складних потоках ініціалізації Podʼа.

Порівняно зі звичайними init-контейнерами, sidecar-контейнери, визначені в initContainers, продовжують роботу після їх запуску. Це важливо, коли в .spec.initContainers для Podʼа є більше одного запису. Після запуску init-контейнера типу sidecar (kubelet встановлює статус started для цього контейнера в true), kubelet запускає наступний init-контейнер з упорядкованого списку .spec.initContainers. Цей статус стає true через те, що в контейнері працює процес і немає визначеного startupProbe, або внаслідок успішного виконання startupProbe.

Під час завершення роботи Podʼа kubelet відкладає завершення sidecar-контейнерів до повної зупинки основного контейнера застосунку. Після цього sidecar-контейнери вимикаються у порядку, протилежному порядку їх появи у специфікації Podʼа. Такий підхід гарантує, що sidecar-контейнери залишаються в робочому стані, підтримуючи інші контейнери в Podʼі, до тих пір, поки їх обслуговування більше не буде потрібне.

Jobs із sidecar-контейнерами

Якщо ви визначаєте Job, який використовує sidecar у вигляді init-контейнерів у стилі Kubernetes, sidecar-контейнер у кожному Podʼі не заважає завершенню Job після завершення основного контейнера.

Ось приклад Job із двома контейнерами, один з яких — це sidecar-контейнер:

apiVersion: batch/v1
kind: Job
metadata:
  name: myjob
spec:
  template:
    spec:
      containers:
        - name: myjob
          image: alpine:latest
          command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      initContainers:
        - name: logshipper
          image: alpine:latest
          # Setting restartPolicy: Always makes this a sidecar container.
          restartPolicy: Always
          command: ['sh', '-c', 'tail -F /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      restartPolicy: Never
      volumes:
        - name: data
          emptyDir: {}

Відмінності від контейнерів застосунків

Sidecar-контейнери працюють поруч з контейнерами застосунку в одному Podʼі. Однак вони не виконують основну логіку застосунку; замість цього вони надають допоміжну функціональність основному застосунку.

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

Sidecar-контейнери спільно використовують з основним контейнером ті самі простори імен мережі та сховища. Це спільне розташування дозволяє їм тісно взаємодіяти та спільно використовувати ресурси.

З погляду Kubernetes коректне завершення sidecar-контейнера є менш важливим. Якщо інші контейнери використали весь виділений час для коректного завершення роботи, то sidecar-контейнери отримають сигнал SIGTERM, а потім SIGKILL, перш ніж вони встигнуть коректно завершити роботу. Отже, коди виходу, відмінні від 0 (0 означає успішний вихід), для sidecar-контейнерів є нормальним явищем під час завершення роботи Podʼа, і зовнішні інструменти зазвичай мають їх ігнорувати.

Відмінності від init-контейнерів

Sidecar-контейнери працюють поруч з основним контейнером, розширюючи його функціональність та надаючи додаткові сервіси.

Sidecar-контейнери працюють паралельно з основним контейнером застосунку. Вони активні протягом усього життєвого циклу Podʼа та можуть бути запущені та зупинені незалежно від основного контейнера. На відміну від init-контейнерів, sidecar-контейнери підтримують проби, щоб контролювати їхній життєвий цикл.

Sidecar-контейнери можуть взаємодіяти безпосередньо з основними контейнерами застосунків, оскільки вони, так само як і init-контейнери, завжди спільно використовують ту саму мережу і за бажанням також можуть спільно використовувати томи (файлові системи).

Init-контейнери зупиняються до того, як основний контейнер застосунку розпочне роботу, тож init-контейнер не може обмінюватись повідомленнями з контейнером застосунку в Podʼі. Будь-які дані передаються лише в один бік (наприклад, init-контейнер може залишити інформацію у томі emptyDir).

Зміна образу sidecar-контейнера не призведе до перезапуску Podʼа, але спровокує перезапуск контейнера.

Спільне використання ресурсів всередині контейнерів

З урахуванням порядку виконання init-контейнерів, sidecar-контейнерів і контейнерів застосунків застосовуються такі правила використання ресурсів:

  • Найвищий запит чи обмеження будь-якого конкретного ресурсу, визначеного у всіх init-контейнерах, вважається ефективним запитом/обмеженням ініціалізації. Якщо для будь-якого ресурсу не вказано обмеження, це вважається найвищим обмеженням.
  • Ефективний запит/обмеження Podʼа для ресурсу — це сума накладних витрат Podʼа та більшого з:
    • суми запитів/обмежень усіх контейнерів, що не є init-контейнерами (контейнерів застосунків і sidecar-контейнерів), для ресурсу
    • ефективного запиту/обмеження ініціалізації для ресурсу
  • Планування виконується на основі ефективних запитів/обмежень, що означає, що init-контейнери можуть резервувати ресурси для ініціалізації, які не використовуються протягом життя Podʼа.
  • Рівень якості обслуговування (QoS), ефективний рівень QoS Podʼа, — це рівень QoS для всіх init-контейнерів, sidecar-контейнерів і контейнерів застосунків.

Квоти та обмеження застосовуються на основі ефективного запиту та обмеження Podʼа.

Sidecar-контейнери та cgroups Linux

У Linux розподіл ресурсів для контрольних груп (cgroups) рівня Podʼа ґрунтується на ефективному запиті та обмеженні Podʼа, так само як і для планувальника.

Що далі

1.5 - Ефемерні контейнери

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.25

Ця сторінка надає огляд ефемерних контейнерів: особливого типу контейнера, який працює тимчасово в наявному Pod для виконання дій, ініційованих користувачем, таких як усунення несправностей. Ефемерні контейнери використовуються для огляду сервісів, а не для створення застосунків.

Розуміння ефемерних контейнерів

Podʼи є фундаментальним елементом застосунків Kubernetes. Оскільки Podʼи призначені бути одноразовими та замінними, ви не можете додати контейнер до Podʼа після його створення. Замість цього ви зазвичай видаляєте та замінюєте Podʼи у контрольований спосіб, використовуючи Deployments.

Іноді, однак, необхідно оглянути стан наявного Podʼа, наприклад, для усунення несправностей, коли важко відтворити помилку. У цих випадках ви можете запустити ефемерний контейнер у наявному Podʼі, щоб оглянути його стан та виконати довільні команди.

Що таке ефемерний контейнер?

Ефемерні контейнери відрізняються від інших контейнерів тим, що вони не мають гарантій щодо ресурсів або виконання, і їх ніколи автоматично не перезапускають, тому вони не підходять для створення застосунків. Ефемерні контейнери описуються за допомогою того самого ContainerSpec, що й звичайні контейнери, але багато полів несумісні та заборонені для ефемерних контейнерів.

  • В ефемерних контейнерів не може бути портів, тому такі поля, як ports, livenessProbe, readinessProbe, заборонені.
  • Виділення ресурсів для Podʼа незмінне, тому встановлення resources заборонене.
  • Для повного списку дозволених полів дивіться довідкову документацію EphemeralContainer.

Ефемерні контейнери створюються за допомогою спеціального обробника ephemeralcontainers в API замість того, щоб додавати їх безпосередньо до pod.spec, тому не можна додати ефемерний контейнер за допомогою kubectl edit.

Як і звичайний контейнер, ефемерний контейнер не можна змінити або видалити після додавання до Podʼа.

Примітка:

Ефемерні контейнери не підтримуються статичними Podʼами.

Використання ефемерних контейнерів

Ефемерні контейнери корисні для інтерактивного усунення несправностей, коли kubectl exec недостатній, оскільки контейнер зазнав збою або образ контейнера не містить засобів налагодження.

Зокрема, образи distroless дозволяють вам розгортати мінімальні образи контейнерів, які зменшують поверхню атаки та вплив помилок і вразливостей. Оскільки образи distroless не включають оболонку або будь-які засоби налагодження, складно налагоджувати образи distroless, використовуючи лише kubectl exec.

Під час використання ефемерних контейнерів корисно увімкнути спільний простір імен процесів (process namespace sharing), щоб ви могли переглядати процеси в інших контейнерах.

Що далі

1.6 - Проби життєздатності, готовності та запуску

Kubernetes дозволяє визначати проби для безперервного моніторингу стану контейнерів у Podʼі. Проба — це діагностична перевірка контейнера, яку періодично виконує kubelet. Для виконання діагностики kubelet або виконує код всередині контейнера, або робить мережевий запит.

На основі результатів проб Kubernetes може перезапускати несправні контейнери або припиняти надсилання трафіку до контейнерів, які не готові.

Типи проб

Kubelet може за потреби виконувати три види проб у запущених контейнерах і реагувати на їхні результати; кожна з них має власне призначення:

Проба запуску

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

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

Проба життєздатності

Проби життєздатності (Liveness) визначають, коли слід перезапустити контейнер. Наприклад, проби життєздатності можуть виявити ситуацію взаємного блокування, коли застосунок працює, але не може просуватися далі. Перезапуск контейнера в такому стані допомагає забезпечити більшу доступність застосунку, незважаючи на наявність помилок.

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

Увага:

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

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

Проба готовності

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

Якщо проба готовності повертає неуспішний стан, контролер EndpointSlice видаляє IP-адресу Podʼа з EndpointSlices усіх Services, що відповідають цьому Podʼу.

Проби готовності виконуються в контейнері протягом всього його життєвого циклу.

Примітка:

Якщо ви хочете мати можливість завершувати обробку запитів під час видалення Podʼа, вам не обовʼязково потрібна проба готовності; коли Pod видаляється, відповідна точка доступу в EndpointSlice оновить свої стани: стан готовності точки доступу буде встановлено на false, тому балансувальники навантаження не використовуватимуть Pod для звичайного трафіку. Дивіться Завершення роботи Podʼа для отримання додаткової інформації про те, як kubelet обробляє видалення Podʼа.

Коли використовувати кожну пробу

Коли слід використовувати пробу запуску?

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

Якщо ваш контейнер зазвичай запускається більше ніж \( initialDelaySeconds + failureThreshold \times periodSeconds \), слід вказати пробу запуску, яка перевіряє ту саму точку доступу, що й проба життєздатності. Стандартне значення для periodSeconds становить 10 секунд. Потім слід встановити failureThreshold достатньо високим, щоб дозволити контейнеру запуститися, не змінюючи стандартне значення для проби життєздатності. Це допомагає захиститися від взаємних блокувань.

Коли слід використовувати пробу життєздатності?

Якщо процес у вашому контейнері може самостійно аварійно завершуватися, щойно виникає проблема або він стає несправним, вам не обовʼязково потрібна проба життєздатності; kubelet автоматично виконає правильну дію відповідно до restartPolicy Podʼа.

Якщо ви хочете, щоб ваш контейнер був завершений і перезапущений у разі невдачі проби, тоді використовуйте пробу життєздатності та встановіть restartPolicy на Always або OnFailure.

Поширеним підходом для проб життєздатності є використання тієї самої низьковитратної точки доступу HTTP, що й для проб готовності, але з вищим failureThreshold. Це гарантує, що Pod вважатиметься неготовим протягом певного часу, перш ніж його буде примусово завершено.

Коли слід використовувати пробу готовності?

Щоб почати надсилати трафік до Podʼа лише після успішного проходження проби, вкажіть пробу готовності. Проба готовності може бути такою ж, як і проба життєздатності, але наявність проби готовності в специфікації означає, що Pod почне працювати без отримання трафіку і почне отримувати трафік лише після того, як проба почне успішно проходити.

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

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

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

Механізми перевірки

Існує чотири різні способи перевірки контейнера за допомогою проб. Кожна проба повинна визначати точно один із цих чотирьох механізмів:

exec
Виконує вказану команду всередині контейнера. Діагностика вважається успішною, якщо команда завершується з кодом стану 0.
grpc
Виконує віддалений виклик процедури за допомогою gRPC. Цільовий обʼєкт повинен реалізовувати перевірки стану gRPC. Діагностика вважається успішною, якщо status відповіді дорівнює SERVING. Для отримання додаткової інформації див. gRPC-проби.
httpGet
Виконує запит HTTP GET до IP-адреси Podʼа на вказаному порту та шляху. Діагностика вважається успішною, якщо відповідь має код стану від 200 до 399 включно. Для отримання додаткової інформації див. HTTP-проби.
tcpSocket
Виконує перевірку TCP на IP-адресу Podʼа на вказаному порту. Діагностика вважається успішною, якщо порт відкритий. Якщо віддалена система (контейнер) закриває зʼєднання відразу після його відкриття, це також вважається справним станом. Для отримання додаткової інформації див. TCP-проби.

Увага:

На відміну від інших механізмів, реалізація проби exec передбачає створення/відгалуження кількох процесів під час кожного виконання. В результаті, у випадку кластерів з високою щільністю Podʼів, меншими інтервалами initialDelaySeconds, periodSeconds, налаштування будь-якої проби з механізмом exec може призвести до збільшення навантаження на CPU вузла. У таких сценаріях розгляньте можливість використання альтернативних механізмів проб, щоб уникнути цих накладних витрат.

Результати проб

Kubelet оцінює результат виконання кожної проби та діє відповідно. Кожна проба має один із трьох результатів:

Success
Контейнер пройшов діагностику.
Failure
Контейнер не пройшов діагностику. Для проб життєздатності та запуску kubelet завершує контейнер, і до нього застосовується його політика перезапуску. Для проб готовності kubelet позначає контейнер як неготовий, і Pod перестає отримувати трафік від відповідних Services.
Unknown
Діагностика не вдалася (жодних дій не слід виконувати, kubelet здійснить подальші перевірки).

Якщо контейнер не надає певну пробу, kubelet завжди вважає результат Success. Для проб готовності, зокрема, результат вважається Failure до закінчення початкової затримки.

Поля конфігурації

Проби мають ряд полів, які можна використовувати для більш точного контролю поведінки перевірок запуску, життєздатності та готовності. Наприклад:

apiVersion: v1
kind: Pod
metadata:
  name: probe-example
spec:
  containers:
  - name: app
    image: registry.k8s.io/e2e-test-images/agnhost:2.40
    ports:
    - containerPort: 8080
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30
      periodSeconds: 10
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 5
      timeoutSeconds: 3
      failureThreshold: 3
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      periodSeconds: 5
initialDelaySeconds
Кількість секунд після запуску контейнера, перш ніж будуть ініційовані проби запуску, життєздатності або готовності. Якщо визначена проба запуску, затримки проб життєздатності та готовності не починаються, поки проба запуску не буде успішною. У деяких старих версіях Kubernetes initialDelaySeconds може ігноруватися, якщо periodSeconds було встановлено на значення більше, ніж initialDelaySeconds. Однак у поточних версіях initialDelaySeconds завжди враховується, і проба не почнеться до закінчення цієї початкової затримки. Стандартне значення — 0 секунд. Мінімальне значення — 0.
periodSeconds
Як часто (у секундах) виконувати пробу. Стандартно — 10 секунд. Мінімальне значення — 1. Поки контейнер не готовий, проба готовності може виконуватися в інший час, ніж налаштований інтервал periodSeconds. Це робиться для того, щоб Pod став готовим швидше.
timeoutSeconds
Кількість секунд, після яких проба вважається такою, що перевищила час очікування. Стандартне значення — 1 секунда. Мінімальне значення — 1.
successThreshold
Мінімальна кількість послідовних успішних спроб, щоб проба вважалася успішною після невдачі. Стандартне значення — 1. Для проб життєздатності та запуску має бути 1. Мінімальне значення — 1.
failureThreshold
Після того, як проба не вдалася failureThreshold разів поспіль, Kubernetes вважає, що загальна перевірка не вдалася: контейнер не готовий/справний/живий. Стандартне значення — 3. Мінімальне значення — 1. У випадку проби запуску або життєздатності, якщо принаймні failureThreshold проб не вдалося, Kubernetes вважає контейнер несправним і запускає перезапуск для цього конкретного контейнера. Kubelet дотримується налаштування terminationGracePeriodSeconds для цього контейнера. Для невдалої проби готовності kubelet продовжує виконувати контейнер, який не пройшов перевірку, і також продовжує виконувати інші проби; оскільки перевірка не вдалася, kubelet встановлює стан Ready для Podʼа у значення false.
terminationGracePeriodSeconds
Налаштуйте період очікування для kubelet між ініціюванням завершення роботи несправного контейнера та примусовою зупинкою цього контейнера середовищем виконання контейнерів. Стандартно успадковується значення на рівні Podʼа для terminationGracePeriodSeconds (30 секунд, якщо не вказано), а мінімальне значення — 1. Див. terminationGracePeriodSeconds на рівні проби для детальнішої інформації.

Увага:

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

terminationGracePeriodSeconds на рівні проби

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.28

У версіях 1.25 і вище користувачі можуть вказати terminationGracePeriodSeconds на рівні проби як частину специфікації проби. Коли встановлені обидва значення terminationGracePeriodSeconds на рівні Podʼа і проби, kubelet використовує значення на рівні проби.

Під час встановлення terminationGracePeriodSeconds зверніть увагу на таке:

  • Kubelet завжди враховує поле terminationGracePeriodSeconds на рівні проби, якщо воно присутнє в Podʼі.
  • Якщо у вас є наявні Podʼи, де встановлено поле terminationGracePeriodSeconds, і ви більше не бажаєте використовувати періоди очікування завершення роботи на рівні проби, вам потрібно видалити ці Podʼи.

Наприклад:

spec:
  terminationGracePeriodSeconds: 3600  # рівень Podʼа
  containers:
  - name: test
    image: ...

    ports:
    - name: liveness-port
      containerPort: 8080

    livenessProbe:
      httpGet:
        path: /healthz
        port: liveness-port
      failureThreshold: 1
      periodSeconds: 60
      # Перевизначення значення terminationGracePeriodSeconds на рівні Podʼа
      terminationGracePeriodSeconds: 60

Значення terminationGracePeriodSeconds на рівні проби не може бути встановлено для проб готовності. Воно буде відхилено API-сервером.

Деталі механізму проб

HTTP-проби

HTTP-проби мають додаткові поля, які можна встановити в httpGet:

  • host: Імʼя хоста для підключення, стандартно IP-адреса Podʼа. Ймовірно, ви захочете встановити "Host" у httpHeaders замість цього.
  • scheme: Схема для підключення до хоста (HTTP або HTTPS). Стандартно "HTTP".
  • path: Шлях для доступу до HTTP-сервера. Стандартно "/".
  • httpHeaders: Власні заголовки для встановлення в запиті. HTTP дозволяє повторювані заголовки.
  • port: Назва або номер порту для доступу до контейнера. Номер повинен бути в діапазоні від 1 до 65535.
  • protocol: Протокол для використання в запиті проби. Стандартно HTTP1. Встановіть HTTP2, щоб виконувати пробу через HTTP/2 без шифрування (h2c). Вимагає увімкнення функціональної можливості H2CContainerProbe.

Для HTTP-проби kubelet надсилає HTTP-запит на вказаний порт і шлях для виконання перевірки. Kubelet надсилає пробу на IP-адресу Podʼа, якщо адреса не перевизначена за допомогою необовʼязкового поля host у httpGet. Якщо поле scheme встановлено в HTTPS, kubelet надсилає HTTPS-запит, пропускаючи перевірку сертифіката. У більшості сценаріїв ви не захочете встановлювати поле host. Ось один сценарій, де ви б його встановили. Припустимо, контейнер слухає на 127.0.0.1, а поле hostNetwork Podʼа встановлено в true. Тоді host у httpGet слід встановити на 127.0.0.1. Якщо ваш Pod покладається на віртуальні хости, що, ймовірно, є більш поширеним випадком, ви не повинні використовувати host, а натомість встановити заголовок Host у httpHeaders.

Для HTTP-проби kubelet надсилає два заголовки запиту на додачу до обовʼязкового заголовка Host:

  • User-Agent, який стандартно дорівнює kube-probe/1.37, де 1.37 — це версія kubelet.
  • Accept, який стандартно дорівнює */*.

Ви можете перевизначити ці заголовки, визначивши httpHeaders для проби. Наприклад:

livenessProbe:
  httpGet:
    httpHeaders:
      - name: Accept
        value: application/json

startupProbe:
  httpGet:
    httpHeaders:
      - name: User-Agent
        value: MyUserAgent

Ви також можете видалити ці два заголовки, визначивши їх з порожнім значенням.

livenessProbe:
  httpGet:
    httpHeaders:
      - name: Accept
        value: ""

startupProbe:
  httpGet:
    httpHeaders:
      - name: User-Agent
        value: ""
СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the H2CContainerProbe feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Ви можете налаштувати HTTP-пробу для використання HTTP/2 без шифрування (h2c), встановивши поле protocol на HTTP2. Коли protocol встановлено на HTTP2, kubelet використовує h2c (HTTP/2 через звичайний TCP) замість HTTP/1.1. Типове значення protocol — HTTP1. Встановлення protocol: HTTP2 вимагає scheme: HTTP (типове значення); API-сервер відхиляє комбінацію protocol: HTTP2 з scheme: HTTPS. Для отримання додаткових відомостей див. Використання HTTP/2 без шифрування (h2c) з HTTP-пробами.

Обробка перенаправлень

Коли kubelet перевіряє контейнер за допомогою HTTP, він слідує за перенаправленнями лише у випадку, якщо перенаправлення відбувається на той самий хост. Це включає перенаправлення, які змінюють протокол з HTTP на HTTPS, навіть якщо проба налаштована з scheme: HTTP.

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

Якщо kubelet слідує за перенаправленням і отримує 11 або більше перенаправлень загалом, проба вважається успішною і записується подія ProbeWarning. Наприклад:

Events:
  Type     Reason        Age                     From               Message
  ----     ------        ----                    ----               -------
  Normal   Scheduled     29m                     default-scheduler  Successfully assigned default/httpbin-7b8bc9cb85-bjzwn to daocloud
  Normal   Pulling       29m                     kubelet            Pulling image "docker.io/kennethreitz/httpbin"
  Normal   Pulled        24m                     kubelet            Successfully pulled image "docker.io/kennethreitz/httpbin" in 5m12.402735213s
  Normal   Created       24m                     kubelet            Created container httpbin
  Normal   Started       24m                     kubelet            Started container httpbin
 Warning  ProbeWarning  4m11s (x1197 over 24m)  kubelet            Readiness probe warning: Probe terminated redirects

Увага:

Під час обробки проби httpGet kubelet припиняє читання тіла відповіді після 10KiB. Успішність проби визначається виключно кодом стану відповіді, який знаходиться в заголовках відповіді.

Якщо ви перевіряєте точку доступу, що повертає тіло відповіді більше ніж 10KiB, kubelet все одно позначить пробу як успішну на основі коду стану, але закриє зʼєднання після досягнення межі 10KiB. Це раптове закриття може спричинити появу в логах вашого застосунку помилок connection reset by peer або broken pipe errors, які важко відрізнити від реальних проблем мережі.

Для надійних проб httpGet наполегливо рекомендується використовувати спеціальні точки доступу перевірки стану, які повертають мінімальне тіло відповіді. Якщо ви повинні використовувати наявну точку доступу з великим обсягом даних, розгляньте можливість використання проби exec для виконання запиту HEAD замість цього.

TCP-проби

Для TCP-проби kubelet встановлює зʼєднання проби на вузлі, а не в Podʼі, що означає, що ви не можете використовувати назву сервісу в параметрі host, оскільки kubelet не може її розвʼязати.

gRPC-проби

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.27

Якщо ваш застосунок реалізує Протокол перевірки стану gRPC, ви можете налаштувати Kubernetes для використання його для перевірки запуску, життєздатності або готовності застосунку.

Ось приклад маніфесту:

apiVersion: v1
kind: Pod
metadata:
  name: etcd-with-grpc
spec:
  containers:
  - name: etcd
    image: registry.k8s.io/etcd:3.5.1-0
    command: [ "/usr/local/bin/etcd", "--data-dir",  "/var/lib/etcd", "--listen-client-urls", "http://0.0.0.0:2379", "--advertise-client-urls", "http://127.0.0.1:2379", "--log-level", "debug"]
    ports:
    - containerPort: 2379
    livenessProbe:
      grpc:
        port: 2379
      initialDelaySeconds: 10

Для використання gRPC-проби необхідно налаштувати port. Якщо ви хочете розрізняти проби різних типів і проби для різних функцій, ви можете використовувати поле service. Ви можете встановити service зі значенням liveness і налаштувати вашу точку доступу gRPC Health Checking так, щоб вона відповідала на цей запит інакше, ніж коли service має значення readiness. Це дозволяє використовувати ту саму точку доступу для різних видів перевірки стану контейнера, замість того щоб слухати на двох різних портах. Якщо ви хочете вказати власну назву сервісу та також вказати тип проби, проєкт Kubernetes рекомендує використовувати назву, яка обʼєднує ці значення. Наприклад: myservice-liveness (використовуючи - як роздільник).

Примітка:

На відміну від HTTP або TCP-проб, ви не можете вказати порт перевірки стану за назвою, і ви не можете налаштувати власне імʼя хоста.

Проблеми конфігурації (наприклад: неправильний порт або сервіс, не реалізований протокол перевірки стану) вважаються невдачею проби, подібно до HTTP та TCP-проб.

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GRPCContainerProbeTLS feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Ви можете налаштувати gRPC-пробу для підключення через TLS, встановивши поле mode на TLS. Коли mode встановлено на TLS, kubelet використовує TLS з InsecureSkipVerify (він не перевіряє сертифікат сервера). Типове значення mode — Plaintext. Для отримання додаткових відомостей див. Використання TLS з gRPC-пробами.

Що далі

1.7 - Порушення

Цей посібник призначений для власників застосунків, які хочуть створити високодоступні застосунки та, таким чином, повинні розуміти, які типи порушень можуть трапитися з Podʼами.

Також це стосується адміністраторів кластера, які хочуть виконувати автоматизовані дії з кластером, такі як оновлення та автомасштабування кластерів.

Добровільні та невідворотні порушення

Podʼи не зникають, поки хтось (людина або контролер) не знищить їх, або не трапиться невідворотна помилка обладнання чи системного програмного забезпечення.

Ми називаємо ці невідворотні випадки невідворотними порушеннями застосунку. Приклади:

  • апаратна відмова фізичної машини, на якій працює вузол
  • адміністратор кластера видаляє віртуальну машину (екземпляр) помилково
  • відмова хмарного провайдера або гіпервізора призводить до зникнення віртуальної машини
  • kernel panic
  • вузол зникає з кластера через поділ мережі кластера
  • виселення Podʼа через вичерпання ресурсів на вузлі.

Окрім вичерпання ресурсів, усі ці ситуації мають бути знайомі більшості користувачів; вони не є специфічними для Kubernetes.

Ми називаємо інші випадки добровільними порушеннями. До них належать як дії, ініційовані власником застосунку, так і ті, які ініціює адміністратор кластера. Типові дії власника застосунку включають:

  • видалення Deployment або іншого контролера, який керує Podʼом
  • оновлення шаблону Podʼа в Deployment, що призводить до перезапуску
  • безпосереднє видалення Podʼа (наприклад, випадково)

Дії адміністратора кластера включають:

  • Очищення вузла для ремонту чи оновлення.
  • Очищення вузла з кластера для зменшення масштабу кластера (дізнайтеся більше про автомасштабування вузлів).
  • Видалення Podʼа з вузла, щоб щось інше помістилося на цей вузол.

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

Зверніться до адміністратора кластера або проконсультуйтеся з документацією вашого хмарного провайдера або дистрибутиву, щоб визначити, чи увімкнено які-небудь джерела добровільних порушень для вашого кластера. Якщо жодне з них не увімкнено, ви можете пропустити створення бюджетів порушень Podʼів (Pod Disruption Budget).

Увага:

Не всі добровільні порушення обмежені бюджетами порушень Podʼів. Наприклад, видалення Deployment чи Pod обходить бюджети порушень Podʼів.

Робота з порушеннями

Ось кілька способів помʼякшення невідворотних порушень:

Частота добровільних порушень різниться. На базовому кластері Kubernetes немає автоматизованих добровільних порушень (тільки ті, які ініціює користувач). Однак адміністратор кластера або провайдер хостингу може запускати деякі додаткові сервіси, які призводять до добровільних порушень. Наприклад, розгортання оновлень програмного забезпечення вузла може призвести до добровільних порушень. Також деякі реалізації автомасштабування кластера (вузла) можуть призводити до добровільних порушень для дефрагментації та ущільнення вузлів. Адміністратор кластера або провайдер хостингу мають задокументувати, якого рівня добровільних порушень, якщо такі є, слід очікувати. Деякі параметри конфігурації, такі як використання PriorityClasses у вашій специфікації Podʼа, також можуть призводити до добровільних (і невідворотних) порушень.

Бюджети порушень Podʼів

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.21

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

Як власник застосунку, ви можете створити бюджет порушень Podʼів (PodDisruptionBudget, PDB) для кожного застосунку. PDB обмежує кількість Podʼів реплікованого застосунку, які можуть одночасно не працювати через добровільні порушення. Наприклад, застосунок на основі кворуму хоче гарантувати, що кількість запущених реплік ніколи не впаде нижче необхідної для кворуму. Вебфронтенд може хотіти гарантувати, що кількість реплік, які обслуговують навантаження, ніколи не впаде нижче певного відсотка від загальної кількості.

Менеджери кластерів та провайдери хостингу повинні використовувати інструменти, які дотримуються бюджетів порушень Podʼів, викликаючи Eviction API замість прямого видалення Podʼів або Deployments.

Наприклад, команда kubectl drain дозволяє вам позначити вузол як такий, що виводиться з експлуатації. Коли ви виконуєте kubectl drain, інструмент намагається виселити всі Podʼи з вузла, який ви виводите з експлуатації. Запит на виселення, який kubectl робить від вашого імені, може тимчасово бути відхилено, тому інструмент періодично повторює всі невдалі запити, доки всі Podʼи на цільовому вузлі не будуть завершені або доки не буде досягнуто налаштованого тайм-ауту.

PDB визначає кількість реплік, яку застосунок може витримати, порівняно з тим, скільки їх має бути. Наприклад, Deployment, який має .spec.replicas: 5, повинен мати 5 Podʼів в будь-який момент часу. Якщо PDB дозволяє бути 4 Podʼам одночасно, то Eviction API дозволить добровільне порушення роботи одного (але не двох) Podʼів одночасно.

Група Podʼів, з яких складається застосунок, визначається за допомогою селектора міток, такого самого, як і той, який використовується контролером застосунку (deployment, stateful-set тощо).

"Передбачена" кількість Podʼів обчислюється з .spec.replicas ресурсу робочого навантаження, який керує цими Podʼами. Панель управління визначає ресурс робочого навантаження, що володіє Podʼом, оглядаючи .metadata.ownerReferences Podʼа.

Невідворотні порушення неможливо запобігти за допомогою PDB; однак вони враховуються в бюджеті.

Podʼи, які видаляються або недоступні через поетапне оновлення застосунку, дійсно враховуються в бюджеті порушень, але ресурси робочого навантаження (такі як Deployment і StatefulSet) не обмежуються PDB під час поетапного оновлення. Натомість обробка збоїв під час оновлення застосунку налаштовується в специфікації конкретного ресурсу робочого навантаження.

Рекомендується встановлювати політику виселення несправних Podʼів AlwaysAllow у ваших PodDisruptionBudgets для підтримки виселення застосунків, що працюють неправильно, під час очищення вузла. Стандартно очищення чекає, доки Podʼи застосунку стануть справними, перш ніж продовжитися.

Коли Pod виселяється за допомогою API виселення, він коректно завершується з урахуванням налаштування terminationGracePeriodSeconds його PodSpec.

Приклад PodDisruptionBudget

Припустимо, що у кластері є 3 вузли, від node-1 до node-3. У кластері працює кілька застосунків. Один з них має 3 репліки, які спочатку називаються pod-a, pod-b і pod-c. Також показано інший, не повʼязаний з ними Pod без PDB — pod-x. Спочатку Podʼи розташовані так:

node-1node-2node-3
pod-a доступнийpod-b доступнийpod-c доступний
pod-x доступний

Усі 3 Podʼи є частиною Deployment, і вони разом мають PDB, який вимагає, щоб одночасно було доступними принаймні 2 з 3 Podʼів.

Наприклад, припустимо, що адміністратор кластера хоче перезавантажитися в нову версію ядра, щоб виправити помилку в ядрі. Адміністратор кластера спочатку намагається очистити node-1 за допомогою команди kubectl drain. Цей інструмент намагається виселити pod-a і pod-x. Це вдається негайно. Обидва Podʼи одночасно переходять у стан terminating. Це переводить кластер у стан:

node-1 очищуєтьсяnode-2node-3
pod-a завершуєтьсяpod-b доступнийpod-c доступний
pod-x завершується

Deployment помічає, що один з Podʼів завершується, тому він створює заміну під назвою pod-d. Оскільки node-1 закрито для планування (cordoned), заміна опиняється на іншому вузлі. Також щось створило pod-y як заміну для pod-x.

(Примітка: для StatefulSet, pod-a, який міг би мати назву щось на зразок pod-0, повинен був би повністю завершити свою роботу, перш ніж його заміна, яка також має назву pod-0, але має інший UID, може бути створена. В іншому випадку приклад застосовується і до StatefulSet.)

Тепер кластер перебуває у такому стані:

node-1 очищуєтьсяnode-2node-3
pod-a завершуєтьсяpod-b доступнийpod-c доступний
pod-x завершуєтьсяpod-d запускаєтьсяpod-y

У якийсь момент Podʼи завершують свою роботу, і кластер виглядає так:

node-1 очищенийnode-2node-3
pod-b доступнийpod-c доступний
pod-d запускаєтьсяpod-y

На цьому етапі, якщо нетерплячий адміністратор кластера намагається очистити node-2 або node-3, команда очищення буде заблокована, оскільки доступно тільки 2 Podʼи для Deployment, і його PDB вимагає принаймні 2. Після того, як пройде певний час, pod-d стає доступним.

Тепер стан кластера виглядає так:

node-1 очищенийnode-2node-3
pod-b доступнийpod-c доступний
pod-d доступнийpod-y

Тепер адміністратор кластера намагається очистити node-2. Команда drain спробує виселити два Podʼи в певному порядку, скажімо, спочатку pod-b, а потім pod-d. Їй вдасться виселити pod-b. Але коли вона спробує виселити pod-d, то отримає відмову, через те, що це залишить тільки один доступний Pod для Deployment.

Deployment створює заміну для pod-b з назвою pod-e. Оскільки в кластері недостатньо ресурсів для планування pod-e, очищення знову буде заблоковано. Кластер може опинитися в такому стані:

node-1 очищенийnode-2node-3немає вузла
pod-b завершуєтьсяpod-c доступнийpod-e очікує
pod-d доступнийpod-y

На цьому етапі адміністратор кластера повинен додати вузол назад до кластера, щоб продовжити оновлення.

Ви можете побачити, як Kubernetes змінює частоту випадків порушень відповідно до:

  • скільки реплік потрібно для застосунку
  • скільки часу потрібно для коректного вимкнення екземпляра
  • скільки часу потрібно для запуску нового екземпляра
  • типу контролера
  • місткості ресурсів кластера

Стани порушення роботи Podʼа

This is a stable feature in Kubernetes, and has been since the 1.31 release. You can no longer toggle this feature (the associated feature gate has been removed).

Спеціальний стан Podʼа DisruptionTarget додається для того, щоб вказати, що Pod буде видалено через порушення. Поле reason цього стану додатково вказує одну з таких причин завершення Podʼа:

PreemptionByScheduler
Pod має бути витіснений планувальником, щоб звільнити місце для нового Podʼа з вищим пріоритетом. Докладніше дивіться Витіснення за пріоритетом Podʼа.
DeletionByTaintManager
Pod має бути видалений Менеджером Taint (який є частиною контролера життєвого циклу вузла в kube-controller-manager) через NoExecute taint, який Pod не толерує; див. виселення на основі taint.
EvictionByEvictionAPI
Pod був позначений для виселення за допомогою API Kubernetes.
DeletionByPodGC
Pod, який повʼязаний із вузлом, якого вже не існує, має бути видалений за допомогою збору сміття Podʼів.
TerminationByKubelet
Pod було завершено kubelet через виселення внаслідок тиску на вузол, коректне вимкнення вузла або витіснення заради системно критичних Podʼів.

У всіх інших сценаріях порушення, таких як виселення через перевищення обмежень контейнерів Podʼа, Podʼи не отримують стан DisruptionTarget, оскільки ці порушення, ймовірно, були спричинені самим Podʼом і повторилися б під час повторної спроби.

Примітка:

Процес порушення роботи Podʼа може бути зупинено. Панель управління може повторно спробувати продовжити порушення роботи того самого Podʼа, але це не гарантовано. В результаті стан DisruptionTarget може бути додано до Podʼа, але цей Pod може фактично не бути видаленим. У такій ситуації через деякий час стан порушення роботи Podʼа буде очищено.

Разом з очищенням Podʼів механізм збору сміття Podʼів (PodGC) також позначає їх як невдалі, якщо вони перебувають у нетермінальній фазі (див. також збір сміття Podʼів).

Під час використання Job (або CronJob) ви можете використовувати ці стани порушення роботи Podʼів як частину політики збоїв Podʼа вашого Job.

Розділення ролей власника кластера та власника застосунку

Часто корисно розглядати менеджера кластера і власника застосунку як окремі ролі з обмеженим знанням одне про одного. Це розділення обовʼязків може мати сенс у таких сценаріях:

  • коли багато команд розробки застосунків використовують спільний кластер Kubernetes і є природна спеціалізація ролей
  • коли використовуються інструменти або сервіси сторонніх розробників для автоматизації управління кластером

Бюджети порушень Podʼів підтримують це розділення ролей, надаючи інтерфейс між цими ролями.

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

Як виконувати дії, що порушують роботу, у вашому кластері

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

  • Прийняти простій під час оновлення.
  • Перемикнутися на іншу повну репліку кластера.
    • Відсутність простою, але може бути дорогою як для дубльованих вузлів, так і для зусиль людей для оркестрування перемикання.
  • Розробляти застосунки, стійкі до порушень, і використовувати PDB.
    • Відсутність простою.
    • Мінімальне дублювання ресурсів.
    • Дозволяє більше автоматизації адміністрування кластера.
    • Написання застосунків, стійких до порушень, складне, але робота над стійкістю до добровільних порушень здебільшого збігається з роботою над підтримкою автомасштабування та стійкістю до невідворотних порушень.

Що далі

1.8 - Імʼя хоста Podʼа

Ця сторінка пояснює, як встановити імʼя хоста Podʼа, можливі побічні ефекти після налаштування та механізми, що лежать в основі.

Стандартне імʼя хоста Podʼа

Коли створюється Pod, імʼя його хоста (яке спостерігається зсередини Podʼа) походить від значення metadata.name Podʼа. І імʼя хоста, і відповідне повністю кваліфіковане доменне імʼя (FQDN) встановлюються у значення metadata.name (з точки зору Podʼа)

apiVersion: v1
kind: Pod
metadata:
  name: busybox-1
spec:
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox

Pod, створений цим маніфестом, матиме імʼя хоста та повністю кваліфіковане доменне імʼя (FQDN) встановлені як busybox-1.

Імʼя хоста з полями hostname та subdomain Podʼа

Специфікація Podʼа включає необовʼязкове поле hostname. Коли воно встановлене, це значення має пріоритет над metadata.name Podʼа як імʼя хоста (яке спостерігається зсередини Podʼа). Наприклад, Pod з spec.hostname встановленим як my-host матиме імʼя хоста встановлене як my-host.

Специфікація Podʼа також включає необовʼязкове поле subdomain, яке вказує, що Pod належить до піддомену в межах свого простору імен. Якщо Pod має spec.hostname встановлений як "foo" і spec.subdomain встановлений як "bar" у просторі імен my-namespace, імʼя його хоста стає foo, а його повністю кваліфіковане доменне імʼя (FQDN) стає foo.bar.my-namespace.svc.cluster-domain.example (спостерігається зсередини Podʼа).

Коли встановлені і hostname, і subdomain, DNS-сервер кластера створить записи A та/або AAAA на основі цих полів. Дивіться: Поля hostname та subdomain Podʼа.

Імʼя хоста з полем setHostnameAsFQDN Podʼа

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.22

Коли Pod налаштований на використання повністю кваліфікованого доменного імені (FQDN), його імʼя хоста є коротким імʼям хоста. Наприклад, якщо у вас є Pod з повністю кваліфікованим доменним імʼям busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example, то стандартно команда hostname всередині цього Podʼа повертає busybox-1, а команда hostname --fqdn повертає FQDN.

Коли в специфікації Podʼа встановлено і setHostnameAsFQDN: true, і поле subdomain, kubelet записує FQDN Podʼа як імʼя хоста для простору імен цього Podʼа. У цьому випадку і hostname, і hostname --fqdn повертають FQDN Podʼа.

FQDN Podʼа будується так само, як було визначено раніше. Воно складається з поля spec.hostname Podʼа (якщо вказано) або поля metadata.name, spec.subdomain, назви простору імен та суфікса домену кластера.

Примітка:

У Linux поле імені хоста ядра (поле nodename структури utsname) обмежено 64 символами.

Якщо Pod вмикає цю функцію, а його FQDN довший за 64 символи, він не зможе запуститися. Pod залишатиметься в статусі Pending (відображається як ContainerCreating через kubectl), генеруючи події помилок, такі як "Failed to construct FQDN from Pod hostname and cluster domain".

Це означає, що під час використання цього поля ви повинні переконатися, що сумарна довжина полів metadata.name (або spec.hostname) та spec.subdomain Podʼа не призводить до появи FQDN, що перевищує 64 символи.

Імʼя хоста з полем hostnameOverride Podʼа

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.37; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.37. It was first available in the v1.34 release.

Встановлення значення для hostnameOverride в специфікації Podʼа змушує kubelet безумовно встановлювати як імʼя хоста, так і повністю кваліфіковане доменне імʼя (FQDN) Podʼа у значення hostnameOverride.

Поле hostnameOverride має обмеження довжини 64 символи і повинно відповідати стандарту імен піддоменів DNS, визначеному в RFC 1123.

Приклад:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-2-busybox-example-domain
spec:
  hostnameOverride: busybox-2.busybox.example.domain
  containers:
  - image: busybox:1.28
    command:
      - sleep
      - "3600"
    name: busybox

Примітка:

Це впливає лише на імʼя хоста всередині Podʼа; це не впливає на записи A або AAAA Podʼа в DNS-сервері кластера.

Якщо hostnameOverride встановлено разом з полями hostname та subdomain:

  • Імʼя хоста всередині Podʼа перевизначається значенням hostnameOverride.

  • Записи A та/або AAAA Podʼа в DNS-сервері кластера все ще генеруються на основі полів hostname та subdomain.

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

Для деталей щодо поведінки, коли hostnameOverride встановлено в комбінації з іншими полями (hostname, subdomain, setHostnameAsFQDN, hostNetwork), див. таблицю в деталях проєкту KEP-4762.

1.9 - Класи якості обслуговування (Quality of Service) Podʼів

Ця сторінка представляє класи якості обслуговування (Quality of Service, QoS) в Kubernetes та пояснює, як Kubernetes присвоює кожному Podʼу клас QoS як наслідок обмежень ресурсів, які ви вказуєте для контейнерів у цьому Podʼі. Kubernetes покладається на цю класифікацію для прийняття рішень про те, які Podʼи виселяти, коли на вузлі бракує доступних ресурсів.

Класи якості обслуговування

Kubernetes класифікує Podʼи, які ви запускаєте, і розподіляє кожен Pod у певний клас якості обслуговування (quality of service, QoS). Kubernetes використовує цю класифікацію, щоб впливати на те, як обробляються різні Podʼи. Kubernetes робить цю класифікацію на основі запитів ресурсів контейнерів у цьому Podʼі, а також того, як ці запити співвідносяться з обмеженнями ресурсів. Це відомо як клас якості обслуговування (QoS). Kubernetes присвоює кожному Podʼу клас QoS на основі запитів та обмежень ресурсів його складових контейнерів. Kubernetes використовує класи QoS, щоб вирішити, які Podʼи виселяти з вузла, що перебуває під тиском на вузол. Можливі класи QoS: Guaranteed, Burstable та BestEffort. Коли на вузлі закінчуються ресурси, Kubernetes спочатку виселяє Podʼи BestEffort, що працюють на цьому вузлі, потім Burstable і нарешті Guaranteed. Коли це виселення спричинене тиском на ресурси, кандидатами на виселення є лише Podʼи, що перевищують запити ресурсів.

Guaranteed

Podʼи, які мають клас Guaranteed, мають найстрогіші обмеження ресурсів і найменшу ймовірність бути виселеними. Гарантується, що їх не буде завершено, доки вони не перевищать свої обмеження або доки не залишиться Podʼів з нижчим пріоритетом, які можна витіснити з вузла. Вони не можуть отримувати ресурси понад вказані обмеження. Ці Podʼи також можуть використовувати ексклюзивні CPU за допомогою політику управління CPU типу static.

Критерії

Щоб Pod отримав клас QoS Guaranteed:

  • Кожен контейнер в Podʼі повинен мати обмеження та запит на памʼять, обидва більші за нуль.
  • Для кожного контейнера у Podʼі обмеження памʼяті повинен дорівнювати запиту памʼяті.
  • Кожен контейнер в Podʼі повинен мати обмеження та запит на CPU, обидва більші за нуль.
  • Для кожного контейнера у Podʼі обмеження CPU повинен дорівнювати запиту CPU.

Якщо ж Pod використовує ресурси на рівні Podʼа:

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.34; (стандартно увімкнено)
  • Pod повинен мати обмеження памʼяті на рівні Podʼа і запит на памʼять, і їхні значення повинні бути рівними.
  • Pod повинен мати обмеження та запит CPU на рівні Podʼа, і їхні значення повинні бути рівними.

Burstable

Podʼи, які мають клас Burstable, мають певні гарантії нижньої межі ресурсів на основі запиту, але не вимагають конкретного обмеження. Якщо обмеження не вказано, стандартно воно дорівнює місткості вузла, що дозволяє Podʼам гнучко збільшувати свої ресурси, якщо ті доступні. У разі виселення Podʼа через тиск на ресурси вузла ці Podʼи виселяються лише після виселення всіх Podʼів з класом BestEffort. Оскільки Burstable Pod може містити контейнер, який не має обмежень чи запитів ресурсів, Pod з класом Burstable може намагатися використовувати будь-яку кількість ресурсів вузла.

Критерії

Pod отримує клас QoS Burstable, якщо:

  • Pod не відповідає критеріям класу QoS Guaranteed.
  • Принаймні один контейнер у Podʼі має запит або обмеження памʼяті чи CPU, або Pod має запит або обмеження памʼяті чи CPU на рівні Podʼа.

BestEffort

Podʼи в класі BestEffort можуть використовувати ресурси вузла, які не призначені спеціально для Podʼів інших класів QoS. Наприклад, якщо у вас є вузол із 16 ядрами CPU, доступними для kubelet, і ви призначили 4 ядра CPU Podʼу з класом Guaranteed, Pod у класі QoS BestEffort може намагатися використовувати будь-яку кількість із решти 12 ядер CPU.

Kubelet віддає перевагу виселенню Podʼів з класом BestEffort, якщо вузол потрапляє в стан тиску на ресурси.

Критерії

Pod має клас QoS BestEffort, якщо він не відповідає критеріям ані Guaranteed, ані Burstable. Іншими словами, Pod має клас BestEffort лише в тому випадку, якщо жоден з контейнерів у Podʼі не має обмеження або запиту памʼяті, і жоден з контейнерів у Podʼі не має обмеження або запиту CPU, а Pod не має жодних обмежень або запитів щодо памʼяті або CPU на рівні Podʼа. Контейнери в Podʼі можуть запитувати інші ресурси (не CPU чи памʼять) і все одно класифікуватися як BestEffort.

Memory QoS з cgroup v2

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно увімкнено)

Memory QoS використовує контролер памʼяті cgroup v2 для керування тротлінгом і захистом памʼяті в Kubernetes. Ця функція використовує клас QoS Podʼа для визначення, які налаштування cgroup слід застосувати, але вона не впливає на класифікацію Podʼів.

Типова конфігурація kubelet не вмикає тротлінг памʼяті або захист памʼяті. Щоб увімкнути будь-яку з цих поведінок, налаштуйте memoryThrottlingFactor або memoryReservationPolicy відповідно.

Тротлінг памʼяті

Тротлінг памʼяті контролюється полем конфігурації kubelet memoryThrottlingFactor. Його типове значення — nil, що означає, що kubelet не встановлює memory.high. Щоб увімкнути тротлінг памʼяті, встановіть memoryThrottlingFactor у значення більше 0 та менше або рівне 1.

Для Podʼів типу Burstable kubelet використовує memory.high, щоб застосувати тротлінг до виділення памʼяті до того, як робоче навантаження досягне свого жорсткого обмеження (memory.max). Поріг тротлінгу для контейнера обчислюється за такою формулою:

memory.high = requests + memoryThrottlingFactor * (limits - requests)

Наприклад, з memoryThrottlingFactor, встановленим на 0.9, контейнер із запитом 256 MiB і обмеженням 1 GiB отримає memory.high, встановлений приблизно на 947 MiB. Якщо контейнер Burstable не має обмеження памʼяті, kubelet використовує доступну для розподілу памʼять вузла замість обмеження.

Для контейнерів BestEffort, які не мають запиту або обмеження памʼяті, kubelet обчислює memory.high, використовуючи нульовий запит та доступну для розподілу памʼять вузла замість обмеження. Контейнери Guaranteed не отримують memory.high, оскільки їхні запити дорівнюють обмеженням.

Налаштування резервування памʼяті

Резервування памʼяті контролюється через поле конфігурації kubelet memoryReservationPolicy:

  • None (стандартно): kubelet не встановлює memory.min або memory.low для контейнерів і Podʼів. Жодна памʼять не блокується ядром жорстко.
  • TieredReservation: kubelet встановлює багаторівневий захист памʼяті на основі класу QoS Podʼа:
    • Podʼи Guaranteed: memory.min встановлюється на запити памʼяті. Ядро не буде звільняти цю памʼять за жодних обставин.
    • Podʼи Burstable: memory.low встановлюється на запити памʼяті. Ядро переважно зберігає цю памʼять, але може звільнити її за надзвичайного тиску.
    • Podʼи BestEffort: захист памʼяті не встановлюється.

Наприклад, така конфігурація kubelet вмикає тротлінг памʼяті з коефіцієнтом 0.9 та багаторівневий захист памʼяті:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
memoryThrottlingFactor: 0.9
memoryReservationPolicy: TieredReservation

Ви можете налаштовувати кожне поле незалежно. Опустіть memoryThrottlingFactor, щоб kubelet не встановлював memory.high, або встановіть memoryReservationPolicy: None, щоб вимкнути захист памʼяті.

Оскільки захист памʼяті cgroup v2 є ієрархічним, kubelet також налаштовує батьківські cgroup. Він встановлює memory.min на кореневій cgroup kubepods як суму запитів памʼяті для Podʼів Guaranteed та Burstable. Він встановлює memory.low на кореневій cgroup kubepods та cgroup QoS Burstable як суму запитів памʼяті для Podʼів Burstable. Без такого покриття батьківських cgroup захист на рівні Podʼа та контейнера був би неефективним.

Увага:

Для Podʼа Guaranteed запити памʼяті дорівнюють обмеженням памʼяті. З memoryReservationPolicy: TieredReservation memory.min тому дорівнює memory.max. Для робочого навантаження, яке використовує великий кеш сторінок, ядро може бути не в змозі звільнити достатньо кешу сторінок, перш ніж cgroup досягне memory.max, що може призвести до завершення через OOM (OOM kill). Встановіть обмеження памʼяті так, щоб включити достатній запас для кешу сторінок.

Вимкнення або відкочування Memory QoS

Щоб вимкнути Memory QoS, встановіть функціональну можливість MemoryQoS на false, переконайтеся, що memoryReservationPolicy не встановлено або встановлено у None, та перезапустіть kubelet. Під час запуску kubelet скидає memory.min та memory.low на кореневій cgroup kubepods та memory.low на cgroup QoS Burstable до нуля. Значення memory.min та memory.low на рівні Podʼа та контейнера можуть залишатися, але вони неефективні, оскільки відповідний захист батьківських cgroup дорівнює нулю.

Коли Memory QoS вимкнено, kubelet встановлює memory.high на max щоразу, коли середовище виконання контейнерів застосовує конфігурацію ресурсів до нового, перезапущеного або зміненого на місці контейнера. Вже запущений контейнер, який не перезапускається та не змінює розмір, може зберігати своє попереднє значення memory.high до наступного перезапуску або зміни розміру на місці.

Системні вимоги

Для роботи Memory QoS необхідна версія Linux із cgroup v2. Рекомендується використовувати ядро версії 5.9 або вище, оскільки обмеження memory.high у старих версіях ядра може спричинити відому помилку livelock. Якщо функція MemoryQoS увімкнена на старішому ядрі, kubelet записує попередження в лог під час запуску.

Деяка поведінка незалежна від класу QoS

Деяка поведінка є незалежною від класу QoS, який визначає Kubernetes. Наприклад:

  • Будь-який контейнер, що перевищує обмеження ресурсів, буде завершено та перезапущено kubelet без впливу на інші контейнери в цьому Podʼі.

  • Якщо контейнер перевищує свій запит ресурсу і вузол, на якому він працює, стикається з нестачею ресурсів, Pod, в якому він перебуває, стає кандидатом для виселення. Якщо це станеться, всі контейнери в цьому Podʼі будуть завершені. Kubernetes може створити новий Pod, зазвичай на іншому вузлі.

  • Запит ресурсів Podʼа дорівнює сумі запитів ресурсів його складових контейнерів, а обмеження Podʼа дорівнює сумі обмежень ресурсів його складових контейнерів.

  • Планувальник kube-scheduler не враховує клас QoS під час вибору того, які Podʼи витіснити. Витіснення може відбуватися, коли кластер не має достатньо ресурсів для запуску всіх визначених вами Podʼів.

  • Клас QoS визначається під час створення Podʼа і залишається незмінним протягом усього терміну існування Podʼа. Якщо пізніше ви спробуєте виконати зміну розміру на місці, що призведе до зміни класу QoS, зміна розміру буде відхилена під час перевірки допуску.

Що далі

1.10 - Група планування

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Ви можете повʼязати Pod з PodGroup, щоб вказати, що Pod належить до групи Pods, які плануються разом. Це дозволяє планувальнику застосовувати політики на рівні групи, такі як групове планування, замість того, щоб розглядати кожен Pod окремо.

Визначення групи планування

Коли увімкнено функціональну можливість GenericWorkload, ви можете встановити поле spec.schedulingGroup у маніфесті Pod. Це поле встановлює звʼязок із конкретним обʼєктом PodGroup у тому самому просторі імен за назвою.

apiVersion: v1
kind: Pod
metadata:
  name: worker-0
  namespace: some-ns
spec:
  schedulingGroup:
    podGroupName: training-worker-0
  containers:
  - name: ml-worker
    image: training:v1

Поле schedulingGroup є незмінним. Після встановлення Pod не можна перемістити до іншого PodGroup.

Поведінка

Коли ви встановлюєте spec.schedulingGroup, планувальник шукає вказаний PodGroup і застосовує визначену в ньому політику планування:

  • Якщо PodGroup використовує політику basic, кожен Pod планується незалежно, використовуючи стандартну поведінку Kubernetes. Групування використовується як мітка на рівні групи.
  • Якщо PodGroup використовує політику gang, Pod входить у життєвий цикл планування "все або нічого". Планувальник намагається розмістити принаймні minCount Pods у групі одночасно; жоден з них не привʼязується до вузлів, якщо мінімум не досягнуто.
СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли функціональну можливість CompositePodGroup увімкнено, PodGroup також може вказувати батьківський CompositePodGroup. В ієрархічному робочому навантаженні планування регулюється політиками, визначеними для всього дерева груп (такими як багаторівневе групове планування або обмеження топології).

Відсутні посилання на групи

Якщо Pod посилається на PodGroup, що ще не існує, Pod залишається в стані очікування. Аналогічно, якщо згаданий PodGroup вказує батьківський CompositePodGroup (через spec.parentCompositePodGroupName), який ще не створено, планування не починається, і Pod залишається в стані очікування, доки вся ієрархія груп не існуватиме в кластері.

Планувальник автоматично розглядає Pod повторно, щойно всі необхідні ресурси PodGroup та CompositePodGroup будуть існувати.

Що далі

1.11 - Статичні Podʼи

Статичні Podʼи (Static Pods) керуються безпосередньо демоном kubelet на конкретному вузлі, без спостереження за ними з боку API-сервера. На відміну від Podʼів, які керуються панеллю управління (наприклад, Deployment), kubelet стежить за кожним статичним Podʼом і перезапускає його у разі збою.

Статичні Podʼи завжди привʼязані до одного kubelet на конкретному вузлі.

Основне призначення статичних Podʼів — запуск самостійно розміщеної панелі управління: іншими словами, використання kubelet для контролю окремих компонентів панелі управління. Наприклад, kubeadm використовує статичні Podʼи для запуску kube-apiserver, kube-controller-manager, kube-scheduler та etcd на вузлах панелі управління.

Примітка:

Якщо ваш кластер запускає компоненти панелі управління як Podʼи, вони, ймовірно, є статичними Podʼами. Ви можете розпізнати їхні дзеркальні Podʼи в просторі імен kube-system за анотацією kubernetes.io/config.mirror.

Дзеркальні Podʼи

Kubelet автоматично намагається створити дзеркальний Pod на API-сервері Kubernetes для кожного статичного Podʼа. Це означає, що Podʼи, що працюють на вузлі, видимі на API-сервері, але керувати ними звідти не можна. До назв Podʼів буде додано імʼя хоста вузла з дефісом перед ним.

Kubelet передає мітки зі статичного Podʼа до дзеркального Podʼа. Ви можете використовувати ці мітки як зазвичай через селектори.

Якщо ви спробуєте використати kubectl для видалення дзеркального Podʼа з API-сервера, kubelet не видалить статичний Pod. Kubelet створить дзеркальний Pod заново.

Обмеження

Специфікація статичного Podʼа не може посилатися на інші обʼєкти API, такі як ServiceAccount, ConfigMap або Secret.

Статичні Podʼи не підтримують ефемерні контейнери.

Статичні Podʼи чи DaemonSets

Якщо ви запускаєте кластер Kubernetes і використовуєте статичні Podʼи для запуску Podʼів на кожному вузлі, вам, ймовірно, слід натомість використовувати DaemonSet.

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

Статичні Podʼи запускаються kubelet до того, як API-сервер стане доступним, що робить їх придатними для ініціалізації компонентів панелі управління. DaemonSets потребують запущеної панелі управління.

Що далі

1.12 - Простори імен користувачів

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.36
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.36. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate UserNamespacesSupport, Kubernetes ignores it but does not report any error.

Ця сторінка пояснює, як використовуються простори імен користувачів у Podʼах Kubernetes. Простір імен користувачів ізолює користувача, який працює всередині контейнера, від користувача на хості.

Процес, який працює як root у контейнері, може працювати на хості як інший користувач (не root); іншими словами, процес має повні привілеї для операцій всередині простору імен користувачів, але не має привілеїв для операцій за його межами.

Ви можете використовувати цю функцію, щоб зменшити шкоду, яку скомпрометований контейнер може заподіяти хосту або іншим Podʼам на тому самому вузлі. Є кілька вразливостей безпеки, які оцінено як ВИСОКІ або КРИТИЧНІ, і які неможливо було використати, коли простори імен користувачів активні. Очікується, що простори імен користувачів також помʼякшуватимуть деякі майбутні вразливості.

Перш ніж ви розпочнете

Примітка: Цей розділ містить посилання на проєкти сторонніх розробників, які надають функціонал, необхідний для Kubernetes. Автори проєкту Kubernetes не несуть відповідальності за ці проєкти. Проєкти вказано в алфавітному порядку. Щоб додати проєкт до цього списку, ознайомтеся з посібником з контенту перед надсиланням змін. Докладніше.

Це функція, доступна лише для Linux, і потребує підтримки в Linux для монтування idmap на використовуваних файлових системах. Це означає:

  • На вузлі файлова система, яку ви використовуєте для /var/lib/kubelet/pods/, або власна тека, яку ви налаштовуєте для цього, повинна підтримувати монтування idmap.
  • Всі файлові системи, які використовуються в томах Podʼа, повинні підтримувати монтування idmap.

На практиці це означає, що вам потрібне ядро Linux принаймні версії 6.3, оскільки tmpfs почав підтримувати монтування idmap у цій версії. Це зазвичай потрібно, оскільки кілька функцій Kubernetes використовують tmpfs (токен ServiceAccount, який монтується стандартно, використовує tmpfs, Secrets також використовують tmpfs тощо).

Деякі популярні файлові системи, які підтримують монтування idmap в Linux 6.3, — це: btrfs, ext4, xfs, fat, tmpfs, overlayfs.

Крім того, середовище виконання контейнерів та його базове середовище виконання OCI повинні підтримувати простори імен користувачів. Підтримку надають такі середовища виконання OCI:

  • crun версії 1.9 або вище (рекомендована версія 1.13+).
  • runc версії 1.2 або вище.

Для використання просторів імен користувачів з Kubernetes також потрібне середовище виконання контейнерів CRI, щоб використовувати цю функцію з Podʼами Kubernetes:

  • containerd: версія 2.0 (і новіші) підтримує простори імен користувачів для контейнерів.
  • CRI-O: версія 1.25 (і новіші) підтримує простори імен користувачів для контейнерів.

Стан підтримки просторів імен користувачів в cri-dockerd відстежується у тікеті на GitHub.

Вступ

Простори імен користувачів — це функція Linux, яка дозволяє зіставляти користувачів у контейнері з іншими користувачами на хості. Крім того, можливості, надані Podʼу в просторі імен користувачів, чинні лише в цьому просторі імен і недійсні поза ним.

Pod може увімкнути використання просторів імен користувачів, встановивши поле pod.spec.hostUsers в false.

Kubelet вибере UID/GID хоста, на які зіставляється Pod, і зробить це так, щоб жодні два Podʼи на одному вузлі не використовували однакове зіставлення.

Поля runAsUser, runAsGroup, fsGroup тощо в pod.spec завжди посилаються на користувача всередині контейнера. Ці користувачі використовуватимуться для монтування томів (вказаних у pod.spec.volumes), і тому UID/GID хоста не матимуть жодного впливу на запис/читання з томів, які може монтувати Pod. Іншими словами, inode, створені/зчитані у томах, змонтованих Podʼом, будуть такими самими, як якби Pod не використовував простори імен користувачів.

Таким чином, Pod може легко вмикати та вимикати простори імен користувачів (не впливаючи на права власності на файли томів), а також надавати спільний доступ до томів з Podʼами без просторів імен користувачів, просто вказавши відповідних користувачів всередині контейнера (RunAsUser, RunAsGroup, fsGroup тощо). Це стосується будь-якого тому, який може бути змонтовано в Pod, включно з hostPath (якщо Podʼу дозволено монтувати томи hostPath).

Стандартно дійсні UID/GID, коли цю функцію активовано, лежать у діапазоні 0-65535. Це стосується файлів та процесів (runAsUser, runAsGroup тощо).

Файли з UID/GID за межами цього діапазону вважатимуться такими, що належать до overflow ID, зазвичай 65534 (налаштовано в /proc/sys/kernel/overflowuid та /proc/sys/kernel/overflowgid). Однак змінити ці файли неможливо, навіть якщо працювати як користувач/група 65534.

Якщо діапазон 0-65535 розширено за допомогою налаштування, вищезазначені обмеження застосовуються до розширеного діапазону.

Більшість застосунків, які потребують запуску з правами root, але не мають доступу до інших просторів імен хоста чи ресурсів, повинні продовжувати працювати без змін, якщо простори імен користувачів активовано.

Розуміння просторів імен користувачів для Podʼів

Кілька середовищ виконання контейнерів із їхньою типовою конфігурацією (таких як Docker Engine, containerd, CRI-O) використовують простори імен Linux для ізоляції. Існують інші технології, які також можна використовувати з цими середовищами (наприклад, Kata Containers використовує віртуальні машини замість просторів імен Linux). Ця сторінка стосується середовищ виконання контейнерів, які використовують простори імен Linux для ізоляції.

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

Це означає, що контейнери можуть працювати як root і зіставлятися з користувачем, який не є root, на хості. Всередині контейнера процес буде вважати себе root (і, отже, інструменти типу apt, dnf тощо працюватимуть нормально), тоді як насправді процес не має привілеїв на хості. Ви можете перевірити це, наприклад, дізнавшись, від імені якого користувача працює процес контейнера, виконавши ps aux на хості. Користувач, якого показує ps, не той самий, що і користувач, якого ви бачите, якщо ви виконаєте команду id всередині контейнера.

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

Крім того, оскільки користувачі в кожному Podʼі будуть зіставлені з різними користувачами на хості, що не перетинаються, обмежено те, що вони можуть зробити з іншими Podʼами.

Можливості, надані Podʼу, також обмежуються простором імен користувачів Podʼа і здебільшого є недійсними поза ним, а деякі навіть абсолютно нечинні. Ось два приклади:

  • CAP_SYS_MODULE не має жодного ефекту, якщо його надано Podʼу, що використовує простори імен користувачів, Pod не може завантажити модулі ядра.
  • CAP_SYS_ADMIN обмежений простором імен користувачів Podʼа та є недійсним поза його межами.

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

Якщо ви хочете дізнатися більше подробиць про те, що змінюється під час використання просторів імен користувачів, дивіться man 7 user_namespaces.

Налаштування вузла для підтримки просторів імен користувачів

Типово kubelet призначає UID/GID Podʼам вище діапазону 0-65535, ґрунтуючись на припущенні, що файли та процеси хоста використовують UID/GID у цьому діапазоні, що є стандартним для більшості дистрибутивів Linux. Цей підхід запобігає будь-якому перетину між UID/GID хоста та UID/GID Podʼів.

Уникнення перетину є важливим для помʼякшення впливу вразливостей, таких як CVE-2021-25741, де потенційно Pod може читати довільні файли на хості. Якщо UID/GID Podʼа та хоста не перетинаються, те, що може робити Pod, обмежено: UID/GID Podʼа не буде відповідати власнику/групі файлів хоста.

Kubelet може використовувати власний діапазон ідентифікаторів користувачів та груп для Podʼів. Для налаштування власного діапазону вузол повинен мати:

  • Користувача kubelet в системі (ви не можете використовувати інше імʼя користувача тут)
  • Встановлений бінарний файл getsubids (частина shadow-utils), доступний у PATH для бінарного файлу kubelet.
  • Конфігурацію допоміжних UID/GID для користувача kubelet (див. man 5 subuid та man 5 subgid).

Цей параметр лише збирає конфігурацію діапазону UID/GID та не змінює користувача, який виконує kubelet.

Вам потрібно дотримуватися деяких обмежень для допоміжного діапазону ID, який ви призначаєте користувачу kubelet:

  • Допоміжний ідентифікатор користувача, який визначає початок діапазону UID для Podʼів, має бути кратним 65536 і також повинен бути більшим або рівним 65536. Іншими словами, ви не можете використовувати жодний ідентифікатор з діапазону 0-65535 для Podʼів; kubelet накладає це обмеження, щоб ускладнити створення ненавмисно незахищеної конфігурації.

  • Кількість допоміжних ID повинна бути кратною 65536.

  • Кількість допоміжних ID повинна бути щонайменше 65536 x <maxPods>, де <maxPods> — максимальна кількість Podʼів, які можуть запускатися на вузлі.

  • Ви повинні призначити однаковий діапазон як для ідентифікаторів користувача, так і для ідентифікаторів груп. Не має значення, чи мають інші користувачі діапазони ідентифікаторів користувача, що не збігаються з діапазонами ідентифікаторів груп.

  • Жоден з призначених діапазонів не повинен перетинатися з жодним іншим призначенням.

  • Конфігурація допоміжних ID повинна бути лише одним рядком. Іншими словами, ви не можете мати кілька діапазонів.

Наприклад, ви можете визначити /etc/subuid та /etc/subgid, щоб обидва мали такі записи для користувача kubelet:

# Формат такий
#   імʼя:firstID:кількість ідентифікаторів
# де
# - firstID дорівнює 65536 (мінімальне можливе значення)
# - кількість ідентифікаторів дорівнює 110 * 65536
#   (110 — стандартне обмеження кількості Podʼів на вузлі)

kubelet:65536:7208960

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

Якщо у вас є вузол, на якому працюють Podʼи з просторами імен користувачів, і ви хочете внести вищезазначені зміни конфігурації, ось кілька важливих приміток.

Конфігурацію слід змінювати, коли на вузлі не запущено жодного Podʼа, що використовує простори імен користувачів. Під час зміни на вузлі, де працюють будь-які Podʼи з просторами імен користувачів, вам потрібно спочатку очистити вузол перед застосуванням конфігурації та перезапуском kubelet. Під час очищення вузла памʼятайте, що Podʼи DaemonSet або інші Podʼи, що толерують taint unschedulable, не будуть виселені.

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

Кількість ID для кожного Podʼа

Починаючи з Kubernetes v1.33 можна встановити кількість ID для кожного Podʼа в KubeletConfiguration.

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
userNamespaces:
  idsPerPod: 1048576

Значення idsPerPod (uint32) має бути кратним 65536. Стандартне значення — 65536. Це значення застосовується лише до контейнерів, створених після запуску kubelet з цією KubeletConfiguration. На запущені контейнери ця конфігурація не впливає.

У версіях Kubernetes до v1.33 кількість ID для кожного Podʼа була жорстко встановлена на рівні 65536.

Інтеграція з перевіркою допуску безпеки Podʼів

Для Podʼів Linux, які увімкнули простори імен користувачів, Kubernetes послаблює застосування Стандартів безпеки Podʼа контрольованим способом.

Якщо ви створите Pod, який використовує простори імен користувачів, такі поля не будуть обмежені навіть у контекстах, які застосовують стандарт безпеки Podʼів Baseline чи Restricted. Це не становить проблему безпеки, оскільки root всередині Podʼа з просторами імен користувачів фактично посилається на користувача всередині контейнера, який ніколи не зіставляється з привілейованим користувачем на хості. Ось список полів, які не перевіряються для Podʼів в цих обставинах:

  • spec.securityContext.runAsNonRoot
  • spec.containers[*].securityContext.runAsNonRoot
  • spec.initContainers[*].securityContext.runAsNonRoot
  • spec.ephemeralContainers[*].securityContext.runAsNonRoot
  • spec.securityContext.runAsUser
  • spec.containers[*].securityContext.runAsUser
  • spec.initContainers[*].securityContext.runAsUser
  • spec.ephemeralContainers[*].securityContext.runAsUser

Крім того, якщо Pod перебуває в контексті зі стандартом безпеки Podʼів Baseline, перевірка таких полів також буде помʼякшена:

  • spec.containers[*].securityContext.procMount
  • spec.initContainers[*].securityContext.procMount
  • spec.ephemeralContainers[*].securityContext.procMount

Зі стандартом безпеки Podʼів Restricted Pod все одно повинен використовувати лише стандартний або порожній ProcMount.

Обмеження

Під час використання просторів імен користувачів для Podʼа заборонено використовувати інші простори імен хоста. Зокрема, якщо ви встановите hostUsers: false, ви не маєте права встановлювати жодне з такого:

  • hostNetwork: true
  • hostIPC: true
  • hostPID: true

Жоден контейнер також не може використовувати volumeDevices (блокові томи raw, такі як /dev/sda). Це стосується всіх масивів контейнерів у специфікації Podʼа:

  • containers
  • initContainers
  • ephemeralContainers

Підтримка файлової системи

Podʼи, які використовують простір імен користувачів, потребують, щоб файлова система підтримувала монтування idmap. Деякі файлові системи не підтримують монтування idmap, і тому не можуть використовуватися з просторами імен користувачів. У таких випадках будуть згенеровані такі події. Зверніть увагу, що деталі попередження залежать від середовища виконання контейнерів, яке ви використовуєте.

Warning  Failed 1s kubelet Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: failed to fulfil mount request: failed to set MOUNT_ATTR_IDMAP on ${your mount path} invalid argument (maybe the filesystem used doesn't support idmap mounts on this kernel?): unknown

Томи NFS не можуть бути змонтовані в Pod з простором імен користувачів, оскільки клієнт Linux NFS ще не підтримує монтування idmap. Для поточного списку підтримуваних файлових систем дивіться сторінку керівництва Linux mount_setattr(2).

Метрики та спостережуваність

Kubelet експортує дві метрики prometheus, специфічні для просторів імен користувачів:

  • started_user_namespaced_pods_total: лічильник, який відстежує кількість спроб створення Podʼів з просторами імен користувачів.
  • started_user_namespaced_pods_errors_total: лічильник, який відстежує кількість помилок під час створення Podʼів з просторами імен користувачів.

Що далі

1.13 - Downward API

Є два способи надати поля Podʼа та контейнера запущеному контейнеру: змінні середовища та файли, які заповнюються спеціальним типом тому. Разом ці два способи надання полів Podʼа та контейнера називають downward API.

Іноді корисно, щоб контейнер мав інформацію про себе, не перебуваючи занадто повʼязаним із Kubernetes. Downward API дозволяє контейнерам використовувати інформацію про себе чи кластер, не використовуючи клієнт Kubernetes або API-сервер.

Прикладом є наявний застосунок, який передбачає, що певна добре відома змінна середовища містить унікальний ідентифікатор. Можна обгорнути застосунок, але це виснажливо, схильне до помилок і суперечить меті слабкого звʼязку. Кращий варіант — використовувати назву Podʼа як ідентифікатор і передати її в цю змінну середовища.

У Kubernetes є два способи надати поля Podʼа та контейнера запущеному контейнеру:

Разом ці два способи надання полів Podʼа та контейнера називають downward API.

Доступні поля

Через downward API доступні лише деякі поля API Kubernetes. У цьому розділі перелічено поля, які ви можете зробити доступними.

Ви можете передавати інформацію з доступних полів рівня Podʼа, використовуючи fieldRef. На рівні API spec для Podʼа завжди визначає принаймні один Container. Ви можете передавати інформацію з доступних полів рівня Container, використовуючи resourceFieldRef.

Інформація, доступна за допомогою fieldRef

Деякі поля рівня Podʼа ви можете передати контейнеру як змінну середовища або через том downwardAPI. Через обидва механізми доступні такі поля:

metadata.name
назва Podʼа
metadata.namespace
простір імен Podʼа
metadata.uid
унікальний ідентифікатор Podʼа
metadata.annotations['<KEY>']
значення анотації Podʼа з назвою <KEY> (наприклад, metadata.annotations['myannotation'])
metadata.labels['<KEY>']
текстове значення мітки Podʼа з назвою <KEY> (наприклад, metadata.labels['mylabel'])

Така інформація доступна через змінні середовища, але не як поле fieldRef у томі downwardAPI:

spec.serviceAccountName
назва ServiceAccount Podʼа
spec.nodeName
назва вузла, на якому виконується Pod
status.hostIP
основна IP-адреса вузла, до якого призначено Pod
status.hostIPs
IP-адреси — це версія подвійного стека status.hostIP, перша завжди така сама, як і status.hostIP.
status.podIP
основна IP-адреса Podʼа (зазвичай, його IPv4-адреса)
status.podIPs
IP-адреси — це версія подвійного стека status.podIP, перша завжди така сама, як і status.podIP

Така інформація доступна через fieldRef тому downwardAPI, але не як змінні середовища:

metadata.labels
всі мітки Podʼа у форматі label-key="escaped-label-value" з однією міткою на рядок
metadata.annotations
всі анотації Podʼа у форматі annotation-key="escaped-annotation-value" з однією анотацією на рядок

Інформація, доступна за допомогою resourceFieldRef

Ці поля рівня контейнера дозволяють надавати інформацію про запити та обмеження для ресурсів, таких як CPU та памʼять.

Примітка:

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.35
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate InPlacePodVerticalScaling, Kubernetes ignores it but does not report any error.

Ресурси CPU та памʼяті контейнера можуть бути змінені під час роботи контейнера. Якщо це станеться, буде оновлено том downward API, але змінні середовища не буде оновлено, доки контейнер не буде перезапущено. Докладніші відомості наведено у статті Зміна розміру ресурсів CPU та памʼяті, призначених контейнерам.

resource: limits.cpu
Обмеження CPU контейнера
resource: requests.cpu
Запит CPU контейнера
resource: limits.memory
Обмеження памʼяті контейнера
resource: requests.memory
Запит памʼяті контейнера
resource: limits.hugepages-*
Обмеження hugepages контейнера
resource: requests.hugepages-*
Запит hugepages контейнера
resource: limits.ephemeral-storage
Обмеження ефемерного сховища контейнера
resource: requests.ephemeral-storage
Запит ефемерного сховища контейнера

Резервна інформація для обмежень ресурсів

Якщо обмеження CPU та памʼяті не вказані для контейнера, і ви намагаєтеся надати цю інформацію через downward API, kubelet стандартно надає максимальне доступне для розподілу значення CPU та памʼяті на основі розрахунку ресурсів вузла, доступних для розподілу.

Що далі

Ви можете прочитати про томи downwardAPI.

Ви можете спробувати використовувати downward API щоб надати інформацію рівня контейнера чи Podʼа:

1.14 - Розширена конфігурація Podʼів

На цій сторінці розглядаються теми з розширеної конфігурації Podʼів, включаючи PriorityClasses, RuntimeClasses, контекст безпеки в Podʼах, а також представлені аспекти планування.

PriorityClasses

PriorityClasses дозволяють вам встановити важливість Podʼів відносно інших Podʼів. Якщо ви призначаєте клас пріоритету Podʼу, Kubernetes встановлює поле .spec.priority для цього Podʼа на основі PriorityClass, який ви вказали (ви не можете встановити .spec.priority безпосередньо). Якщо або коли Pod не може бути запланований, і проблема повʼязана з нестачею ресурсів, kube-scheduler намагається витіснити Podʼи з нижчим пріоритетом, щоб зробити можливим планування Podʼа з вищим пріоритетом.

PriorityClass — це обʼєкт API в межах кластера, який зіставляє назву класу пріоритету з цілочисельним значенням пріоритету. Більші числа вказують на вищий пріоритет.

Визначення PriorityClass

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 10000
globalDefault: false
description: "Клас пріоритету для робочих навантажень із високим пріоритетом"

Вказування пріоритету Podʼа за допомогою PriorityClass

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  priorityClassName: high-priority

Вбудовані PriorityClasses

Kubernetes надає два вбудовані PriorityClasses:

  • system-cluster-critical: для системних компонентів, які є критичними для кластера
  • system-node-critical: для системних компонентів, які є критичними для окремих вузлів. Це найвищий пріоритет, який можуть мати Podʼи в Kubernetes.

Для отримання додаткової інформації див. Пріоритет і витіснення Podʼів.

RuntimeClasses

RuntimeClass дозволяє вказати низькорівневе середовище виконання контейнерів для Podʼа. Це корисно, коли потрібно вказати різні середовища виконання контейнерів для різних типів Podʼів, наприклад, коли потрібні різні рівні ізоляції або функції середовища виконання.

Приклад Podʼа

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: myclass
  containers:
  - name: mycontainer
    image: nginx

RuntimeClass — це обʼєкт у межах кластера, який представляє середовище виконання контейнерів, доступне на деяких або всіх ваших вузлах.

Адміністратор кластера встановлює та налаштовує конкретні середовища виконання, що підтримують RuntimeClass.

Адміністратор може налаштувати цю спеціальну конфігурацію середовища виконання контейнерів на всіх вузлах або лише на деяких з них.

Докладнішу інформацію див. у документації RuntimeClass.

Конфігурація контексту безпеки на рівні Podʼа та контейнера

Поле Security context у специфікації Podʼа забезпечує детальний контроль за налаштуваннями безпеки для Podʼів та контейнерів.

securityContext на рівні Podʼа

Деякі аспекти безпеки застосовуються до всього Podʼа; для інших аспектів ви можете встановити стандартне значення без будь-яких перевизначень на рівні контейнера.

Ось приклад використання securityContext на рівні Podʼа:

Приклад Podʼа

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:  # Це стосується всього Podʼа
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  containers:
  - name: sec-ctx-demo
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: ["sh", "-c", "sleep 1h"]

Контекст безпеки на рівні контейнера

Ви можете вказати контекст безпеки тільки для конкретного контейнера. Ось приклад:

Приклад Podʼа

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  containers:
  - name: sec-ctx-demo-2
    image: gcr.io/google-samples/node-hello:1.0
    securityContext:
      allowPrivilegeEscalation: false
      runAsNonRoot: true
      runAsUser: 1000
      capabilities:
        drop:
        - ALL
      seccompProfile:
        type: RuntimeDefault

Параметри контексту безпеки

  • Ідентифікатори користувачів та груп: контроль того, під яким користувачем/групою працює контейнер
  • Capabilities: додавання або видалення можливостей Linux
  • Профілі Seccomp: налаштування профілів обчислювальної безпеки
  • Параметри SELinux: налаштування контексту SELinux
  • AppArmor: налаштування профілів AppArmor для додаткового контролю доступу
  • Параметри Windows: налаштування параметрів безпеки, специфічних для Windows

Увага:

Ви також можете використовувати securityContext Podʼа, щоб дозволити привілейований режим у контейнерах Linux. Привілейований режим перевизначає багато інших налаштувань безпеки в securityContext. Уникайте використання цього параметра, якщо ви не можете надати еквівалентні дозволи за допомогою інших полів у securityContext. Ви можете запускати контейнери Windows у подібному привілейованому режимі, встановивши прапорець windowsOptions.hostProcess у контексті безпеки на рівні Podʼа. Детальні відомості та інструкції див. у розділі Створення Windows HostProcess Podʼа.

Для отримання додаткової інформації див. Налаштування контексту безпеки для Podʼа або контейнера.

Вплив на рішення щодо планування Podʼів

Kubernetes надає кілька механізмів для контролю над тим, на яких вузлах плануються ваші Podʼи.

Селектори вузлів

Найпростіша форма обмеження вибору вузлів:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeSelector:
    disktype: ssd

Спорідненість вузлів

Спорідненість вузлів дозволяє вам вказати правила, які обмежують, на яких вузлах може бути запланований ваш Pod. Ось приклад Podʼа, який віддає перевагу роботі на вузлах, позначених як такі, що розташовані на певному континенті, вибираючи на основі значення мітки topology.kubernetes.io/zone.

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: topology.kubernetes.io/zone
            operator: In
            values:
            - antarctica-east1
            - antarctica-west1
  containers:
  - name: with-node-affinity
    image: registry.k8s.io/pause:3.8

Спорідненість та антиспорідненість Podʼів

Окрім спорідненості вузлів, ви також можете обмежити, на яких вузлах може бути заплановано Pod, на основі міток інших Podʼів, які вже працюють на вузлах. Спорідненість Podʼів дозволяє вам вказати правила щодо розміщення Podʼів відносно інших Podʼів.

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - database
        topologyKey: topology.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: registry.k8s.io/pause:3.8

Tolerations

Tolerations дозволяють планувати Podʼи на вузли з відповідними taints:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: myapp
    image: nginx
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

Для отримання додаткової інформації див. Призначення Podʼів до вузлів.

Накладні витрати на Pod

Накладні витрати на Pod дозволяють враховувати ресурси, що споживаються інфраструктурою Podʼа, понад запити та обмеження контейнерів.

---
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kvisor-runtime
handler: kvisor-runtime
overhead:
  podFixed:
    memory: "2Gi"
    cpu: "500m"
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: kvisor-runtime
  containers:
  - name: myapp
    image: nginx
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Що далі

2 - Керування навантаженням

Kubernetes надає кілька вбудованих API для декларативного керування вашими робочими навантаженнями та їх компонентами.

У кінцевому підсумку ваші застосунки працюють як контейнери всередині Podʼів; однак керування окремими Podʼами вимагало б багато зусиль. Наприклад, якщо Pod зазнає збою, ви, ймовірно, захочете запустити новий Pod для його заміни. Kubernetes може зробити це за вас.

Ви використовуєте API Kubernetes для створення обʼєкта робочого навантаження, який представляє вищий рівень абстракції, ніж Pod, а потім панель управління Kubernetes автоматично керує обʼєктами 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.

DaemonSet визначає Podʼи, які надають можливості, що є локальними для конкретного вузла; наприклад, драйвер, який дозволяє контейнерам на цьому вузлі отримувати доступ до системи зберігання. Ви використовуєте DaemonSet, коли драйвер або інший сервіс рівня вузла має працювати на вузлі, де він корисний. Кожен Pod в DaemonSet виконує роль, схожу на системний демон на класичному сервері Unix/POSIX. DaemonSet може бути фундаментальним для роботи вашого кластера, наприклад, як втулок, який надає цьому вузлу доступ до мережі кластера, він може допомогти вам керувати вузлом, або надати менш важливі можливості, які покращують платформу контейнерів, яку ви використовуєте. Ви можете запускати DaemonSets (та їхні Podʼи) на кожному вузлі вашого кластера або лише на підмножині (наприклад, встановити драйвер прискорювача GPU лише на вузлах, де встановлено GPU).

Ви можете використовувати Job та/або CronJob для визначення завдань, які виконуються до завершення та зупиняються. Job представляє одноразове завдання, тоді як кожен CronJob повторюється згідно з розкладом.

Інші теми в цьому розділі:

2.1 - Deployments

Deployment керує набором Podʼів для запуску робочого навантаження застосунку, зазвичай такого, що не зберігає стан.

Deployment забезпечує декларативні оновлення для Podʼів та ReplicaSets.

Ви описуєте бажаний стан у Deployment, і контролер Deployment змінює фактичний стан на бажаний з контрольованою швидкістю. Ви можете визначити Deployments для створення нових ReplicaSets або для видалення наявних Deployments і перейняття всіх їхніх ресурсів новими Deployments.

Примітка:

Не керуйте ReplicaSets, що належать Deployment. Розгляньте можливість створення тікета в основному репозиторії Kubernetes, якщо ваш випадок використання не врахований нижче.

Сценарії використання

Типові сценарії використання Deployments:

Створення 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.7.9
        ports:
        - containerPort: 80

У цьому прикладі:

  • Створюється Deployment з назвою nginx-deployment, назва вказується в полі .metadata.name. Ця назва буде основою для ReplicaSets та Podʼів, які буде створено потім. Докладніше див. у розділі Написання специфікації Deployment.

  • 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, повинні бути виконані для отримання збігу.
  • Поле .spec.template має такі вкладені поля:

    • Podʼи позначаються міткою app: nginx з поля .metadata.labels.
    • Специфікація шаблону Podʼа, або поле .spec, вказує на те, що Podʼи запускають один контейнер, nginx, який використовує образ nginx з Docker Hub версії 1.14.2.
    • Створюється один контейнер із назвою nginx, вказаною в полі .spec.containers[0].name.

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

  1. Створіть Deployment, виконавши таку команду:

    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
    
  2. Виконайте kubectl get deployments для перевірки створення Deployment.

    Якщо Deployment все ще створюється, ви побачите вивід, подібний до цього:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   0/3     0            0           1s
    

    Коли ви переглядаєте Deployments у вашому кластері, показуються такі поля:

    • NAME — містить назви Deployments у просторі імен.
    • READY — показує, скільки реплік застосунку доступно користувачам. Значення відповідає шаблону готово/бажано.
    • UP-TO-DATE — показує кількість реплік, які були оновлені для досягнення бажаного стану.
    • AVAILABLE — показує, скільки реплік застосунку доступно користувачам.
    • AGE — показує час впродовж якого застосунок працює.

    Зверніть увагу, що бажана кількість реплік дорівнює 3 відповідно до поля .spec.replicas.

  3. Для перевірки стану розгортання 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
    
  4. Запустіть kubectl get deployments знов через кілька секунд. Вивід буде подібний до цього:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           18s
    

    Зверніть увагу, що Deployment створив усі три репліки, і всі репліки актуальні (вони містять останній шаблон Podʼа) та доступні.

  5. Для перевірки 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.

  6. Для ознайомлення з мітками, автоматично створеними для кожного 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 запускається тоді й лише тоді, коли змінюється шаблон Podʼа Deployment (тобто .spec.template), наприклад, якщо оновлено мітки чи образи контейнерів шаблону. Інші оновлення, такі як масштабування Deployment, не запускають розгортання.

Дотримуйтеся поданих нижче кроків для оновлення вашого Deployment:

  1. Оновіть 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
    

    Або ви можете відредагувати (edit) Deployment і змінити .spec.template.spec.containers[0].image з nginx:1.14.2 на nginx:1.16.1:

    kubectl edit deployment/nginx-deployment
    

    Вивід буде подібний до цього:

    deployment.apps/nginx-deployment edited
    
  2. Щоб перевірити статус розгортання, виконайте:

    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 реплік.

    kubectl get rs
    

    Вивід буде подібний до цього:

    NAME                          DESIRED   CURRENT   READY   AGE
    nginx-deployment-1564180365   3         3         3       6s
    nginx-deployment-2035384211   0         0         0       36s
    
  • Виклик get pods повинен тепер показати лише нові Podʼи:

    kubectl get pods
    

    Вивід буде подібний до цього:

    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ʼів буде створено лише певну кількість. Типово він гарантує, що працюватимуть щонайбільше 125% бажаної кількості Podʼів (максимальне перевищення 25%).

    Наприклад, якщо ви ретельно досліджуєте Deployment вище, ви побачите, що спочатку було створено новий Pod, потім видалено старий Pod і створено ще один новий. Старі Podʼи не прибираються допоки не зʼявиться достатня кількість нових, і не створюються нові Podʼи допоки не буде прибрано достатню кількість старих. Deployment гарантує, що доступні принаймні 3 Podʼи, а загалом доступно щонайбільше 4 Podʼи. У випадку розгортання з 4 репліками кількість Podʼів буде між 3 і 5.

  • Отримайте деталі вашого Deployment:

    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 відповідно до оновлення, почне масштабувати його і перекине (roll over) 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, перш ніж змінити напрямок.

Оновлення селектора міток

Зазвичай не рекомендується вносити оновлення до селектора міток, і рекомендується планувати ваші селектори наперед.

Селектор міток Deployment є незмінним після створення; його не можна оновити за допомогою kubectl patch, kubectl edit, kubectl apply або інструментів, таких як helm upgrade.

Якщо вам потрібно змінити селектор, вам доведеться видалити Deployment і створити його заново. Стандартно видалення Deployment також видаляє його запущені Podʼи, що призводить до простою; використовуйте --cascade=orphan, якщо вам потрібно, щоб ці Podʼи продовжували працювати під час повторного створення Deployment (див. наслідки нижче). Будьте дуже обережні та переконайтеся, що ви розумієте такі наслідки:

  • Додавання: Коли ви створюєте новий Deployment з більш вузьким селектором, новий Deployment повинен також мати відповідний шаблон Podʼа. Якщо у вас є наявний маніфест і ви редагуєте його, щоб звузити селектор, вам потрібно відредагувати метадані шаблону Podʼа всередині цього Deployment, додавши нові мітки для відповідності, інакше API-сервер поверне помилку валідації. Це зміна без перетину: новий Deployment не "побачить" старі Podʼи (які не мають нової мітки), тому старий ReplicaSet стане сирітським і буде створено абсолютно новий ReplicaSet.
  • Оновлення значень: Зміна наявного значення в ключі селектора (наприклад, з v1 на v2) призводить до тієї ж поведінки, що й додавання (сирітство та повторне створення).
  • Видалення: Видалення наявного ключа з селектора Deployment не вимагає жодних змін у мітках шаблону Podʼа. Це зміна з перетином: новий, ширший селектор відповідатиме старим Podʼам. Наявні ReplicaSets не стають сирітськими, і новий ReplicaSet не створюється, але зверніть увагу, що видалена мітка все ще існує в будь-яких наявних Podʼах та ReplicaSets. Ви можете прибрати її, запустивши розгортання Deployment.

Відкочування Deployment

Іноді вам може знадобитися відкотити Deployment, наприклад, коли Deployment нестабільний, зокрема зациклений на збоях (crash looping). Типово вся історія розгортань 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.

    kubectl get rs
    

    Вивід буде подібний до цього:

    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, застряг у циклі завантаження образу.

    kubectl get pods
    

    Вивід буде подібний до цього:

    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%.
  • Отримайте опис Deployment:

    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
    

    Для виправлення цього вам потрібно відкотитися до попередньої ревізії Deployment, яка є стабільною.

Перевірка історії розгортання Deployment

Виконайте наведені нижче кроки, щоб перевірити історію розгортань:

  1. По-перше, перевірте ревізії цього Deployment:

    kubectl rollout history deployment/nginx-deployment
    

    Вивід буде подібний до цього:

    deployments "nginx-deployment"
    REVISION    CHANGE-CAUSE
    1           <none>
    2           <none>
    3           <none>
    

    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"
    • Ручним редагуванням маніфесту ресурсу.
    • Використовуючи інструменти, які автоматично встановлюють анотації.

Примітка:

У старих версіях Kubernetes можна було використовувати прапорець --record з командами kubectl для автоматичного заповнення поля CHANGE-CAUSE. Цей прапорець є застарілим і буде видалений у майбутніх версіях.
  1. Щоб переглянути деталі кожної ревізії, виконайте:

    kubectl rollout history deployment/nginx-deployment --revision=2
    

    Вивід буде подібний до цього:

    deployments "nginx-deployment" revision 2
      Labels:       app=nginx
              pod-template-hash=1159050644
      Containers:
       nginx:
        Image:      nginx:1.16.1
        Port:       80/TCP
         QoS Tier:
            cpu:      BestEffort
            memory:   BestEffort
        Environment Variables:      <none>
      No volumes.
    

Відкочування до попередньої ревізії

Виконайте наведені нижче кроки, щоб відкотити Deployment з поточної версії на попередню версію, яка є версією 2.

  1. Тепер ви вирішили скасувати поточне розгортання та повернутися до попередньої ревізії:

    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 тепер повернуто до попередньої стабільної ревізії. Як ви можете бачити, контролер Deployment генерує подію DeploymentRollback щодо відкочування до ревізії 2.

  2. Перевірте, чи відкочування був успішним і Deployment працює як очікується, виконавши:

    kubectl get deployment nginx-deployment
    

    Вивід буде подібний до цього:

    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment   3/3     3            3           30m
    
  3. Отримайте опис Deployment:

    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
    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ʼів, які ви хочете запускати, на основі використання CPU вашими наявними Podʼами.

kubectl autoscale deployment/nginx-deployment --min=10 --max=15 --cpu-percent=80%

Вивід буде подібний до цього:

deployment.apps/nginx-deployment scaled

Пропорційне масштабування

Deployments RollingUpdate підтримують виконання кількох версій застосунку одночасно. Коли ви або автомасштабувальник масштабуєте Deployment RollingUpdate, який перебуває посеред розгортання (у процесі або призупиненого), контролер Deployment балансує додаткові репліки в наявних активних ReplicaSets (ReplicaSets з Podʼами), щоб помʼякшити ризик. Це називається пропорційним масштабуванням.

Наприклад, ви використовуєте Deployment з 10 репліками, maxSurge=3 та maxUnavailable=2.

  • Переконайтеся, що у вашому Deployment працює 10 реплік.

    kubectl get deploy
    

    Вивід буде подібний до цього:

    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
    
  • Оновлення образу розпочинає нове розгортання з ReplicaSet nginx-deployment-1989198191, але воно блокується через вимогу maxUnavailable, згадану вище. Перевірте стан розгортання:

    kubectl get rs
    

    Вивід буде подібний до цього:

    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, за умови, що нові репліки стають справними. Для підтвердження цього виконайте:

kubectl get deploy

Вивід буде подібний до цього:

NAME                 DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment     15        18        7            8           7m

Статус розгортання підтверджує, як репліки були додані до кожного ReplicaSet.

kubectl get rs

Вивід буде подібний до цього:

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:

    kubectl get deploy
    

    Вивід буде подібний до цього:

    NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    nginx     3         3         3            3           1m
    

    Отримайте стан розгортання:

    kubectl get rs
    

    Вивід буде подібний до цього:

    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
    
  • Зверніть увагу, що нове розгортання не розпочалося:

    kubectl rollout history deployment/nginx-deployment
    

    Вивід буде подібний до цього:

    deployments "nginx"
    REVISION  CHANGE-CAUSE
    1   <none>
    
  • Отримайте стан розгортання, щоб перевірити, що наявний ReplicaSet не змінився:

    kubectl get rs
    

    Вивід буде подібний до цього:

    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 до призупинення його розгортання продовжить працювати, але нові оновлення до Deployment не матимуть жодного впливу, поки розгортання Deployment призупинено.

  • У кінці відновіть розгортання Deployment і спостерігайте, як новий ReplicaSet зʼявляється з усіма новими оновленнями:

    kubectl rollout resume deployment/nginx-deployment
    

    Вивід буде подібний до цього:

    deployment.apps/nginx-deployment resumed
    
  • Спостерігайте за статусом розгортання, доки воно не завершиться.

    kubectl get rs --watch
    

    Вивід буде подібний до цього:

    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
    
  • Отримайте статус останнього розгортання:

    kubectl get rs
    

    Вивід буде подібний до цього:

    NAME               DESIRED   CURRENT   READY     AGE
    nginx-2142116321   0         0         0         2m
    nginx-3926361531   3         3         3         28s
    

Примітка:

Ви не можете відкотити призупинене розгортання Deployment, доки ви його не відновите.

Статус Deployment

Deployment переходить через різні стани протягом свого життєвого циклу. Він може бути в процесі, коли виконується розгортання нового ReplicaSet, може бути завершеним або не зможе просуватися.

Deployment в процесі

Kubernetes позначає Deployment як в процесі (progressing), коли виконується одне з таких завдань:

  • Deployment створює новий ReplicaSet.
  • Deployment масштабує вгору свій новий ReplicaSet.
  • Deployment масштабує вниз свої старі ReplicaSets.
  • Нові 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. Якщо розгортання завершилося успішно, 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 (успіх):

echo $?
0

Невдалий Deployment

Ваш Deployment може застрягти під час спроби розгорнути свій найновіший ReplicaSet і ніколи не завершитися. Це може статися через такі чинники:

  • Недостатні квоти
  • Збій проб readiness
  • Помилки завантаження образів
  • Недостатні дозволи
  • Діапазони обмежень (limit ranges)
  • Неправильна конфігурація середовища виконання застосунку

Один із способів виявлення цього стану — це вказати параметр крайнього терміну у специфікації вашого Deployment: (.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
    lastUpdateTime: 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 (позначає помилку):

echo $?
1

Операції з невдалим Deployment

Всі дії, які застосовуються до завершеного Deployment, також застосовуються до невдалого Deployment. Ви можете масштабувати його вгору/вниз, відкотити на попередню ревізію або навіть призупинити, якщо вам потрібно застосувати кілька змін у шаблоні Podʼа Deployment.

Політика очищення

Ви можете встановити поле .spec.revisionHistoryLimit у Deployment, щоб вказати, скільки старих ReplicaSets для цього Deployment ви хочете зберегти. Решту прибере збір сміття у фоновому режимі. Типове значення становить 10.

Примітка:

Якщо явно встановити це поле на 0, буде виконано очищення всієї історії вашого Deployment, і цей Deployment не зможе виконати відкочування.

Очищення починається лише після того, як Deployment досягне завершеного стану. Якщо ви встановите .spec.revisionHistoryLimit у 0, будь-яке розгортання все одно спричинить створення нового ReplicaSet до того, як Kubernetes видалить старий.

Навіть з ненульовим обмеженням історії ревізій ви можете мати більше ReplicaSets, ніж ви налаштували. Наприклад, якщо Podʼи зациклені на збоях і з часом запускається кілька подій поетапного оновлення, ви можете мати більше ReplicaSets, ніж встановлено .spec.revisionHistoryLimit, оскільки Deployment ніколи не досягає завершеного стану.

Канаркові розгортання

Якщо ви хочете впроваджувати релізи для підмножини користувачів чи серверів, використовуючи Deployment, ви можете створити кілька Deployments, по одному для кожного релізу, дотримуючись канаркового шаблону, описаного в розділі керування ресурсами.

Щоб дізнатися, що це передбачає, пройдіть навчальний посібник Розгортання релізу за допомогою канаркового розгортання.

Написання специфікації 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ʼи в режимі поетапного оновлення (поступово зменшуючи масштаб старих ReplicaSets і збільшуючи масштаб нового), коли .spec.strategy.type==RollingUpdate. Ви можете вказати maxUnavailable та maxSurge, щоб контролювати процес поетапного оновлення.

Максимум недоступних

.spec.strategy.rollingUpdate.maxUnavailable — це необовʼязкове поле, яке вказує максимальну кількість Podʼів, які можуть бути недоступні під час процесу оновлення. Значення може бути абсолютним числом (наприклад, 5) або відсотком від бажаної кількості Podʼів (наприклад, 10%). Абсолютне число обчислюється з відсотків округленням униз. Значення не може бути 0, якщо .spec.strategy.rollingUpdate.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 Seconds

.spec.progressDeadlineSeconds — це необовʼязкове поле, яке вказує кількість секунд, протягом яких ви хочете чекати на просування вашого Deployment, перш ніж система повідомить, що Deployment не зміг просуватися, — це відображається як стан з type: Progressing, status: "False" та reason: ProgressDeadlineExceeded в статусі ресурсу. Контролер Deployment буде продовжувати повторювати спроби Deployment. Стандартно це значення становить 600.

Якщо вказано це поле, воно повинно бути більше, ніж значення .spec.minReadySeconds.

Min Ready Seconds

.spec.minReadySeconds — це необовʼязкове поле, яке вказує мінімальну кількість секунд, протягом яких новостворений Pod повинен бути готовим без збоїв будь-якого з його контейнерів, щоб вважатися доступним. Стандартно це значення становить 0 (Pod буде вважатися доступним, як тільки він буде готовий). Щоб дізнатися більше про те, коли Pod вважається готовим, див. Проби контейнерів.

Podʼи, що завершують роботу

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.35; (стандартно увімкнено)

Ви можете бачити Podʼи, що завершують роботу, лише якщо функціональну можливість DeploymentReplicaSetTerminatingReplicas увімкнено на API-сервері та в kube-controller-manager

Podʼи, що завершують роботу через видалення або зменшення масштабу, можуть завершуватися тривалий час і впродовж цього періоду споживати додаткові ресурси. Як наслідок, загальна кількість усіх Podʼів може тимчасово перевищити .spec.replicas. Podʼи, що завершують роботу, можна відстежувати за допомогою поля .status.terminatingReplicas в Deployment.

Обмеження історії ревізій

Історія ревізій 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.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, мають у полі ownerReferences ідентифікаційну інформацію ReplicaSet, що ними володіє. Завдяки цим посиланням 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:
  # modify replicas according to your case
  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://k8s-docs.ru/examples/controllers/frontend.yaml

Ви можете переглянути розгорнуті ReplicaSets за допомогою команди:

kubectl get rs

І побачите, що створено 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ʼи:

kubectl get pods

І побачите щось подібне до цього:

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 frontend. Для цього отримайте YAML одного із запущених Podʼів:

kubectl get pods frontend-gbgfx -o yaml

Вивід буде схожий на цей, з інформацією про ReplicaSet frontend у полі 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://k8s-docs.ru/examples/pods/pod-rs.yaml

Нові Podʼи будуть отримані ReplicaSet та негайно завершені, оскільки ReplicaSet буде мати більше, ніж його бажана кількість.

Отримання Podʼів:

kubectl get pods

Вивід покаже, що нові 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://k8s-docs.ru/examples/pods/pod-rs.yaml

А потім створите ReplicaSet таким чином:

kubectl apply -f https://k8s-docs.ru/examples/controllers/frontend.yaml

Ви побачите, що ReplicaSet отримав Podʼи та створив нові лише відповідно до свого опису, доки кількість його нових Podʼів та оригінальних не відповідала його бажаній кількості. Якщо отримати Podʼи:

kubectl get pods

Вивід покаже, що:

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.

Для поля політики перезапуску шаблону, .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.replicas, то типово значення дорівнює 1.

Робота з ReplicaSets

Видалення ReplicaSet та його Podʼів

Щоб видалити ReplicaSet і всі його Podʼи, використовуйте kubectl delete. Збирач сміття стандартно автоматично видаляє всі залежні 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 безпосередньо не підтримують поетапне оновлення.

Podʼи, що завершують роботу

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.35; (стандартно увімкнено)

Ви можете увімкнути цю функцію, встановивши функціональну можливість DeploymentReplicaSetTerminatingReplicas на API-сервері та в kube-controller-manager

Podʼи, що завершують роботу через видалення або зменшення масштабу, можуть завершуватися тривалий час і впродовж цього періоду споживати додаткові ресурси. Як наслідок, загальна кількість усіх Podʼів може тимчасово перевищити .spec.replicas. Podʼи, що завершують роботу, можна відстежувати за допомогою поля .status.terminatingReplicas в ReplicaSet.

Ізолювання Podʼів від ReplicaSet

Ви можете видалити Podʼи з ReplicaSet, змінивши їх мітки. Цей метод може бути використаний для вилучення Podʼів з обслуговування з метою налагодження, відновлення даних тощо. Podʼи, які вилучаються цим способом, будуть автоматично замінені (за умови, що кількість реплік також не змінюється).

Масштабування ReplicaSet

ReplicaSet можна легко масштабувати вгору або вниз, просто оновивши поле .spec.replicas. Контролер ReplicaSet гарантує, що бажана кількість Podʼів з відповідним селектором міток доступна та працює.

Під час зменшення масштабу контролер ReplicaSet вибирає Podʼи для видалення, сортуючи доступні Podʼи, щоб визначити, які Podʼи видаляти в першу чергу, за таким загальним алгоритмом:

  1. Перш за все прибираються Podʼи, що перебувають в очікуванні (і непридатні для планування).
  2. Якщо встановлено анотацію controller.kubernetes.io/pod-deletion-cost, то Pod із меншим значенням буде видалено першим.
  3. Podʼи на вузлах з більшою кількістю реплік йдуть перед Podʼами на вузлах з меншою кількістю реплік.
  4. Якщо часи створення Podʼів відрізняються, то Pod, створений пізніше, йде перед старішим Podʼом (часи створення групуються за цілочисельною логарифмічною шкалою).

Якщо все вище вказане збігається, вибір випадковий.

Вартість видалення Podʼа

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.22

За допомогою анотації 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.

Примітка:

  • Це враховується за принципом best-effort, тому порядок видалення Podʼів не гарантується.
  • Користувачам слід уникати частого оновлення анотації, такого як оновлення її на основі значення метрики, оскільки це призведе до значного числа оновлень Podʼів на apiserver.

Приклад використання

Різні Podʼи застосунку можуть мати різний рівень використання. Під час зменшення масштабу застосунок може віддавати перевагу видаленню Podʼів з меншим використанням. Щоб уникнути частого оновлення Podʼів, застосунок повинен оновити controller.kubernetes.io/pod-deletion-cost один раз перед зменшенням масштабу (встановлення анотації в значення, пропорційне рівню використання Podʼа). Це працює, якщо сам застосунок контролює масштабування вниз; наприклад, Pod-драйвер розгортання Spark.

ReplicaSet як ціль горизонтального автомасштабування Podʼа

ReplicaSet також може бути ціллю для горизонтального автомасштабування Podʼа (HPA). Іншими словами, ReplicaSet може автоматично масштабуватися за допомогою HPA. Ось приклад HPA, який застосовується до ReplicaSet, створеного в попередньому прикладі.

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: frontend-scaler
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: ReplicaSet
    name: frontend
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

Збереження цього маніфесту в hpa-rs.yaml та його застосування до кластера Kubernetes повинно створити визначене HPA, яке автоматично змінює масштаб цільового ReplicaSet залежно від використання CPU реплікованими Podʼами.

kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml

Або ви можете використовувати команду kubectl autoscale для досягнення того ж самого (і це простіше!)

kubectl autoscale rs frontend --max=10 --min=3 --cpu=50%

Альтернативи ReplicaSet

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.

Що далі

2.3 - StatefulSets

StatefulSet запускає групу Podʼів і зберігає стійку ідентичність для кожного з цих Podʼів. Це корисно для керування застосунками, які потребують постійного сховища або стабільної, унікальної мережевої ідентичності.

StatefulSet — це обʼєкт API робочого навантаження, який використовується для керування застосунками зі збереженням стану.

StatefulSet керує розгортанням і масштабуванням групи Podʼів, і забезпечує гарантії щодо порядку та унікальності цих Podʼів.

Як і Deployment, StatefulSet керує Podʼами, які базуються на ідентичній специфікації контейнерів. На відміну від Deployment, StatefulSet зберігає постійну ідентичність для кожного свого Podʼа. Ці Podʼи створюються за однаковою специфікацією, але не є взаємозамінними: у кожного є постійний ідентифікатор, який він зберігає під час будь-якого перепланування.

Якщо ви хочете використовувати томи для забезпечення постійності вашого робочого навантаження, ви можете використовувати StatefulSet як частину рішення. Хоча окремі Podʼи в StatefulSet можуть вийти з ладу, постійні ідентифікатори Podʼів полегшують зіставлення наявних томів із новими Podʼами, які замінюють ті, що вийшли з ладу.

Використання StatefulSets

StatefulSets є цінним інструментом для застосунків, які потребують одного або кількох із таких елементів:

  • Стабільних, унікальних мережевих ідентифікаторів.
  • Стабільного, постійного сховища.
  • Упорядкованого, плавного розгортання та масштабування.
  • Упорядкованих, автоматизованих поетапних оновлень.

Тут «стабільний» означає збереження під час (пере)планування Podʼів. Якщо застосунок не потребує стабільних ідентифікаторів або упорядкованого розгортання, видалення чи масштабування, вам слід розгортати його за допомогою обʼєкта робочого навантаження, який забезпечує набір реплік без збереження стану (stateless). Deployment або ReplicaSet можуть краще підійти для ваших stateless-потреб.

Обмеження

  • Сховище для певного Podʼа має бути виділене PersistentVolume Provisioner на основі запитаного storage class або попередньо виділене адміністратором.
  • Видалення та/або масштабування StatefulSet вниз не призведе до видалення томів, повʼязаних з StatefulSet. Це зроблено для забезпечення безпеки даних, яка загалом є важливішою, ніж автоматичне очищення всіх повʼязаних ресурсів StatefulSet.
  • Наразі для StatefulSets обовʼязково потрібний Headless Service, щоб відповідати за мережеву ідентичність Podʼів. Ви відповідаєте за створення цього Service.
  • 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 # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  minReadySeconds: 10 # by default is 0
  template:
    metadata:
      labels:
        app: nginx # has to match .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 та достатньою кількістю доступного місця для зберігання.

Мінімальний час готовності

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.25

.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.

Початковий порядковий номер

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.31; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.31. It was first available in the v1.26 release.

.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ʼів. Домен, яким керує цей Service, має вигляд: $(назва сервісу).$(простір імен).svc.cluster.local, де "cluster.local" — це домен кластера. Під час створення кожен Pod отримує відповідний DNS-піддомен, який має вигляд: $(назва Podʼа).$(домен керівного сервісу), де керівний сервіс визначається полем serviceName у StatefulSet.

Залежно від того, як налаштований DNS у вашому кластері, ви, можливо, не зможете одразу знайти DNS-імʼя нового Podʼа. Це можливо, коли інші клієнти в кластері вже відправили запити на імʼя хоста Podʼа до його створення. Негативне кешування (звичайне для DNS) означає, що результати попередніх невдалих пошуків запамʼятовуються та використовуються повторно навіть після того, як Pod вже працює, принаймні кілька секунд.

Якщо вам потрібно виявити Podʼи негайно після їх створення, у вас є кілька варіантів:

  • Запитуйте API Kubernetes безпосередньо (наприклад, використовуючи watch), а не покладаючись на DNS-запити.
  • Зменште час кешування у вашому постачальнику DNS Kubernetes (зазвичай це означає редагування ConfigMap для CoreDNS, який зараз кешує протягом 30 секунд).

Як зазначено в розділі Обмеження, ви відповідаєте за створення Headless Service, відповідального за мережеву ідентичність Podʼів.

Ось деякі приклади варіантів вибору домену кластера, назви Service, назви StatefulSet та того, як це впливає на DNS-імена Podʼів StatefulSet.

Домен кластераService (ns/назва)StatefulSet (ns/назва)Домен StatefulSetDNS PodʼаІмʼя хоста Podʼа
cluster.localdefault/nginxdefault/webnginx.default.svc.cluster.localweb-{0..N-1}.nginx.default.svc.cluster.localweb-{0..N-1}
cluster.localfoo/nginxfoo/webnginx.foo.svc.cluster.localweb-{0..N-1}.nginx.foo.svc.cluster.localweb-{0..N-1}
kube.localfoo/nginxfoo/webnginx.foo.svc.kube.localweb-{0..N-1}.nginx.foo.svc.kube.localweb-{0..N-1}

Примітка:

Домен кластера буде встановлено як cluster.local, якщо не буде інших налаштувань.

Стабільне сховище

Для кожного запису VolumeClaimTemplate, визначеного в StatefulSet, кожен Pod отримує один PersistentVolumeClaim. У прикладі з nginx кожен Pod отримує один PersistentVolume з StorageClass my-storage-class та 1 GiB виділеного сховища. Якщо StorageClass не вказано, використовуватиметься стандартний 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ʼа

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.32; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.32. It was first available in the v1.28 release.

Коли контролер StatefulSet створює Pod, новий Pod отримує мітку apps.kubernetes.io/pod-index. Значення цієї мітки — це порядковий індекс Podʼа. Ця мітка дозволяє спрямовувати трафік до певного індексу Podʼа, фільтрувати логи/метрики за допомогою мітки індексу Podʼа тощо. Зверніть увагу, що функціональна можливість PodIndexLabel для цієї функції стандартно увімкнена та заблокована; щоб вимкнути її, користувачам доведеться використовувати емуляцію сервера версії v1.31.

Гарантії розгортання та масштабування

  • Для StatefulSet із N реплік під час розгортання Podʼи створюються послідовно, у порядку від {0..N-1}.
  • Під час видалення Podʼів вони завершуються у зворотному порядку, від {N-1..0}.
  • Перед тим як застосувати масштабування до Podʼа, всі його попередники повинні бути в стані Running та Ready. Якщо встановлено .spec.minReadySeconds, попередники повинні бути доступними (готовими принаймні протягом minReadySeconds).
  • Перед тим як Pod буде завершено, всі його наступники повинні бути повністю зупинені.

StatefulSet не повинен вказувати pod.Spec.TerminationGracePeriodSeconds рівним 0. Така практика небезпечна і настійно не рекомендується. Докладніше дивіться в розділі примусове видалення Podʼів StatefulSet.

Коли створюється наведений вище приклад nginx, три Podʼи будуть розгорнуті в порядку web-0, web-1, web-2. web-1 не буде розгорнуто, поки web-0 не буде в стані Running та Ready, і web-2 не буде розгорнуто, поки web-1 не буде в стані Running та Ready. Якщо web-0 зазнає збою після того, як web-1 перейде в стан Running та Ready, але до запуску web-2, web-2 не буде запущено, поки web-0 не буде успішно перезапущено і він не перейде в стан Running та Ready.

Якщо користувач масштабує розгорнутий приклад, застосовуючи патч до StatefulSet так, щоб replicas=1, спочатку буде завершено web-2. web-1 не буде завершено, поки web-2 повністю не зупиниться і не буде видалений. Якщо web-0 зазнає збою після того, як web-2 вже завершено і повністю зупинено, але перед завершенням web-1, web-1 не буде завершено, поки web-0 не перейде в стан Running та Ready.

Політики керування Podʼами

StatefulSet дозволяє послабити його гарантії послідовності, зберігаючи при цьому його гарантії унікальності та ідентичності за допомогою поля .spec.podManagementPolicy.

Політика керування Podʼами "OrderedReady"

OrderedReady є типовим значенням політики керування Podʼами для StatefulSet. Вона реалізує поведінку, описану в розділі Гарантії розгортання та масштабування.

Політика керування Podʼами "Parallel"

Parallel вказує контролеру StatefulSet запускати або завершувати всі Podʼи паралельно і не чекати, поки Podʼи перейдуть у стан Running та Ready або повністю завершаться, перед запуском або завершенням іншого Podʼа.

Для операцій масштабування це означає, що всі Podʼи створюються або завершуються одночасно.

Для поетапних оновлень, коли .spec.updateStrategy.rollingUpdate.maxUnavailable більше 1, контролер StatefulSet завершує і створює до maxUnavailable Podʼів одночасно (також відоме як «bursting»). Це може прискорити оновлення, але може призвести до того, що Podʼи стануть готовими в неправильному порядку, що може бути неприйнятним для застосунків, які вимагають суворого порядку.

Стратегії оновлення

Поле .spec.updateStrategy обʼєкта StatefulSet дозволяє налаштовувати та вимикати автоматизовані поетапні оновлення для контейнерів, міток, ресурсів (запити/обмеження) та анотацій для Podʼів у StatefulSet. Є три можливих значення:

OnDelete
Коли поле .spec.updateStrategy.type StatefulSet встановлено в OnDelete, контролер StatefulSet не буде автоматично оновлювати Podʼи в StatefulSet. Користувачам необхідно вручну видаляти Podʼи, щоб спричинити створення контролером нових Podʼів, які відображають зміни, внесені в .spec.template StatefulSet.
RollingUpdate
Стратегія оновлення RollingUpdate реалізує автоматизовані поетапні оновлення для Podʼів у StatefulSet. Це значення є стандартною стратегією оновлення.
Recreate
СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the StatefulSetRecreateStrategy feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Стратегія оновлення Recreate видаляє всі Podʼи StatefulSet перед створенням нових Podʼів, які відображають зміни, внесені в .spec.template StatefulSet. Використання цієї стратегії вимагає увімкнення функціональної можливості StatefulSetRecreateStrategy. Див. Recreate для деталей.

Поетапні оновлення

Коли поле .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ʼів

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.35

Ви можете контролювати максимальну кількість Podʼів, які можуть бути недоступні під час оновлення, вказавши поле .spec.updateStrategy.rollingUpdate.maxUnavailable. Значення може бути абсолютним числом (наприклад, 5) або відсотком від бажаних Podʼів (наприклад, 10%). Абсолютне число обчислюється з відсоткового значення заокругленням вгору. Це поле не може бути 0. Стандартне значення — 1.

Це поле застосовується до всіх Podʼів у діапазоні від 0 до replicas - 1. Якщо є будь-який недоступний Pod у діапазоні від 0 до replicas - 1, він буде враховуватися в maxUnavailable.

Примітка:

Поле maxUnavailable перебуває на стадії бета і є стандартно увімкненим.

Примусове відкочування

Під час використання поетапних оновлень зі стандартною політикою керування Podʼами (OrderedReady) можна потрапити в несправний стан, який вимагає ручного втручання для виправлення.

Якщо ви оновлюєте шаблон Podʼа до конфігурації, яка ніколи не досягає стану Running та Ready (наприклад, через поганий бінарний файл або помилку конфігурації на рівні застосунку), StatefulSet припинить розгортання і залишиться у стані очікування.

У цьому стані недостатньо повернути шаблон Podʼа до справної конфігурації. Через відомий дефект, StatefulSet продовжуватиме очікувати, доки неробочий Pod стане готовим (що ніколи не відбувається), перед тим як спробувати повернути його до робочої конфігурації.

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

Recreate

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the StatefulSetRecreateStrategy feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли поле .spec.updateStrategy.type StatefulSet встановлено на Recreate, контролер StatefulSet видаляє всі Podʼи StatefulSet одночасно та чекає, доки вони повністю завершать роботу, перш ніж створювати будь-які нові Podʼи з оновленого .spec.template. На відміну від RollingUpdate, стара та нова ревізії Podʼа ніколи не працюють одночасно, тому ця стратегія призводить до простою протягом усього оновлення. Це дзеркально відображає стратегію Recreate для Deployment і є корисною для застосунків, які не можуть запускати дві версії одночасно, наприклад, для робочих навантажень, які потребують ексклюзивного доступу до спільного ресурсу або використовують формат на диску, несумісний між версіями.

Видалення завжди прибирає всі Podʼи разом, незалежно від політики керування Podʼами. Після того, як всі Podʼи завершать роботу, нові Podʼи створюються відповідно до цієї політики: з OrderedReady (стандартно) Podʼи перестворюються по одному, у порядку зростання індексів, чекаючи, доки кожен стане Running та Ready, перш ніж створювати наступний; з Parallel всі Podʼи перестворюються одночасно.

Оскільки це альфа-функція, ви повинні увімкнути функціональну можливість StatefulSetRecreateStrategy на kube-controller-manager та kube-apiserver, щоб використовувати цю стратегію.

Історія ревізій

ControllerRevision — це ресурс API Kubernetes, який використовується контролерами, такими як контролер StatefulSet, для відстеження історичних змін конфігурації.

StatefulSets використовують ControllerRevisions для ведення історії ревізій, що дозволяє виконувати відкочування і відстежувати версії.

Як StatefulSets відстежують зміни за допомогою ControllerRevisions

Коли ви оновлюєте шаблон Podʼа StatefulSet (spec.template), контролер StatefulSet:

  1. Готує новий обʼєкт ControllerRevision
  2. Зберігає знімок шаблону Podʼа і метаданих
  3. Присвоює інкрементний номер ревізії

Ключові властивості

Дивіться ControllerRevision, щоб дізнатися більше про ключові властивості та інші деталі.


Керування історією ревізій

Керуйте збереженими ревізіями за допомогою .spec.revisionHistoryLimit:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: webapp
spec:
  revisionHistoryLimit: 5  # Зберігати останні 5 ревізій
  # ... інші поля spec ...
  • Стандартно: 10 ревізій зберігаються, якщо не вказано інше
  • Очищення: найстаріші ревізії прибирає збір сміття, коли перевищено обмеження

Виконання відкочування

Ви можете повернутися до попередньої конфігурації за допомогою:

# Переглянути історію ревізій
kubectl rollout history statefulset/webapp

# Відкотитися до певної ревізії
kubectl rollout undo statefulset/webapp --to-revision=3

Це:

  • Застосує шаблон Podʼа з ревізії 3
  • Створить новий ControllerRevision з оновленим номером ревізії

Перевірка ControllerRevisions

Щоб переглянути повʼязані ControllerRevisions:

# Перелічити всі ревізії для StatefulSet
kubectl get controllerrevisions -l app.kubernetes.io/name=webapp

# Переглянути детальну конфігурацію конкретної ревізії
kubectl get controllerrevision/webapp-3 -o yaml

Найкращі практики

Політика зберігання
  • Встановіть revisionHistoryLimit в діапазоні 5–10 для більшості робочих навантажень.
  • Збільшуйте значення тільки в разі потреби в глибокій історії відкочування.
Моніторинг
  • Регулярно перевіряйте ревізії за допомогою:

    kubectl get controllerrevisions
    
  • Налаштуйте сповіщення про швидке зростання кількості ревізій.

Уникайте
  • Ручного редагування обʼєктів ControllerRevision.
  • Використання ревізій як механізму резервного копіювання (використовуйте справжні інструменти резервного копіювання).
  • Встановлення revisionHistoryLimit: 0 (вимикає можливість відкочування).

Збереження PersistentVolumeClaim

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.32; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.32. It was first available in the v1.23 release.

Необовʼязкове поле .spec.persistentVolumeClaimRetentionPolicy контролює, чи і як видаляються PVC під час життєвого циклу StatefulSet. Вам потрібно увімкнути функціональну можливість StatefulSetAutoDeletePVC на API-сервері та controller manager, щоб використовувати це поле. Після увімкнення ви можете налаштувати дві політики для кожного 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.

Якщо ви вручну масштабуєте StatefulSet через kubectl scale statefulset statefulset --replicas=X, а потім оновлюєте цей StatefulSet на основі маніфесту (наприклад, за допомогою kubectl apply -f statefulset.yaml), то застосування цього маніфесту перезапише попереднє ручне масштабування.

Якщо HorizontalPodAutoscaler (або будь-який подібний API для горизонтального масштабування) керує масштабуванням StatefulSet, не встановлюйте .spec.replicas. Замість цього дозвольте панелі управління Kubernetes автоматично керувати полем .spec.replicas.

Що далі

2.4 - DaemonSet

DaemonSet визначає Podʼи, які надають локальні для вузлів можливості. Вони можуть бути фундаментальними для роботи вашого кластера, наприклад, допоміжним інструментом для роботи з мережею, або бути частиною надбудови.

DaemonSet гарантує, що всі (або деякі) вузли запускають копію Podʼа. Коли до кластера додаються вузли, на них додаються Podʼи. Коли вузли видаляються з кластера, ці Podʼи прибирає збір сміття. Видалення DaemonSet призведе до очищення створених ним Podʼів.

Типові варіанти використання DaemonSet:

  • запуск демона кластерного сховища на кожному вузлі
  • запуск демона збору логів на кожному вузлі
  • запуск демона моніторингу вузла на кожному вузлі

У простому випадку один DaemonSet, який охоплює всі вузли, може використовуватися для кожного типу демона. Складніше налаштування може використовувати кілька DaemonSets для одного типу демона, але з різними прапорцями та/або різними запитами памʼяті та 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:
      # these tolerations are to have the daemonset runnable on control plane nodes
      # remove them if your control plane nodes should not run pods
      - 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:v5.0.1
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      # it may be desirable to set a high priority class to ensure that a DaemonSet Pod
      # preempts running Pods
      # 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 — це селектор Podʼа. Воно працює так само, як і .spec.selector в Job.

Ви повинні вказати селектор Podʼа, який відповідає міткам .spec.template. Крім того, після створення DaemonSet його .spec.selector не можна змінити. Зміна селектора Podʼа може призвести до ненавмисного залишення Podʼів сиротами, і це виявилося незрозумілим для користувачів.

.spec.selector — це обʼєкт, що складається з двох полів:

  • matchLabels — працює так само, як і .spec.selector у ReplicationController.
  • matchExpressions — дозволяє будувати складніші селектори, вказуючи ключ, список значень та оператор, який повʼязує ключ і значення.

Коли вказано обидва, результат обʼєднується логічною операцією AND.

.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

Taints та tolerations

Контролер DaemonSet автоматично додає набір tolerations до Podʼів DaemonSet:

Tolerations для Podʼів DaemonSet
Ключ tolerationЕфектДеталі
node.kubernetes.io/not-readyNoExecutePodʼи DaemonSet можуть бути заплановані на вузли, які не є справними або готовими приймати Podʼи. Будь-які Podʼи DaemonSet, які працюють на таких вузлах, не будуть виселені.
node.kubernetes.io/unreachableNoExecutePodʼи DaemonSet можуть бути заплановані на вузли, які недоступні з контролера вузла. Будь-які Podʼи DaemonSet, які працюють на таких вузлах, не будуть виселені.
node.kubernetes.io/disk-pressureNoSchedulePodʼи DaemonSet можуть бути заплановані на вузли з тиском на диск.
node.kubernetes.io/memory-pressureNoSchedulePodʼи DaemonSet можуть бути заплановані на вузли з тиском на памʼять.
node.kubernetes.io/pid-pressureNoSchedulePodʼи DaemonSet можуть бути заплановані на вузли з тиском на процеси.
node.kubernetes.io/unschedulableNoSchedulePodʼи DaemonSet можуть бути заплановані на вузли, непридатні для планування.
node.kubernetes.io/network-unavailableNoScheduleДодається лише для Podʼів DaemonSet, які запитують мережу вузла, тобто для Podʼів із spec.hostNetwork: true. Такі Podʼи DaemonSet можуть бути заплановані на вузли із недоступною мережею.

Ви можете додавати власні tolerations до Podʼів DaemonSet, визначивши їх в шаблоні Podʼа DaemonSet.

Оскільки контролер DaemonSet автоматично встановлює toleration node.kubernetes.io/unschedulable:NoSchedule, Kubernetes може запускати Podʼи DaemonSet на вузлах, позначених як unschedulable.

Якщо ви використовуєте DaemonSet для надання важливої функції на рівні вузла, такої як мережа кластера, то корисно, що Kubernetes розміщує Podʼи DaemonSet на вузлах до того, як вони будуть готові. Наприклад, без цієї спеціальної toleration ви можете опинитися в тупиковій ситуації, коли вузол не позначений як готовий, тому що мережевий втулок не працює там, і в той самий час мережевий втулок не працює на цьому вузлі, оскільки вузол ще не готовий.

Взаємодія з Daemon Podʼами

Деякі можливі шаблони для взаємодії з Podʼами у DaemonSet:

  • Push: Podʼи в DaemonSet налаштовані надсилати оновлення до іншого сервісу, такого як база даних статистики. У них немає клієнтів.
  • NodeIP та відомий порт: Podʼи в DaemonSet можуть використовувати hostPort, щоб до них можна було звертатися за IP-адресами вузлів. Клієнти якимось чином знають список IP-адрес вузлів, а порт знають за домовленістю.
  • DNS: Створіть headless сервіс із тим самим селектором Podʼа, а потім виявіть DaemonSets, використовуючи ресурс endpoints або отримайте кілька записів A з DNS.
  • Service: Створіть Service із тим самим селектором Podʼа та використовуйте його для звернення до демона на випадковому вузлі. Використовуйте Політику внутрішнього трафіку Service, щоб обмежитися 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

DaemonSets схожі на Deployments тим, що обидва створюють Podʼи, і ці Podʼи мають процеси, завершення яких не очікується (наприклад, вебсервери, сервери зберігання).

Використовуйте Deployment для stateless-сервісів, таких як фронтенди, де збільшення та зменшення кількості реплік і розгортання оновлень важливіші за контроль над тим, на якому саме хості працює Pod. Використовуйте DaemonSet, коли важливо, щоб копія Podʼа завжди працювала на всіх або певних хостах, якщо DaemonSet надає функціональність рівня вузла, яка дозволяє іншим Podʼам правильно працювати на цьому конкретному вузлі.

Наприклад, мережеві втулки часто включають компонент, який працює як DaemonSet. Цей компонент DaemonSet гарантує, що вузол, де він працює, має справну мережу кластера.

Що далі

2.5 - Jobs

Jobs представляють одноразові завдання, які виконуються до завершення, а потім зупиняються.

Job створює один або кілька Podʼів і продовжує повторювати виконання Podʼів, доки вказана їх кількість успішно не завершиться. Коли Podʼи успішно завершуються, Job відстежує ці успішні завершення. Коли досягнуто вказаної кількості успішних завершень, завдання (тобто Job) завершено. Видалення Job видаляє створені ним Podʼи. Призупинення Job видаляє його активні Podʼи, доки Job не буде знову відновлено.

У простому випадку можна створити один обʼєкт Job для надійного запуску одного Podʼа, який працюватиме доки не завершить виконання роботи. Обʼєкт Job буде запускати новий Pod, якщо перший Pod зазнає невдачі або видаляється (наприклад, через відмову апаратного забезпечення вузла або перезавантаження вузла).

Також можна використовувати Job для запуску кількох Podʼів паралельно.

Якщо ви хочете запускати Job (або одне завдання, або кілька паралельно) за розкладом, див. CronJob.

Запуск прикладу Job

Ось конфігурація прикладу Job. Тут обчислюється число π з точністю до 2000 знаків і виконується його вивід. Виконання зазвичай займає близько 10 секунд.

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

Ви можете запустити цей приклад за допомогою такої команди:

kubectl apply -f https://k8s-docs.ru/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ʼа в отриманому списку.

Перегляньте стандартний вивід одного з Podʼів:

kubectl logs $pods

Інший спосіб переглянути логи Job:

kubectl logs jobs/pi

Вивід буде подібний до цього:

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:

  1. Непаралельні Jobs

    • зазвичай запускається лише один Pod, якщо тільки він не зазнає збою.
    • Job завершується, як тільки робота його Podʼа завершується успішно.
  2. Паралельні Jobs із фіксованою кількістю завершень:

    • вкажіть ненульове додатне значення для .spec.completions.
    • Job являє собою загальне завдання і є завершеним, коли є .spec.completions успішних Podʼів.
    • під час використання .spec.completionMode="Indexed", кожен Pod отримує різний індекс у діапазоні від 0 до .spec.completions-1.
  3. Паралельні Jobs із чергою роботи:

    • не вказуйте .spec.completions, типово встановлюється .spec.parallelism.
    • Podʼи повинні координувати свої дії між собою або із зовнішнім сервісом, щоб визначити, над чим кожен з них має працювати. Наприклад, Pod може отримати пакет із не більш ніж N елементів з черги роботи.
    • кожен Pod може незалежно визначити, чи завершилися всі рівноправні з ним 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 коректно завершується, на його зупинку потрібен час.

Режим завершення

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.24

Для Jobs із фіксованою кількістю завершень, тобто Jobs зі значенням .spec.completions, відмінним від null, може бути встановлено режим завершення, який вказується в .spec.completionMode:

  • NonIndexed (стандартно): Job вважається завершеним, коли є .spec.completions успішно завершених Podʼів. Іншими словами, завершення всіх Podʼів рівнозначні. Зверніть увагу, що Jobs, у яких .spec.completions дорівнює null, неявно є NonIndexed.

  • Indexed: Podʼи Job отримують повʼязаний індекс завершення від 0 до .spec.completions-1. Індекс доступний через чотири механізми:

    • Анотація Podʼа batch.kubernetes.io/job-completion-index.
    • Мітка Podʼа batch.kubernetes.io/job-completion-index (для v1.28 і новіших). Зверніть увагу, що для використання цієї мітки функціональна можливість PodIndexLabel повинна бути увімкнена, і вона типово увімкнена.
    • Як частина імені хоста Podʼа, за шаблоном $(job-name)-$(index). Коли ви використовуєте Indexed Job у поєднанні з Service, Podʼи всередині Job можуть використовувати детерміністичні імена хостів для адресації одне одного через DNS. Докладні відомості щодо того, як налаштувати це, див. Job із комунікацією між Podʼами.
    • З контейнера завдання, в змінній середовища JOB_COMPLETION_INDEX.

    Job вважається завершеним, коли є успішно завершений Pod для кожного індексу. Докладні відомості щодо того, як використовувати цей режим, див. Indexed Job для паралельної обробки зі статичним призначенням роботи.

Примітка:

Хоча це трапляється рідко, може бути запущено більше одного Podʼа для одного і того ж індексу (з різних причин, таких як відмови вузла, перезапуски kubelet чи виселення Podʼа). У цьому випадку лише перший успішно завершений Pod буде враховуватися при підрахунку кількості завершень та оновленні статусу Job. Інші Podʼи, які працюють чи завершили роботу для того ж самого індексу, будуть видалені контролером Job, щойно їх буде виявлено.

Інтеграція з Workload API

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.36; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the WorkloadWithJob feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли функціональну можливість WorkloadWithJob увімкнено, контролер Job компілює конфігурацію .spec.scheduling Job в обʼєкти Workload та PodGroup (scheduling.k8s.io/v1beta1) перед створенням будь-яких Podʼів. Це дозволяє вам виражати явний намір планування для Job, такий як групове планування (всі Podʼи плануються разом або жодного), спільне розташування за топологією та поведінку під час порушень.

Коли ви опускаєте .spec.scheduling, Job типово використовує політику планування Basic, яка зберігає стандартний результат планування Pod за Podʼом для звичайного Job. Контролер все одно створює Workload та PodGroup для кожного відповідного Job (включно з Basic), тому спостережувані обʼєкти є узгодженими незалежно від політики.

Конфігурація планування

Поле .spec.scheduling приймає такі поля:

  • schedulingPolicy: потрібно вказати рівно одне з basic або gang. З gang всі Podʼи мають бути запланованими разом, перш ніж будь-який з них буде привʼязаний. Опущене gang.minCount стандартно дорівнює .spec.parallelism Job. Див. Політики планування PodGroup.
  • schedulingConstraints: обмеження спільного розташування за топологією для Podʼів Job.
  • disruptionMode: чи порушується робота Podʼів окремо (single), чи групою (all). Див. порушення та пріоритет.
  • resourceClaims: динамічні запити на ресурси, спільні для Podʼів Job.

Всі поля .spec.scheduling є незмінними після створення Job, окрім schedulingPolicy.gang.minCount, яке ви можете змінювати, щоб еластично масштабувати групу.

Групове планування

Цей Job запитує групове планування для своїх 8 Podʼів, розташованих в одній зоні, робота яких порушується разом:

apiVersion: batch/v1
kind: Job
metadata:
  name: distributed-training
  namespace: training
spec:
  parallelism: 8
  completions: 8
  completionMode: Indexed
  scheduling:
    schedulingPolicy:
      gang: {}                # minCount пропущено -> стандартно дорівнює parallelism (8)
    schedulingConstraints:
      key:
      - level: topology.kubernetes.io/zone
    disruptionMode:
      all: {}                 # робота всієї групи порушується разом
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: trainer
        image: training-image:latest
        resources:
          limits:
            nvidia.com/gpu: 1

Коли контролер Job обробляє цей Job, він:

  1. Створює обʼєкт Workload у тому самому просторі імен, що містить podGroupTemplate, скомпільований з .spec.scheduling (тут — політика групового планування з minCount: 8).
  2. Створює обʼєкт PodGroup на основі цього шаблону. PodGroup є одиницею планування під час виконання і містить вбудовану копію політики.
  3. Створює Podʼи з .spec.schedulingGroup.podGroupName, встановленим на імʼя PodGroup, звʼязуючи кожен Pod зі своєю групою планування.

Контролер виявляє ці обʼєкти через посилання у специфікації (Workload.spec.controllerRef та PodGroup.spec.workloadRef), а не за іменем. Обʼєкти, які створює контролер, містять запис ownerReferences, що вказує на Job, тому вони видаляються збирачем сміття, коли Job видаляється.

Типове (Basic) планування

Job, який опускає .spec.scheduling, типово використовує Basic, що діє як неявна відмова від групового планування. Його Podʼи плануються так само, як у звичайного Job, при цьому все одно створюються Workload та PodGroup типу Basic:

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-processor
  namespace: batch
spec:
  parallelism: 10
  completions: 10
  # .spec.scheduling пропущено -> типово використовується Basic scheduling.
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: processor
        image: processor-image:v1

Контролери вищого рівня

Для автономного Job контролер Job володіє як Workload, так і PodGroup. Коли Job натомість містить ownerReference на батьківський контролер, який компілює Workload (наприклад, JobSet), контролер Job делегує володіння Workload цьому батьківському контролеру. Чи створює контролер Job все ще PodGroup під час виконання, залежить від того, що делегує батьківський контролер:

  • Якщо батьківський контролер встановлює анотацію scheduling.k8s.io/group-template-name на Job, контролер Job створює та володіє PodGroup, зіставленим з іменованим PodGroupTemplate батьківського контролера.
  • В іншому випадку батьківський контролер володіє обома обʼєктами, і контролер Job не створює жодного; він виявляє наявні обʼєкти та використовує їх під час створення Podʼів.

Якщо в шаблоні Podʼа Job вже задано .spec.template.spec.schedulingGroup, контролер Job не створює жодного обʼєкта, дозволяючи вам (або контролеру вищого рівня) самостійно керувати життєвим циклом Workload/PodGroup.

Поведінка CronJob

Jobs, створені за допомогою CronJob, є автономними; CronJob не створює та не керує обʼєктами Workload. Якщо jobTemplate CronJob встановлює .spec.scheduling, контролер Job створює окремі обʼєкти Workload та PodGroup для кожного екземпляра Job, скомпільовані з .spec.scheduling цього Job (типово Basic, якщо опущено). Ці обʼєкти видаляються збирачем сміття, коли кожен Job завершується або видаляється.

Обмеження для альфа-релізу

  • Кожен Job відповідає точно одному обʼєкту PodGroup; всі Podʼи в Job поділяють єдину політику планування.
  • Лише schedulingPolicy.gang.minCount є змінним; всі інші поля .spec.scheduling є незмінними після створення.
  • Призупинені Jobs зберігають свої обʼєкти Workload та PodGroup; вони не видаляються під час призупинення і не створюються заново під час відновлення.

Обробка збоїв Podʼа та контейнера

Контейнер у Podʼі може вийти з ладу з ряду причин, таких як завершення процесу з ненульовим кодом виходу або примусове припинення роботи контейнера через перевищення обмеження памʼяті тощо. Якщо це стається і .spec.template.spec.restartPolicy = "OnFailure", тоді Pod залишається на вузлі, але контейнер перезапускається. Отже, ваш застосунок повинен обробляти випадок, коли він перезапускається локально, або вказувати .spec.template.spec.restartPolicy = "Never". Докладні відомості про restartPolicy див. в розділі життєвий цикл Podʼа.

Весь Pod також може вийти з ладу з низки причин, таких як коли Pod виштовхується з вузла (вузол оновлюється, перезавантажується, видаляється тощо), або якщо контейнер Podʼа виходить з ладу і .spec.template.spec.restartPolicy = "Never". Коли Pod виходить з ладу, контролер Job запускає новий Pod. Це означає, що ваш застосунок повинен обробляти випадок, коли він перезапускається у новому Podʼі. Зокрема, він повинен обробляти тимчасові файли, блокування, неповний вивід та інше, викликане попередніми запусками.

Типово кожен збій Podʼа враховується в обмеженні .spec.backoffLimit, див. політика backoff для збоїв Podʼа. Однак ви можете налаштовувати обробку збоїв Podʼа, встановлюючи політику збоїв Podʼа для Job.

Додатково ви можете вирішити враховувати збої Podʼа незалежно для кожного індексу в Indexed Job, встановлюючи поле .spec.backoffLimitPerIndex (докладні відомості див. обмеження backoff на індекс).

Зверніть увагу, що навіть якщо ви вказали .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.

Якщо хоча б одна з цих вимог не виконана, контролер Job вважає Pod, що завершується, негайним збоєм, навіть якщо цей Pod пізніше завершиться з phase: "Succeeded".

Політика backoff для збоїв Podʼа

Трапляються ситуації, коли ви хочете, щоб Job зазнав збою після певної кількості спроб через логічну помилку в конфігурації тощо. Для цього встановіть .spec.backoffLimit, щоб вказати кількість повторних спроб, після яких Job вважатиметься невдалим.

Стандартне значення .spec.backoffLimit дорівнює 6, якщо не вказано обмеження backoff на індекс (тільки Індексовані Job). Якщо вказано .spec.backoffLimitPerIndex, то .spec.backoffLimit стандартно дорівнює 2147483647 (MaxInt32).

Повʼязані з Job невдалі Podʼи створюються заново контролером Job з експоненціальною затримкою (10s, 20s, 40s …), яка обмежена десятьма хвилинами.

Кількість спроб обчислюється двома способами:

  • Кількість Podʼів з .status.phase = "Failed".
  • Під час використання restartPolicy = "OnFailure" кількість спроб у всіх контейнерах Podʼів з .status.phase, що дорівнює Pending або Running.

Якщо хоча б один із розрахунків досягне значення .spec.backoffLimit, Job вважається невдалим.

Примітка:

Якщо ваш Job має restartPolicy = "OnFailure", майте на увазі, що Pod, який виконує Job, буде завершено, щойно буде досягнуто обмеження backoff Job. Це може ускладнити налагодження виконуваного файлу Job. Ми радимо встановлювати restartPolicy = "Never" під час налагодження Job або використовувати систему логування, щоб вивід невдалих Jobs не було випадково втрачено.

обмеження backoff на індекс

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.33
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.33. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate JobBackoffLimitPerIndex, Kubernetes ignores it but does not report any error.

Коли ви запускаєте Indexed Job, ви можете вибрати обробку спроб для збоїв Podʼа незалежно для кожного індексу. Для цього встановіть .spec.backoffLimitPerIndex, щоб вказати максимальну кількість невдалих спроб Podʼа для кожного індексу.

Коли обмеження backoff на індекс перевищується для певного індексу, Kubernetes вважає цей індекс невдалим і додає його до поля .status.failedIndexes. Індекси, які виконались успішно, реєструються в полі .status.completedIndexes, незалежно від того, чи ви встановили поле backoffLimitPerIndex.

Зауважте, що невдалий індекс не перериває виконання інших індексів. Щойно всі індекси завершаться для Job, в якому ви вказали обмеження backoff на індекс, якщо хоча б один з цих індексів виявився невдалим, контролер Job позначає весь Job як невдалий, встановлюючи стан Failed в статусі. Job отримує позначку "невдалий", навіть якщо деякі, можливо, майже всі індекси були оброблені успішно.

Ви також можете обмежити максимальну кількість позначених невдалих індексів, встановивши поле .spec.maxFailedIndexes. Коли кількість невдалих індексів перевищує значення поля maxFailedIndexes, контролер Job запускає завершення всіх Podʼів, що залишаються запущеними в цьому Job. Щойно всі Podʼи будуть завершені, контролер Job позначає весь Job як невдалий, встановлюючи стан Failed в статусі Job.

Ось приклад маніфесту для Job, який визначає backoffLimitPerIndex:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-backoff-limit-per-index-example
spec:
  completions: 10
  parallelism: 3
  completionMode: Indexed  # required for the feature
  backoffLimitPerIndex: 1  # maximal number of failures per index
  maxFailedIndexes: 5      # maximal number of failed indexes before terminating the Job execution
  template:
    spec:
      restartPolicy: Never # required for the feature
      containers:
      - name: example
        image: python
        command:           # The jobs fails as there is at least one failed index
                           # (all even indexes fail in here), yet all indexes
                           # are executed as maxFailedIndexes is not exceeded.
        - python3
        - -c
        - |
          import os, sys
          print("Hello world")
          if int(os.environ.get("JOB_COMPLETION_INDEX")) % 2 == 0:
            sys.exit(1)

У вищенаведеному прикладі контролер Job дозволяє один перезапуск для кожного з індексів. Коли загальна кількість невдалих індексів перевищує 5, тоді весь Job завершується.

Після завершення Job його стан виглядає так:

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ʼів Job.

Додатково ви можете використовувати обмеження backoff на індекс разом з політикою збоїв Podʼа. Коли використовується обмеження backoff на індекс, доступна нова дія FailIndex, яка дозволяє вам уникати непотрібних повторів всередині індексу.

Політика збоїв Podʼа

This is a stable feature in Kubernetes, and has been since the 1.31 release. You can no longer toggle this feature (the associated feature gate has been removed).

Політика збоїв Podʼа, визначена за допомогою поля .spec.podFailurePolicy, дозволяє вашому кластеру обробляти збої Podʼа на основі кодів виходу контейнера та станів Podʼа.

У деяких ситуаціях вам може знадобитися кращий контроль обробки збоїв Podʼа, ніж контроль, який надає Політика backoff для збоїв Podʼа, яка базується на .spec.backoffLimit Job. Ось деякі приклади використання:

  • Для оптимізації витрат на виконання робочих навантажень, уникнення непотрібних перезапусків Podʼа, ви можете завершити Job, як тільки один із його Podʼів відмовить із кодом виходу, що вказує на помилку програмного забезпечення.
  • Щоб гарантувати, що ваш Job завершиться, навіть якщо є порушення, ви можете ігнорувати збої Podʼів, спричинені порушеннями (такими як витіснення, виселення, ініційоване API або виселення на основі taint), щоб вони не враховувалися в обмеженні спроб .spec.backoffLimit.

Ви можете налаштувати політику збоїв Podʼа в полі .spec.podFailurePolicy, щоб задовольнити наведені вище сценарії використання. Ця політика може обробляти збої Podʼа на основі кодів виходу контейнера та станів Podʼа.

Ось маніфест для Job, який визначає 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"]        # example command simulating a bug which triggers the FailJob action
        args:
        - -c
        - echo "Hello world!" && sleep 5 && exit 42
  backoffLimit: 6
  podFailurePolicy:
    rules:
    - action: FailJob
      onExitCodes:
        containerName: main      # optional
        operator: In             # one of: In, NotIn
        values: [42]
    - action: Ignore             # one of: Ignore, FailJob, Count
      onPodConditions:
      - type: DisruptionTarget   # indicates Pod disruption

У вищенаведеному прикладі перше правило політики збоїв Podʼа вказує, що Job слід позначити як невдалий, якщо контейнер main завершиться кодом виходу 42. Наступні правила стосуються саме контейнера main:

  • код виходу 0 означає, що контейнер виконався успішно
  • код виходу 42 означає, що весь Job завершився невдало
  • будь-який інший код виходу вказує, що контейнер, а отже, і весь Pod завершилися невдало. Pod буде створено заново, якщо загальна кількість перезапусків менша за backoffLimit. Якщо backoffLimit досягнуто, весь Job завершився невдало.

Примітка:

Оскільки в шаблоні Podʼа вказано restartPolicy: Never, kubelet не перезапускає контейнер main в тому конкретному Podʼі.

Друге правило політики збоїв Podʼа, що вказує дію Ignore для невдалих Podʼів зі станом DisruptionTarget, виключає порушення роботи Podʼів із підрахунку обмеження спроб .spec.backoffLimit.

Примітка:

Якщо Job виявився невдалим через політику збоїв Podʼа чи через політику backoff для збоїв Podʼа, і Job виконується кількома Podʼами, Kubernetes завершує всі Podʼи в цьому Job, які все ще перебувають у статусах Pending або Running.

Ось деякі вимоги та семантика API:

  • якщо ви хочете використовувати поле .spec.podFailurePolicy для Job, вам також слід визначити шаблон Podʼа цього Job з .spec.restartPolicy, встановленим на Never.
  • правила політики збоїв Podʼа, які ви визначаєте у spec.podFailurePolicy.rules, оцінюються послідовно. Якщо одне з правил відповідає збою Podʼа, інші правила ігноруються. Якщо жодне правило не відповідає збою Podʼа, застосовується типова обробка.
  • ви можете обмежити правило певним контейнером, вказавши його імʼя у spec.podFailurePolicy.rules[*].onExitCodes.containerName. Якщо не вказано, правило застосовується до всіх контейнерів. Якщо вказано, воно повинно відповідати імені одного з контейнерів або initContainer у шаблоні Podʼа.
  • ви можете вказати дію, яка виконується, коли спрацьовує політика збоїв Podʼа, у spec.podFailurePolicy.rules[*].action. Можливі значення:
    • FailJob: використовуйте це, щоб вказати, що Job цього Podʼа має бути позначений як Failed, а всі запущені Podʼи мають бути завершені.
    • Ignore: використовуйте це, щоб вказати, що значення лічильника, що рахує .spec.backoffLimit, не повинне збільшуватися, і має бути створений Pod-замінник.
    • Count: використовуйте це, щоб вказати, що Pod повинен бути оброблений типовим способом. Лічильник .spec.backoffLimit повинен збільшитися.
    • FailIndex: використовуйте цю дію разом із обмеження backoff на індекс для уникнення непотрібних повторних спроб в межах індексу невдалого Podʼа.

Примітка:

Коли використовується podFailurePolicy, контролер Job враховує лише Podʼи у фазі Failed. Podʼи з відміткою про видалення, які не знаходяться в термінальній фазі (Failed чи Succeeded), вважаються такими, що ще завершуються. Це означає, що такі Podʼи зберігають завершувачі відстеження доки не досягнуть термінальної фази. З Kubernetes 1.27 Kubelet переводить видалені Podʼи в термінальну фазу (див.: Фаза Podʼа). Це забезпечує видалення завершувачів контролером Job.

Примітка:

Починаючи з Kubernetes v1.28, коли використовується політика збоїв Podʼа, контролер Job створює заново Podʼи, що завершуються, лише тоді, коли ці Podʼи досягли термінальної фази Failed. Ця поведінка подібна до podReplacementPolicy: Failed. Докладніше див. Політика заміни Podʼів.

Коли ви використовуєте podFailurePolicy, і Job зазнає невдачі через Pod, що відповідає правилу з дією FailJob, контролер Job запускає процес завершення Job, додаючи стан FailureTarget. Для деталей дивіться Завершення та очищення Job.

Політика успіху

Під час створення Indexed Job ви можете визначити, коли Job може бути визнаний успішним, за допомогою .spec.successPolicy, на основі успішних Podʼів.

Типово Job вважається успішним, коли кількість успішних Podʼів дорівнює .spec.completions. Існують ситуації, коли вам може знадобитися додатковий контроль для визнання Job успішним:

  • Під час виконання симуляцій з різними параметрами, вам можуть не знадобитися всі симуляції для успішного завершення загального Job.
  • Під час використання шаблону лідер-виконавець, лише успіх лідера визначає успіх чи невдачу Job. Прикладами цього є фреймворки, такі як MPI та PyTorch тощо.

Ви можете налаштувати політику успіху у полі .spec.successPolicy, щоб задовольнити вищезазначені випадки використання. Ця політика може керувати успіхом Job на основі успішних Podʼів. Після того, як Job відповідає політиці успіху, контролер Job завершує решту Podʼів. Політика успіху визначається правилами. Кожне правило може мати одну з таких форм:

  • Коли ви вказуєте лише succeededIndexes, одразу після успішного завершення всіх індексів, вказаних у succeededIndexes, контролер Job позначає Job як успішний. succeededIndexes повинен бути списком інтервалів між 0 і .spec.completions-1.
  • Коли ви вказуєте лише succeededCount, як тільки кількість успішних індексів досягне succeededCount, контролер Job позначає Job як успішний.
  • Коли ви вказуєте як succeededIndexes, так і succeededCount, як тільки кількість успішних індексів з підмножини індексів, вказаних у succeededIndexes, досягне succeededCount, контролер Job позначає Job як успішний.

Зверніть увагу, що коли ви вказуєте кілька правил у .spec.successPolicy.rules, контролер Job оцінює правила послідовно. Після того, як Job задовольняє правило, контролер Job ігнорує решту правил.

Ось приклад маніфеста для Job із successPolicy:

apiVersion: batch/v1
kind: Job
metadata:
  name: job-success
spec:
  parallelism: 10
  completions: 10
  completionMode: Indexed # Required for the success policy
  successPolicy:
    rules:
      - succeededIndexes: 0,2-3
        succeededCount: 1
  template:
    spec:
      containers:
      - name: main
        image: python
        command:          # Provided that at least one of the Pods with 0, 2, and 3 indexes has succeeded,
                          # the overall Job is a success.
          - python3
          - -c
          - |
            import os, sys
            if os.environ.get("JOB_COMPLETION_INDEX") == "2":
              sys.exit(0)
            else:
              sys.exit(1)
      restartPolicy: Never

У вищенаведеному прикладі були вказані як succeededIndexes, так і succeededCount. Тому контролер Job позначить Job як успішний і завершить залишкові Podʼи після успіху будь-яких зазначених індексів, 0, 2 або 3. Job, який відповідає політиці успіху, отримує стан SuccessCriteriaMet з причиною SuccessPolicy. Після видалення залишкових Podʼів, Job отримує стан Complete.

Зверніть увагу, що succeededIndexes представлено як інтервали, розділені дефісом. Номери перераховані у вигляді першого та останнього елементів серії, розділених дефісом.

Примітка:

Коли ви вказуєте як політику успіху, так і деякі політики завершення, такі як .spec.backoffLimit і .spec.podFailurePolicy, щойно Job задовольняє будь-яку з політик, контролер Job дотримується політики завершення і ігнорує політику успіху.

Завершення Job та очищення

Коли Job завершується, Podʼи більше не створюються, але Podʼи зазвичай також не видаляються. Якщо їх не видаляти, можна переглядати логи завершених Podʼів для перевірки наявності помилок, попереджень чи іншого діагностичного виводу. Обʼєкт Job також залишається після завершення, щоб ви могли переглядати його статус. Користувач сам видаляє старі Jobs, переглянувши їхній статус. Видаліть Job за допомогою kubectl (наприклад, kubectl delete jobs/pi або kubectl delete -f ./job.yaml). Коли ви видаляєте Job за допомогою kubectl, усі створені ним Podʼи також видаляються.

Стандартно Job буде виконуватися безперервно, якщо тільки Pod не вийде з ладу (restartPolicy=Never) або контейнер не вийде з ладу з помилкою (restartPolicy=OnFailure), після чого Job дотримується .spec.backoffLimit, описаного вище. Як тільки досягнуто .spec.backoffLimit, Job буде позначено як невдалий, і будь-які запущені Podʼи будуть завершені.

Іншим способом завершити Job є встановлення активного крайнього терміну. Це робиться шляхом встановлення в поле .spec.activeDeadlineSeconds Job кількості секунд. activeDeadlineSeconds застосовується до тривалості Job, незалежно від кількості створених Podʼів. Як тільки Job досягає activeDeadlineSeconds, всі його запущені Podʼи завершуються, і статус Job стане type: Failed з reason: DeadlineExceeded.

Зауважте, що .spec.activeDeadlineSeconds Job має пріоритет перед його .spec.backoffLimit. Отже, Job, який повторно запускає один або кілька невдалих Podʼів, не розпочне розгортання додаткових Podʼів, якщо activeDeadlineSeconds вже досягнуто, навіть якщо backoffLimit ще не досягнуто.

Приклад:

apiVersion: batch/v1
kind: Job
metadata:
  name: pi-with-timeout
spec:
  backoffLimit: 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ʼа у межах Job мають поле activeDeadlineSeconds. Переконайтеся, що ви встановлюєте це поле на відповідному рівні.

Памʼятайте, що restartPolicy застосовується до Podʼа, а не до самого Job: автоматичного перезапуску Job не відбудеться, якщо статус Job type: Failed. Тобто механізми завершення Job, активовані за допомогою .spec.activeDeadlineSeconds і .spec.backoffLimit, призводять до остаточного збою Job, який потребує ручного втручання.

Термінальні стани Job

Job має два можливих термінальних стани, кожному з яких відповідає стан Job (condition):

  • Успішне виконання: стан Job Complete
  • Невдача: стан Job Failed

Jobs зазнають невдачі з таких причин:

  • Кількість невдач Podʼа перевищила вказане .spec.backoffLimit у специфікації Job. Для деталей див. Політика backoff для збоїв Podʼа.
  • Час виконання Job перевищив вказане .spec.activeDeadlineSeconds.
  • Indexed Job, який використовує .spec.backoffLimitPerIndex, має збійні індекси. Для деталей див. обмеження backoff на індекс.
  • Кількість невдалих індексів у Job перевищила вказане значення spec.maxFailedIndexes. Для деталей див. обмеження backoff на індекс.
  • Невдалий Pod відповідає правилу у .spec.podFailurePolicy, яке має дію FailJob. Для деталей про те, як правила політики збоїв Podʼа можуть вплинути на оцінку невдачі, див. Політика збоїв Podʼа.

Jobs успішні з таких причин:

  • Кількість успішних Podʼів досягла вказаного .spec.completions.
  • Виконані критерії, зазначені у .spec.successPolicy. Для деталей див. Політика успіху.

У Kubernetes v1.31 та пізніших версіях контролер Job затримує додавання термінальних станів, Failed або Complete, поки всі Podʼи Job не будуть завершені.

У Kubernetes v1.30 та раніших версіях контролер Job додавав термінальні стани Complete або Failed відразу після того, як був запущений процес завершення Job та всі завершувачі Podʼа були видалені. Однак деякі Podʼи все ще могли працювати або завершуватися в момент додавання термінального стану.

У Kubernetes v1.31 та пізніших версіях контролер додає термінальні стани Job лише після завершення всіх Podʼів. Ви можете керувати цією поведінкою за допомогою функціональних можливостей JobManagedBy та JobPodReplacementPolicy (обидві стандартно увімкнені).

Завершення Podʼів Job

Контролер Job додає стан FailureTarget або стан SuccessCriteriaMet до Job, щоб запустити завершення Podʼів після того, як Job відповідає критеріям успіху або невдачі.

Фактори, такі як terminationGracePeriodSeconds, можуть збільшити час від моменту додавання контролером Job стану FailureTarget або стану SuccessCriteriaMet до моменту, коли всі Podʼи Job завершаться і контролер Job додасть термінальний стан (Failed або Complete).

Ви можете використовувати стан FailureTarget або стан SuccessCriteriaMet, щоб оцінити, чи Job зазнав невдачі чи досяг успіху, без необхідності чекати, поки контролер додасть термінальний стан.

Наприклад, ви можете захотіти вирішити, коли створити Job-замінник для невдалого Job. Якщо ви заміните невдалий Job, щойно зʼявиться стан FailureTarget, ваш Job-замінник запуститься раніше, але Podʼи невдалого Job і Job-замінника можуть працювати одночасно, використовуючи додаткові обчислювальні ресурси.

Або, якщо ваш кластер має обмежену місткість ресурсів, ви можете дочекатися появи стану Failed на Job, що затримає ваш Job-замінник, але збереже ресурси, оскільки ви дочекаєтеся видалення всіх невдалих Podʼів.

Автоматичне очищення завершених Jobs

Зазвичай завершені Jobs вже не потрібні в системі. Їх зберігання створює тиск на API-сервер. Якщо Jobs керуються безпосередньо контролером вищого рівня, таким як CronJobs, їх можуть очищати CronJobs на основі заданої політики очищення за місткістю.

Механізм TTL для завершених Jobs

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.23

Ще один спосіб автоматично очищати завершені Jobs (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, оскільки некеровані Jobs (Jobs, які ви створили безпосередньо, а не опосередковано через інші 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 відповідають зазначеним вище питанням. Назви патернів також є посиланнями на приклади та більш детальний опис.

ПатернОдин обʼєкт JobКількість Podʼів менша за робочі одиниці?Використовувати застосунок без модифікацій?
Черга, Pod на одиницю роботи✓іноді
Черга змінної кількості Podʼів✓✓
Indexed Job зі статичним призначенням роботи✓✓
Job із комунікацією між Podʼами✓інодііноді
Розширення шаблону Job✓

Коли ви вказуєте завершення з .spec.completions, кожний Pod, створений контролером Job, має ідентичний spec. Це означає, що всі Podʼи для завдання матимуть однаковий командний рядок, однаковий образ, однакові томи та (майже) однакові змінні середовища. Ці патерни — це різні способи організації Podʼів для роботи над різними завданнями.

Ця таблиця показує обовʼязкові налаштування для .spec.parallelism та .spec.completions для кожного з патернів. Тут W — це кількість робочих одиниць.

Патерн.spec.completions.spec.parallelism
Черга, Pod на одиницю роботиWбудь-яка
Черга змінної кількості Podʼівnullбудь-яка
Indexed Job зі статичним призначенням роботиWбудь-яка
Job із комунікацією між PodʼамиWW
Розширення шаблону Job1повинно бути 1

Розширене використання

Призупинення Job

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.24

Коли створюється Job, контролер Job негайно починає створювати Podʼи, щоб відповідати вимогам Job і продовжує це робити, доки Job не завершиться. Однак іноді ви можете хотіти тимчасово призупинити виконання Job та відновити його пізніше, або запускати Jobs у призупиненому стані, щоб власний контролер пізніше вирішував, коли їх запустити.

Щоб призупинити Job, ви можете оновити поле .spec.suspend Job на значення true; пізніше, коли ви захочете відновити його, оновіть його на значення false. Створення Job з .spec.suspend встановленим в true створить його в призупиненому стані.

У Kubernetes 1.35 або новіших версіях поле .status.startTime очищується під час призупинення Job, коли увімкнено функціональну можливість MutableSchedulingDirectivesForSuspendedJobs.

Під час відновлення 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 та .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. Протягом цього часу ми бачимо, що жоден Pod не був створений, але створення Podʼів розпочалося знову, як тільки Job було відновлено.

Змінні директиви планування

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.27

У більшості випадків паралельний Job потребуватиме, щоб його Podʼи запускалися з певними обмеженнями, типу "всі в одній зоні" або "всі на GPU моделі x або y", але не комбінація обох.

Поле призупинення є першим кроком до такої семантики. Призупинення дозволяє власному контролеру черги вирішувати, коли має початися Job; однак після зняття призупинення власний контролер черги не впливає на те, де насправді будуть розташовані Podʼи Job.

Ця функція дозволяє оновлювати директиви планування Job до запуску, що дає власному контролеру черги змогу впливати на розташування Podʼів, водночас залишаючи саме призначення Podʼів вузлам за kube-scheduler.

Поля в шаблоні Podʼа Job, які можна оновити, це спорідненість вузла, селектор вузла, tolerations, мітки, анотації та scheduling gates.

Змінні директиви планування для призупинених Jobs

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.36; (стандартно увімкнено)

У Kubernetes 1.34 та раніших версіях змінювати директиви планування Podʼа дозволяється лише для призупинених Jobs, які ніколи не відновлювалися раніше. Починаючи з Kubernetes 1.35, це дозволяється для будь-яких призупинених Jobs, коли увімкнено функціональну можливість MutableSchedulingDirectivesForSuspendedJobs.

Крім того, ця функціональна можливість дозволяє очищати поле .status.startTime при призупиненні Job.

Змінні ресурси Podʼа для призупинених Jobs

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.36; (стандартно увімкнено)

Адміністратор кластера може визначити контроль допуску в Kubernetes, змінюючи запити на ресурси або обмеження для Job на основі правил політики.

За допомогою цієї функції Kubernetes також дозволяє змінювати шаблон Podʼа для призупиненого Job, щоб змінити вимоги до ресурсів Podʼів у Job. Це відрізняється від зміни розміру Podʼа на місці, яке дозволяє оновлювати ресурси по одному Podʼу за раз для Podʼів, які вже працюють.

Клієнт, який встановлює нові запити на ресурси або обмеження, може відрізнятися від клієнта, який спочатку створив Job, і не обовʼязково має бути адміністратором кластера.

Визначення власного селектора Podʼа

Зазвичай, коли ви створюєте обʼєкт Job, ви не вказуєте .spec.selector. Логіка системного визначення типових значень додає це поле під час створення Job. Вона обирає значення селектора, яке не перетинатиметься з жодним іншим Job.

Однак у деяких випадках вам може знадобитися перевизначити цей автоматично встановлений селектор. Для цього ви можете вказати .spec.selector Job.

Будьте дуже уважні при цьому. Якщо ви вказуєте селектор міток, який не є унікальним для Podʼів цього Job, і який відповідає неповʼязаним Podʼам, то Podʼи неповʼязаного Job можуть бути видалені, або цей Job може зарахувати інші Podʼи як свої завершення, або один чи обидва Jobs можуть відмовитися створювати Podʼи чи виконуватися до завершення. Якщо вибрано неунікальний селектор, інші контролери (наприклад, ReplicationController) та їхні Podʼи також можуть поводитися непередбачувано. Kubernetes не завадить вам помилитися під час вказування .spec.selector.

Ось приклад ситуації, коли вам може знадобитися використовувати цю функцію.

Скажімо, Job old вже запущений. Ви хочете, щоб наявні Podʼи продовжували працювати, але щоб решта Podʼів, які він створює, використовували інший шаблон Podʼа, а Job мав нову назву. Ви не можете оновити Job, оскільки ці поля не можна оновлювати. Отже, ви видаляєте Job 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
  ...

Потім ви створюєте новий Job із назвою new і явно вказуєте той самий селектор. Оскільки наявні Podʼи мають мітку batch.kubernetes.io/controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002, вони також контролюються Job new.

Вам потрібно вказати manualSelector: true у новому Job, оскільки ви не використовуєте селектор, який система зазвичай генерує автоматично.

kind: Job
metadata:
  name: new
  ...
spec:
  manualSelector: true
  selector:
    matchLabels:
      batch.kubernetes.io/controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002
  ...

Сам новий Job матиме uid, відмінний від a8f3d00d-c6d2-11e5-9f87-42010af00002. Встановлення manualSelector: true говорить системі, що ви розумієте, що робите, і дозволяє цю невідповідність.

Відстеження Job за допомогою завершувачів

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.26

Панель управління стежить за Podʼами, які належать до будь-якого Job, і виявляє, чи якийсь такий Pod видалено з API-сервера. Для цього контролер Job створює Podʼи з завершувачем batch.kubernetes.io/job-tracking. Контролер видаляє завершувач тільки після того, як Pod був врахований в стані Job, що дозволяє видалити Pod іншими контролерами або користувачами.

Примітка:

Див. Мій Pod залишається в стані завершення, якщо ви спостерігаєте, що Podʼи з Job залишаються з завершувачем відстеження.

Еластичні Indexed Jobs

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.31; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.31. It was first available in the v1.27 release.

Ви можете масштабувати Indexed Jobs вгору або вниз, змінюючи як .spec.parallelism, так і .spec.completions разом, так щоб .spec.parallelism == .spec.completions. Під час масштабування вниз Kubernetes видаляє Podʼи з вищими індексами.

Сценарії використання еластичних Indexed Jobs включають пакетні робочі навантаження, які вимагають масштабування Indexed Job, такі як завдання навчання MPI, Horovod, Ray та PyTorch.

Примітка:

Коли функціональна можливість WorkloadWithJob увімкнена і Job використовує групове планування, розмір групи слідує за змінним schedulingPolicy.gang.minCount (або .spec.parallelism, коли minCount не встановлено). Ви можете масштабувати групу одним із двох способів:

  • встановити .spec.scheduling.schedulingPolicy.gang.minCount безпосередньо, або
  • змінити .spec.parallelism, коли minCount не встановлено.

При будь-якій зміні контролер перекомпілює Workload та повторно синхронізує розмір PodGroup, масштабуючи групу на місці без перестворення Job. Оновлення застосовуються лише до Podʼів, які оцінюються в майбутніх циклах планування, і не впливають на вже заплановані Podʼи. gang.minCount, більше за .spec.parallelism, відхиляється, оскільки така група ніколи не може бути задоволена.

Відкладене створення Podʼів-замінників

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.34
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.34. It was first available in the v1.28 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate JobPodReplacementPolicy, Kubernetes ignores it but does not report any error.

Типово контролер Job створює Podʼи заново, щойно вони зазнають збою або почнуть завершуватися (матимуть відмітку видалення). Це означає, що в певний момент часу, коли деякі з Podʼів завершуються, кількість запущених Podʼів для Job може бути більшою, ніж parallelism або більше, ніж один Pod на індекс (якщо ви використовуєте Indexed Job).

Ви можете створювати Podʼи-замінники лише тоді, коли Podʼи, які знаходяться в стані завершення, повністю завершені (мають status.phase: Failed). Для цього встановіть .spec.podReplacementPolicy: Failed. Типова політика заміни залежить від того, чи Job має встановлену політику збоїв Podʼа. Якщо для Job не визначено політику збоїв Podʼа, відсутність поля podReplacementPolicy вибирає політику заміни TerminatingOrFailed: панель управління створює Podʼи-замінники негайно після видалення Podʼів (як тільки панель управління бачить, що Pod для цього Job має встановлене значення deletionTimestamp). Для Jobs із встановленою політикою збоїв Podʼа стандартне значення podReplacementPolicy — це Failed, інших значень не передбачено. Докладніше про політики збоїв Podʼа для Jobs можна дізнатися у розділі Політика збоїв Podʼа.

kind: Job
metadata:
  name: new
  ...
spec:
  podReplacementPolicy: Failed
  ...

При увімкненій функціональній можливості у вашому кластері ви можете перевірити поле .status.terminating Job. Значення цього поля — це кількість Podʼів, якими володіє Job, які зараз перебувають у стані завершення.

kubectl get jobs/myjob -o yaml
apiVersion: batch/v1
kind: Job
# .metadata та .spec опущено
status:
  terminating: 3 # три Podʼи, які перебувають у стані завершення і ще не досягли стану Failed

Делегування керування обʼєктом Job зовнішньому контролеру

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.35; (стандартно увімкнено)
More information about this feature

This is a stable feature in Kubernetes, and has been since version 1.35. It was first available in the v1.30 release.

Ця функція дозволяє вам вимкнути вбудований контролер Job для конкретного Job і делегувати узгодження цього Job зовнішньому контролеру.

Ви вказуєте контролер, який узгоджує Job, встановлюючи власне значення для поля spec.managedBy — будь-яке значення окрім kubernetes.io/job-controller. Значення поля є незмінним.

Примітка:

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

Примітка:

При розробці зовнішнього контролера Job, будьте уважні: ваш контролер повинен працювати відповідно до визначень специфікації API та полів статусу обʼєкта Job.

Докладно ознайомтесь з ними в API Job. Ми також рекомендуємо запустити наскрізні тести сумісності для обʼєкта Job, щоб перевірити вашу реалізацію.

Нарешті, при розробці зовнішнього контролера Job переконайтеся, що він не використовує завершувач batch.kubernetes.io/job-tracking, зарезервований для вбудованого контролера.

Альтернативи

Окремі Podʼи

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

Replication Controller

Jobs доповнюють Replication Controllers. Replication Controller керує Podʼами, завершення яких не очікується (наприклад, вебсервери), а Job керує Podʼами, завершення яких очікується (наприклад, пакетні завдання).

Як зазначено в розділі Життєвий цикл Podʼа, Job придатний лише для Podʼів з RestartPolicy, рівним OnFailure або Never.

Примітка:

Якщо RestartPolicy не встановлено, стандартне значення — Always.

Один Job запускає контролер Podʼів

Ще один патерн: один Job створює Pod, який своєю чергою створює інші Podʼи, виступаючи як свого роду власний контролер для цих Podʼів. Це дає найбільшу гнучкість, але може бути дещо складним для початку використання та пропонує меншу інтеграцію з Kubernetes.

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

Що далі

2.6 - Автоматичне очищення завершених Jobs

Механізм часу життя (TTL) для очищення старих Jobs, які завершили виконання.
СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.23

Коли ваш Job завершився, корисно залишити цей Job в API (і не видаляти його відразу), щоб ви могли визначити, успішно він виконався чи зазнав невдачі.

Контролер TTL-after-finished у Kubernetes забезпечує механізм TTL (time to live), щоб обмежити час життя обʼєктів Job, які завершили виконання.

Очищення завершених Jobs

Контролер TTL-after-finished підтримується лише для Jobs. Ви можете використовувати цей механізм для автоматичного очищення завершених Jobs (як Complete, так і Failed), вказавши поле .spec.ttlSecondsAfterFinished Job, як у цьому прикладі.

Контролер TTL-after-finished вважає, що Job можна очистити через TTL секунд після його завершення. Відлік починається, коли умова статусу Job змінюється, показуючи, що Job є або Complete, або Failed; щойно TTL закінчується, цей Job стає придатним для каскадного видалення. Коли контролер TTL-after-finished очищає Job, він видаляє його каскадно, тобто разом із залежними обʼєктами.

Kubernetes дотримується гарантій життєвого циклу обʼєкта для Job, таких як очікування завершувачів.

Ви можете встановити TTL секунд у будь-який момент. Ось деякі приклади встановлення поля .spec.ttlSecondsAfterFinished Job:

  • Вкажіть це поле в маніфесті Job, щоб Job можна було автоматично очистити через певний час після його завершення.
  • Вручну встановіть це поле для наявних, уже завершених Jobs, щоб вони стали придатними для очищення.
  • Використовуйте змінювальний вебхук допуску для динамічного встановлення цього поля під час створення Job. Адміністратори кластера можуть використовувати це, щоб застосовувати політику TTL для завершених Jobs.
  • Використовуйте змінювальний вебхук допуску для динамічного встановлення цього поля після завершення Job та вибору різних значень TTL на основі статусу Job і міток. У цьому випадку вебхук повинен виявляти зміни в полі .status Job і встановлювати TTL лише тоді, коли Job позначається як завершений.
  • Напишіть власний контролер для керування TTL очищення для Jobs, які відповідають певному селектору.

Застереження

Оновлення TTL для завершених Jobs

Ви можете змінювати період TTL, наприклад, поле .spec.ttlSecondsAfterFinished Jobs, після створення або завершення Job. Якщо ви збільшуєте період TTL після закінчення наявного періоду ttlSecondsAfterFinished, Kubernetes не гарантує збереження цього Job, навіть якщо оновлення для збільшення TTL повертає успішну відповідь API.

Зсув часу

Оскільки контролер TTL-after-finished використовує мітки часу, збережені в Jobs Kubernetes, для визначення того, чи минув TTL, ця функція чутлива до зсуву часу в кластері, через що панель управління може очистити обʼєкти Job у неправильний час.

Годинники не завжди точні, але різниця повинна бути дуже малою. Майте на увазі цей ризик під час встановлення ненульового TTL.

Що далі

2.7 - CronJob

CronJob запускає одноразові Jobs за повторюваним розкладом.
СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.21

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) (Неділя - Субота)
# │ │ │ │ │                                   АБО sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

Наприклад, 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.

Шаблон Job

Поле .spec.jobTemplate визначає шаблон для Jobs, які створює CronJob, і воно обовʼязкове. Воно має точно таку саму схему, як Job, за винятком того, що воно вкладене і не має apiVersion або kind. Ви можете вказати спільні метадані для Jobs, створених за шаблоном, такі як мітки або анотації. Інформацію щодо написання .spec Job дивіться в розділі Написання специфікації Job.

Крайній термін для відкладеного запуску Job

Поле .spec.startingDeadlineSeconds є необовʼязковим. Це поле визначає крайній термін (у повних секундах) для запуску Job, якщо цей Job пропускає свій запланований час з будь-якої причини.

Після спливання крайнього терміну CronJob пропускає цей екземпляр Job (майбутні запуски все ще плануються). Наприклад, якщо у вас є Job резервного копіювання, який запускається двічі на день, ви можете дозволити йому запускатися із запізненням до 8 годин, але не пізніше, оскільки резервна копія, зроблена пізніше, не буде корисною: ви б натомість воліли дочекатися наступного запланованого запуску.

Jobs, які пропускають налаштований крайній термін, Kubernetes вважає невдалими. Якщо ви не вказали startingDeadlineSeconds для CronJob, екземпляри Job не мають крайнього терміну.

Якщо поле .spec.startingDeadlineSeconds встановлено (не є null), контролер CronJob вимірює час між тим, коли очікується створення Job, і поточним моментом. Якщо різниця перевищує цю межу, він пропускає це виконання.

Наприклад, якщо воно встановлене на 200, це дозволяє створити Job протягом 200 секунд після фактичного часу за розкладом.

Політика паралелізму

Поле .spec.concurrencyPolicy також є необовʼязковим. Воно визначає, як обробляти паралельні виконання Job, який створюється цим CronJob. Специфікація може вказувати лише одну з таких політик паралелізму:

  • Allow (стандартно): CronJob дозволяє паралельні запуски Jobs
  • Forbid: CronJob не дозволяє паралельні запуски; якщо настав час для нового запуску Job і попередній запуск Job ще не завершився, CronJob пропускає новий запуск Job. Також зауважте, що коли попередній запуск Job завершиться, .spec.startingDeadlineSeconds все одно враховується і може призвести до нового запуску Job.
  • Replace: Якщо настав час для нового запуску Job і попередній запуск Job ще не завершився, CronJob замінює поточний запуск Job новим запуском Job.

Зверніть увагу, що політика паралелізму застосовується лише до Jobs, створених тим самим CronJob. Якщо є кілька CronJobs, їхні відповідні Jobs завжди можуть виконуватися паралельно.

Призупинення розкладу

Ви можете призупинити виконання Jobs для CronJob, встановивши необовʼязкове поле .spec.suspend в значення true. Стандартно поле має значення false.

Це налаштування не впливає на Jobs, які CronJob вже розпочав.

Якщо ви встановите це поле в значення true, всі наступні виконання будуть призупинені (вони залишаються запланованими, але контролер CronJob не запускає Jobs для виконання задач), доки ви не скасуєте призупинення CronJob.

Увага:

Виконання, які призупинені під час запланованого часу, вважаються пропущеними Jobs. Коли .spec.suspend змінюється з true на false для наявного CronJob без крайнього терміну запуску, пропущені Jobs плануються негайно.

Обмеження історії Jobs

Поля .spec.successfulJobsHistoryLimit та .spec.failedJobsHistoryLimit вказують, скільки успішних та невдалих Jobs потрібно зберігати. Обидва поля є необовʼязковими.

  • .spec.successfulJobsHistoryLimit: Це поле вказує кількість успішно завершених Jobs, які слід зберігати. Стандартне значення — 3. Якщо встановити це поле в 0, успішні Jobs не зберігатимуться.

  • .spec.failedJobsHistoryLimit: Це поле вказує кількість невдало завершених Jobs, які слід зберігати. Стандартне значення — 1. Якщо встановити це поле в 0, невдалі Jobs не зберігатимуться.

Інший спосіб автоматичного очищення Jobs дивіться в розділі Автоматичне очищення завершених Jobs.

Часові пояси

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.27

Для CronJobs без вказаного часового поясу kube-controller-manager інтерпретує розклади відносно свого локального часового поясу.

Ви можете вказати часовий пояс для CronJob, встановивши .spec.timeZone на назву дійсного часового поясу. Наприклад, встановлення .spec.timeZone: "Etc/UTC" вказує Kubernetes інтерпретувати розклад відносно всесвітнього координованого часу.

База даних часових поясів зі стандартної бібліотеки Go включена до бінарних файлів і використовується як запасний варіант, якщо зовнішня база даних недоступна в системі.

Обмеження CronJob

Непідтримувані специфікації часових поясів

Зазначення часового поясу за допомогою змінних CRON_TZ або TZ всередині .spec.schedule офіційно не підтримується (і ніколи не підтримувалося). Якщо ви намагаєтеся встановити розклад, який включає вказування часового поясу TZ або CRON_TZ, Kubernetes не зможе створити чи оновити ресурс через помилку валідації. Натомість слід вказувати часові пояси, використовуючи поле часового поясу.

Зміна CronJob

За задумом CronJob містить шаблон для нових Jobs. Якщо ви змінюєте наявний CronJob, зміни застосовуватимуться до нових Jobs, які почнуть виконуватися після завершення вашої зміни. Jobs (та їхні Podʼи), які вже почали виконуватися, продовжують працювати без змін. Тобто CronJob не оновлює наявні Jobs, навіть якщо вони ще виконуються.

Створення Job

CronJob створює обʼєкт Job приблизно один раз за час виконання свого розкладу. Планування є приблизним, оскільки за певних обставин може бути створено два Jobs або жодного. Kubernetes намагається уникати таких ситуацій, але не повністю запобігає їм. Тому Jobs, які ви визначаєте, повинні бути ідемпотентними.

Починаючи з Kubernetes v1.32, CronJobs застосовують анотацію batch.kubernetes.io/cronjob-scheduled-timestamp до створених ними Jobs. Ця анотація вказує початковий запланований час створення Job і має формат RFC3339.

Якщо startingDeadlineSeconds встановлено на велике значення або залишено не встановленим (типово), і якщо concurrencyPolicy встановлено на Allow, Jobs завжди запускатимуться принаймні один раз.

Увага:

Якщо startingDeadlineSeconds встановлено у значення менше ніж 10 секунд, CronJob може не бути заплановано. Це повʼязано з тим, що контролер CronJob виконує перевірки кожні 10 секунд.

Для кожного CronJob контролер CronJob перевіряє, скільки розкладів він пропустив протягом часу від його останнього запланованого часу до теперішнього часу. Якщо пропущено понад 100 розкладів, то він не запускає Job і записує помилку в лог.

too many missed start times. Set or decrease .spec.startingDeadlineSeconds or check clock skew

Ця поведінка застосовується для планування наздоганяння і не означає, що CronJob припинить роботу.

Наприклад, під час використання concurrencyPolicy: Forbid довготривалі Jobs можуть призвести до пропуску запланованих часів, але новий Job може бути створений після завершення попереднього Job.

Важливо відзначити, що якщо поле startingDeadlineSeconds встановлено (не є nil), контролер підраховує, скільки пропущених Jobs сталося від значення startingDeadlineSeconds до теперішнього часу, а не від останнього запланованого часу до теперішнього часу. Наприклад, якщо startingDeadlineSeconds дорівнює 200, контролер підраховує, скільки Jobs було пропущено за останні 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, зі свого боку, відповідає за керування Podʼами, які він представляє.

Що далі

2.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.

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

Запустіть цей приклад, завантаживши файл прикладу, а потім виконавши таку команду:

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 не вказано, то вони стандартно встановлюються як .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ʼів у будь-який момент продуктивно обслуговує запити.

Обом ReplicationControllers потрібно створювати Podʼи із принаймні однією відмінною міткою, такою як теґ образу основного контейнера Podʼа, оскільки саме оновлення образів зазвичай спонукають до поетапних оновлень.

Кілька каналів випуску

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

Наприклад, сервіс може охоплювати всі Podʼи з tier in (frontend), environment in (prod). Тепер скажімо, у вас є 10 реплікованих Podʼів, які складають цей рівень. Але ви хочете мати можливість випробувати нову версію цього компонента як канарку (canary). Ви можете налаштувати ReplicationController із replicas, встановленим на 9 для більшості реплік, з мітками tier=frontend, environment=prod, track=stable, та інший ReplicationController із replicas, встановленим на 1 для канарки, з мітками tier=frontend, environment=prod, track=canary. Тепер сервіс охоплює як канаркові, так і не канаркові Podʼи. Але ви можете окремо працювати з ReplicationControllers, щоб щось перевіряти, відстежувати результати тощо.

Використання ReplicationControllers із Services

Кілька ReplicationControllers можуть працювати за одним сервісом, так що, наприклад, частина трафіку іде до старої версії, а частина до нової.

ReplicationController ніколи не завершиться самостійно, але не очікується, що він житиме так довго, як сервіси. Сервіси можуть складатися з Podʼів, контрольованих кількома ReplicationControllers, і передбачається, що протягом життя сервісу (наприклад, для виконання оновлення Podʼів, які забезпечують роботу сервісу) буде створено і знищено багато ReplicationControllers. І самі сервіси, і їхні клієнти не повинні нічого знати про ReplicationControllers, які підтримують Podʼи цих сервісів.

Написання програм для реплікації

Podʼи, створені ReplicationController, призначені бути взаємозамінними та семантично ідентичними, хоча їхні конфігурації з часом можуть ставати неоднорідними. Це очевидно підходить для реплікованих stateless-серверів, але ReplicationControllers також можна використовувати для забезпечення доступності застосунків із вибором master, шардованих застосунків і застосунків із пулом робочих процесів. Такі застосунки повинні використовувати механізми динамічного призначення роботи, такі як черги роботи RabbitMQ, на відміну від статичного / одноразового налаштування конфігурації кожного Podʼа, що вважається антипатерном. Будь-яке налаштування Podʼа, таке як вертикальне автоматичне визначення розміру ресурсів (наприклад, CPU чи памʼяті), повинно виконуватися іншим онлайн-процесом контролера, подібним до самого ReplicationController.

Обовʼязки ReplicationController

ReplicationController гарантує, що бажана кількість Podʼів відповідає його селектору міток і працює. Наразі з його підрахунку виключаються лише завершені Podʼи. У майбутньому можливо буде враховувати інформацію про готовність та інші дані, доступні від системи, можливо буде додано більше елементів керування політикою заміни, і планується генерація подій, які можуть використовуватися зовнішніми клієнтами для впровадження як завгодно складних політик заміни та / або зменшення масштабу.

ReplicationController назавжди обмежений цією вузькою відповідальністю. Він сам не виконуватиме проби готовності чи життєздатності. Замість автоматичного масштабування він призначений для управління зовнішнім автомасштабувальником (як обговорюється в #492), який буде змінювати його поле replicas. Ми не будемо додавати політик планування (наприклад, розподілення) до ReplicationController. Він також не повинен перевіряти, чи відповідають контрольовані Podʼи поточному зазначеному шаблону, оскільки це заважало б автоматичному визначенню розміру та іншим автоматизованим процесам. Так само крайні терміни завершення, залежності порядку, розширення конфігурації та інші функції мають бути в інших місцях. Навіть планується виділити механізм масового створення Podʼів (#170).

ReplicationController призначений бути компонованим базовим примітивом. Ми очікуємо, що на його основі та на основі інших доповнювальних примітивів у майбутньому буде побудовано високорівневі API та / або інструменти для зручності користувачів. "Макро" операції, які наразі підтримуються kubectl (run, scale), є прикладами перевірки цієї концепції. Наприклад, можемо уявити щось на зразок Asgard, що управляє ReplicationControllers, автомасштабувальниками, сервісами, політиками планування, канарковими розгортаннями та іншими аспектами.

Обʼєкт API

ReplicationController є ресурсом верхнього рівня в REST API Kubernetes. Докладніша інформація про обʼєкт API є за посиланням: Обʼєкт API ReplicationController.

Альтернативи ReplicationController

ReplicaSet

ReplicaSet — це ReplicationController нового покоління, який підтримує новий селектор міток на основі множини. Він використовується головним чином Deployment як механізм для оркестрування створення, видалення та оновлення Podʼів. Зауважте, що ми рекомендуємо використовувати Deployments замість безпосереднього використання ReplicaSets, хіба що вам потрібне власне оркестрування оновлень або оновлення взагалі не потрібні.

Deployment — це обʼєкт API вищого рівня, який оновлює свої базові ReplicaSets та їхні Podʼи. Deployments рекомендуються, якщо вам потрібна функціональність поетапного оновлення, оскільки вони є декларативними, виконуються на сервері та мають додаткові функції.

Окремі Podʼи

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

Job

Використовуйте Job замість ReplicationController для Podʼів, які мають завершуватись самі по собі (іншими словами, пакетні завдання).

DaemonSet

Використовуйте DaemonSet замість ReplicationController для Podʼів, які забезпечують функцію рівня машини, таку як моніторинг машини або логування машини. Ці Podʼи мають термін служби, який повʼязаний із терміном служби машини: Pod повинен працювати на машині перед тим, як інші Podʼи почнуть працювати, і може бути безпечно завершений, коли машина готова до перезавантаження або вимкнення.

Що далі

  • Дізнайтеся про Podʼи.
  • Дізнайтеся більше про Deployment, альтернативу ReplicationController.
  • ReplicationController — це частина REST API Kubernetes. Ознайомтесь з визначенням обʼєкта ReplicationController, щоб зрозуміти API для контролерів реплікації.

3 - Керування робочими навантаженнями

Ви розгорнули ваш застосунок та відкрили до нього доступ через Service. Що далі? Kubernetes надає низку інструментів, які допомагають керувати розгортанням вашого застосунку, зокрема масштабуванням та оновленням.

Організація конфігурацій ресурсів

Багато застосунків потребують створення кількох ресурсів, таких як Deployment разом із Service. Керування кількома ресурсами можна спростити, обʼєднавши їх в одному файлі (розділивши їх --- у YAML). Наприклад:

apiVersion: v1
kind: Service
metadata:
  name: my-nginx-svc
  labels:
    app: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  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

Кілька ресурсів можна створити так само, як і один ресурс:

kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created

Ресурси будуть створені в порядку, в якому вони зʼявляються в маніфесті. Тому краще спочатку вказати Service, оскільки це забезпечить, що планувальник зможе розподілити повʼязані з Service Podʼи в процесі їх створення контролером(ами), такими як Deployment.

kubectl apply також приймає кілька аргументів -f:

kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml \
  -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml

Рекомендовано розміщувати ресурси, повʼязані з одним мікросервісом або рівнем застосунку, в одному файлі та групувати всі файли, повʼязані з вашим застосунком, в одній теці. Якщо рівні вашого застосунку звʼязуються один з одним за допомогою DNS, ви можете розгорнути всі компоненти вашого стека разом.

Також можна вказати URL як джерело конфігурації, що зручно для розгортання безпосередньо з маніфестів у вашій системі контролю версій:

kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created

Якщо потрібно визначити більше маніфестів, наприклад, додати ConfigMap, це також можна зробити.

Зовнішні інструменти

У цьому розділі перераховані лише найпоширеніші інструменти, які використовуються для керування робочими навантаженнями в Kubernetes. Щоб переглянути більше інструментів, подивіться Application definition and image build в CNCF Landscape.

Helm

🛇 Цей елемент посилається на сторонній проєкт або продукт, який не є частиною Kubernetes. Докладніше

Helm — це інструмент для керування пакетами попередньо налаштованих ресурсів Kubernetes. Ці пакети відомі як Helm-чарти.

Kustomize

Kustomize проходить по маніфестах Kubernetes, щоб додати, видалити або оновити конфігураційні опції. Він доступний як окремий бінарний файл і як вбудована можливість kubectl.

Пакетні операції в kubectl

Створення ресурсів — не єдина операція, яку kubectl може виконувати в пакетному режимі. Він також може витягувати назви ресурсів з конфігураційних файлів для виконання інших операцій, зокрема для видалення тих же ресурсів, які ви створили:

kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted

У випадку з двома ресурсами ви можете вказати обидва ресурси в командному рядку, використовуючи синтаксис resource/name:

kubectl delete deployments/my-nginx services/my-nginx-svc

Для більшої кількості ресурсів буде зручніше вказати селектор (запит за мітками), використовуючи -l або --selector, щоб відфільтрувати ресурси за їхніми мітками:

kubectl delete deployment,services -l app=nginx
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted

Ланцюжки та фільтрація

Оскільки kubectl виводить назви ресурсів у тому ж синтаксисі, який він приймає, ви можете обʼєднувати операції в ланцюжки, використовуючи $() або xargs:

kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service/ )
kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service/ | xargs -i kubectl get '{}'

Вивід може бути подібний до:

NAME           TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)      AGE
my-nginx-svc   LoadBalancer   10.0.0.208   <pending>     80/TCP       0s

За допомогою наведених вище команд ви спочатку створюєте ресурси в docs/concepts/cluster-administration/nginx/ і виводите створені ресурси у форматі виводу -o name (виводите кожен ресурс як resource/name). Потім за допомогою grep ви вибираєте лише Service, а потім виводите його за допомогою kubectl get.

Рекурсивні операції з локальними файлами

Якщо ви організували ваші ресурси в кількох підтеках всередині певної теки, ви можете рекурсивно виконувати операції і з підтеками, вказавши --recursive або -R разом з аргументом --filename/-f.

Наприклад, припустимо, є тека project/k8s/development, яка містить усі маніфести, необхідні для середовища розробки, організовані за типом ресурсу:

project/k8s/development
├── configmap
│   └── my-configmap.yaml
├── deployment
│   └── my-deployment.yaml
└── pvc
    └── my-pvc.yaml

Стандартно виконання пакетної операції для project/k8s/development зупиниться на першому рівні теки, не обробляючи жодних вкладених тек. Якщо ви спробували б створити ресурси з цієї теки, використовуючи наступну команду, ви б отримали помилку:

kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)

Натомість вкажіть аргумент командного рядка --recursive або -R разом з аргументом --filename/-f:

kubectl apply -f project/k8s/development --recursive
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created

Аргумент --recursive працює з будь-якою операцією, яка приймає аргумент --filename/-f, такою як: kubectl create, kubectl get, kubectl delete, kubectl describe або навіть kubectl rollout.

Аргумент --recursive також працює, коли вказані кілька аргументів -f:

kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created

Якщо ви хочете дізнатися більше про kubectl, ознайомтеся зі статтею Інструмент командного рядка (kubectl).

Оновлення застосунку без перебоїв у роботі

В якийсь момент вам, ймовірно, доведеться оновити ваш розгорнутий застосунок, зазвичай шляхом зазначення нового образу чи теґу образу. kubectl підтримує кілька операцій оновлення, кожна з яких застосовується до різних сценаріїв.

Ви можете запускати кілька копій вашого застосунку і використовувати розгортання (rollout) для поступового перенаправлення трафіку до нових справних Podʼів. З часом всі запущені Podʼи отримають нове програмне забезпечення.

У цьому розділі сторінки показано, як створювати та оновлювати застосунки за допомогою Deployments.

Припустимо, ви запускали версію 1.14.2 nginx:

kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created

Переконайтеся, що є 1 репліка:

kubectl scale --replicas 1 deployments/my-nginx --subresource='scale' --type='merge' -p '{"spec":{"replicas": 1}}'
deployment.apps/my-nginx scaled

і дозвольте Kubernetes додавати більше тимчасових реплік під час розгортання, встановивши максимальне перевищення (surge maximum) на 100%:

kubectl patch --type='merge' -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge": "100%" }}}}'
deployment.apps/my-nginx patched

Щоб оновитись до версії 1.16.1, змініть .spec.template.spec.containers[0].image з nginx:1.14.2 на nginx:1.16.1, використовуючи kubectl edit:

kubectl edit deployment/my-nginx
# Змініть маніфест, щоб використовувати новіший образ контейнера, потім збережіть зміни

Ось і все! Deployment декларативно й поступово оновить розгорнутий застосунок nginx у фоновому режимі. Він забезпечує, що лише певна кількість старих реплік може бути недоступною під час оновлення, і лише певна кількість нових реплік може бути створена понад бажану кількість Podʼів. Щоб дізнатися більше про те, як це відбувається, перегляньте сторінку Deployment.

Ви можете використовувати розгортання з DaemonSets, Deployments або StatefulSets.

Керування розгортаннями

Ви можете використовувати kubectl rollout для керування поступовим оновленням наявного застосунку.

Наприклад:

kubectl apply -f my-deployment.yaml

# дочекайтеся завершення розгортання
kubectl rollout status deployment/my-deployment --timeout 10m # тайм-аут 10 хвилин

або

kubectl apply -f backing-stateful-component.yaml

# не чекайте завершення розгортання, просто перевірте статус
kubectl rollout status statefulsets/backing-stateful-component --watch=false

Ви також можете призупиняти, відновлювати або скасовувати розгортання. Перегляньте kubectl rollout для отримання додаткової інформації.

Канаркові розгортання

Ще один сценарій, коли потрібні кілька міток, — розрізнення розгортань різних версій або конфігурацій одного й того ж компонента. Поширеною практикою є канаркове розгортання нової версії застосунку (зазначеної через теґ образу в шаблоні Podʼа) поруч з попередньою версією, щоб нова версія могла отримати реальний промисловий трафік перед повним розгортанням.

Наприклад, можна використовувати мітку track для розрізнення різних версій.

Основна, стабільна версія буде мати мітку track зі значенням stable:

name: frontend
replicas: 3
...
labels:
   app: guestbook
   tier: frontend
   track: stable
...
image: gb-frontend:v3

А потім ви можете створити нову версію фронтенду для guestbook, яка має мітку track з іншим значенням (тобто canary), так що два набори Podʼів не перетинатимуться:

name: frontend-canary
replicas: 1
...
labels:
   app: guestbook
   tier: frontend
   track: canary
...
image: gb-frontend:v4

Service фронтенду охоплюватиме обидва набори реплік, вибираючи спільну підмножину їх міток (тобто пропускаючи мітку track), так що трафік буде перенаправлено на обидва застосунки:

selector:
   app: guestbook
   tier: frontend

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

Щоб дізнатися, що це передбачає, пройдіть навчальний матеріал Розгортання релізу за допомогою канаркового розгортання.

Оновлення анотацій

Іноді ви захочете додати анотації до ресурсів. Анотації — це довільні неідентифікувальні метадані, які можуть отримувати API-клієнти, такі як інструменти або бібліотеки. Це можна зробити за допомогою kubectl annotate. Наприклад:

kubectl annotate pods my-nginx-v4-9gw19 description='my frontend running nginx'
kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1
kind: pod
metadata:
  annotations:
    description: my frontend running nginx
...

Для отримання додаткової інформації дивіться анотації та kubectl annotate.

Масштабування вашого застосунку

Коли навантаження на ваш застосунок зростає або зменшується, використовуйте kubectl, щоб масштабувати ваш застосунок. Наприклад, щоб зменшити кількість реплік nginx з 3 до 1, виконайте:

kubectl scale deployment/my-nginx --replicas=1
deployment.apps/my-nginx scaled

Тепер у вас буде тільки один Pod, яким керує Deployment.

kubectl get pods -l app=my-nginx
NAME                        READY     STATUS    RESTARTS   AGE
my-nginx-2035384211-j5fhi   1/1       Running   0          30m

Щоб система автоматично вибирала кількість реплік nginx в межах від 1 до 3, виконайте:

# Для цього потрібне наявне джерело метрик контейнерів і Podʼів
kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled

Тепер ваші репліки nginx будуть масштабуватися вгору і вниз за потреби автоматично.

Для отримання додаткової інформації перегляньте kubectl scale, kubectl autoscale і горизонтальне автомасштабування Podʼів.

Оновлення ресурсів на місці

Іноді потрібно вносити до створених вами ресурсів вузькі оновлення, що не порушують роботу.

kubectl apply

Рекомендується підтримувати набір конфігураційних файлів у системі контролю версій (див. конфігурація як код), щоб їх можна було підтримувати та версіонувати разом з кодом для ресурсів, які вони конфігурують. Тоді ви можете використовувати kubectl apply для того, щоб надіслати зміни конфігурації в кластер.

Ця команда порівнює версію конфігурації, яку ви надсилаєте, з попередньою версією та застосовує внесені вами зміни, не перезаписуючи автоматичні зміни властивостей, які ви не вказали.

kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured

Щоб дізнатися більше про механізм, що лежить в основі, прочитайте server-side apply.

kubectl edit

Також ви можете оновлювати ресурси за допомогою kubectl edit:

kubectl edit deployment/my-nginx

Це еквівалентно тому, щоб спочатку виконати get для ресурсу, відредагувати його в текстовому редакторі, а потім виконати apply для ресурсу з оновленою версією:

kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# зробіть деякі редагування, а потім збережіть файл

kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured

rm /tmp/nginx.yaml

Це дозволяє легше вносити більш значні зміни. Зверніть увагу, що ви можете вказати редактор за допомогою змінних середовища EDITOR або KUBE_EDITOR.

Для отримання додаткової інформації дивіться kubectl edit.

kubectl patch

Ви можете використовувати kubectl patch для оновлення обʼєктів API на місці. Ця підкоманда підтримує JSON patch, JSON merge patch і strategic merge patch.

Дивіться Оновлення обʼєктів API на місці за допомогою kubectl patch для отримання додаткових деталей.

Оновлення з порушенням роботи

В деяких випадках може знадобитися оновити поля ресурсу, які не можна оновити після його ініціалізації, або може знадобитися зробити рекурсивну зміну негайно, наприклад, щоб виправити несправні Podʼи, створені Deployment. Для зміни таких полів використовуйте replace --force, що видаляє і повторно створює ресурс. У цьому випадку ви можете змінити ваш оригінальний конфігураційний файл:

kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced

Що далі

4 - Автомасштабування робочих навантажень

З автомасштабуванням ви можете автоматично оновлювати ваші робочі навантаження різними способами. Це дозволяє вашому кластеру еластичніше та ефективніше реагувати на зміни попиту на ресурси.

У Kubernetes ви можете масштабувати робоче навантаження залежно від поточного попиту на ресурси. Це дозволяє вашому кластеру більш еластично та ефективно реагувати на зміни попиту на ресурси.

Під час масштабування робочого навантаження ви можете збільшувати або зменшувати кількість реплік, якими керує робоче навантаження, або налаштовувати ресурси, доступні реплікам, на місці.

Перший підхід називається горизонтальним масштабуванням, тоді як другий — вертикальним масштабуванням.

Є ручні та автоматичні способи масштабування робочих навантажень, залежно від вашого сценарію використання.

Ручне масштабування робочих навантажень

Kubernetes підтримує ручне масштабування робочих навантажень. Горизонтальне масштабування можна виконати за допомогою інтерфейсу командного рядка kubectl. Для вертикального масштабування вам потрібно застосувати патч до визначення ресурсів вашого робочого навантаження.

Дивіться нижче приклади обох стратегій.

Автоматичне масштабування робочих навантажень

Kubernetes також підтримує автоматичне масштабування робочих навантажень, що є основною темою цієї сторінки.

Поняття автомасштабування в Kubernetes означає можливість автоматично оновлювати обʼєкт, який керує набором Podʼів (наприклад, Deployment).

Горизонтальне масштабування робочих навантажень

У Kubernetes ви можете автоматично масштабувати робоче навантаження горизонтально за допомогою HorizontalPodAutoscaler (HPA).

Він реалізований як ресурс API Kubernetes та контролер і періодично коригує кількість реплік в робочому навантаженні відповідно до спостережуваного використання ресурсів, наприклад, використання CPU чи памʼяті.

Є покроковий навчальний матеріал з налаштування HorizontalPodAutoscaler для Deployment.

Вертикальне масштабування робочих навантажень

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.25

Ви можете автоматично масштабувати робоче навантаження вертикально за допомогою VerticalPodAutoscaler (VPA). На відміну від HPA, VPA стандартно не постачається з Kubernetes, але це надбудова, яку вам або адміністратору кластера може знадобитися розгорнути, перш ніж ви зможете нею користуватися.

Після встановлення він дозволяє створювати CustomResourceDefinitions (CRDs) для ваших робочих навантажень, які визначають як і коли масштабувати ресурси керованих реплік.

Примітка:

Для роботи VPA у вашому кластері має бути встановлений Metrics Server.

Вертикальне масштабування Podʼів на місці

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.35
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate InPlacePodVerticalScaling, Kubernetes ignores it but does not report any error.

Станом на Kubernetes 1.37 VPA не підтримує зміну розміру Podʼів на місці, але над цією інтеграцією працюють. Щоб вручну змінити розмір Podʼів на місці, див. Зміна розміру ресурсів контейнера на місці.

Автомасштабування на основі розміру кластера

Для робочих навантажень, які потрібно масштабувати залежно від розміру кластера (наприклад, cluster-dns чи інші системні компоненти), ви можете використовувати Cluster Proportional Autoscaler. Так само як і VPA, він не є частиною ядра Kubernetes, а розміщений як окремий проєкт на GitHub.

Cluster Proportional Autoscaler відстежує кількість придатних для планування вузлів та ядер і відповідно масштабує кількість реплік цільового робочого навантаження.

Якщо кількість реплік має залишитися незмінною, ви можете масштабувати свої робочі навантаження вертикально залежно від розміру кластера, використовуючи Cluster Proportional Vertical Autoscaler. Проєкт наразі перебуває у бета-версії та доступний на GitHub.

Тоді як Cluster Proportional Autoscaler масштабує кількість реплік робочого навантаження, Cluster Proportional Vertical Autoscaler коригує запити на ресурси для робочого навантаження (наприклад, Deployment або DaemonSet) залежно від кількості вузлів та/або ядер у кластері.

Автомасштабування на основі подій

Також існує можливість масштабування робочих навантажень на основі подій, наприклад, використовуючи Kubernetes Event Driven Autoscaler (KEDA).

KEDA — це проєкт CNCF зі статусом graduated, що дозволяє масштабувати ваші робочі навантаження залежно від кількості подій, які потрібно обробити, наприклад, кількості повідомлень у черзі. Існує широкий спектр адаптерів для різних джерел подій на вибір.

Автомасштабування на основі розкладу

Ще одна стратегія масштабування ваших робочих навантажень — планувати операції масштабування за розкладом, наприклад, щоб зменшити споживання ресурсів у непікові години.

Як і у випадку автомасштабування на основі подій, такої поведінки можна досягти за допомогою KEDA разом з його Cron scaler. Cron scaler дозволяє вам визначати розклади (і часові пояси) для збільшення чи зменшення ваших робочих навантажень.

Масштабування інфраструктури кластера

Якщо масштабування робочих навантажень недостатньо для ваших потреб, ви також можете масштабувати саму інфраструктуру вашого кластера.

Масштабування інфраструктури кластера зазвичай передбачає додавання або видалення вузлів. Дивіться Автомасштабування вузлів для отримання додаткової інформації.

Що далі

5 - Горизонтальне автомасштабування Podʼів

У Kubernetes HorizontalPodAutoscaler автоматично оновлює ресурс робочого навантаження (наприклад, Deployment або StatefulSet), щоб автоматично масштабувати потужності відповідно до попиту.

Горизонтальне масштабування означає, що реакція на збільшення навантаження полягає у розгортанні додаткових Podʼів. Це відрізняється від вертикального масштабування, що для Kubernetes означає призначення додаткових ресурсів (наприклад, памʼяті або CPU) для уже запущених Podʼів робочого навантаження.

Якщо навантаження зменшується, а кількість Podʼів перевищує налаштований мінімум, HorizontalPodAutoscaler дає вказівку ресурсу робочого навантаження (Deployment, StatefulSet або іншому схожому ресурсу) масштабуватися вниз.

Горизонтальне автомасштабування Podʼів не застосовується до обʼєктів, які не можна масштабувати (наприклад, DaemonSet).

HorizontalPodAutoscaler реалізований як ресурс API Kubernetes та контролер. Ресурс визначає поведінку контролера. Контролер горизонтального автомасштабування Podʼів, який працює в панелі управління Kubernetes, періодично коригує бажаний масштаб своєї цілі (наприклад, Deployment), щоб він відповідав спостережуваним метрикам, таким як середнє використання CPU, середнє використання памʼяті або будь-яка інша власна метрика, яку ви вказуєте.

Є покроковий приклад використання горизонтального автомасштабування Podʼів.

Як працює HorizontalPodAutoscaler?

graph BT

hpa[HorizontalPodAutoscaler] --> scale[Scale]

subgraph rc[Deployment]
    scale
end

scale -.-> pod1[Pod 1]
scale -.-> pod2[Pod 2]
scale -.-> pod3[Pod N]

classDef hpa fill:#D5A6BD,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D;
classDef rc fill:#F9CB9C,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D;
classDef scale fill:#B6D7A8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D;
classDef pod fill:#9FC5E8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D;
class hpa hpa;
class rc rc;
class scale scale;
class pod1,pod2,pod3 pod

Схема 1. HorizontalPodAutoscaler керує масштабуванням Deployment та його ReplicaSet

У Kubernetes горизонтальне автомасштабування Podʼів реалізовано як цикл керування, що працює періодично (це не безперервний процес). Інтервал встановлюється параметром --horizontal-pod-autoscaler-sync-period для kube-controller-manager (а стандартне значення — 15 секунд).

Один раз протягом кожного періоду менеджер контролерів запитує використання ресурсів відповідно до метрик, вказаних у визначенні кожного HorizontalPodAutoscaler. Менеджер контролерів знаходить цільовий ресурс, визначений за допомогою scaleTargetRef, потім вибирає Podʼи на основі міток .spec.selector цільового ресурсу та отримує метрики або з API метрик ресурсів (для метрик ресурсів на кожен Pod), або з API власних метрик (для всіх інших метрик).

  • Для метрик ресурсів на кожен Pod (наприклад, CPU) контролер отримує метрики з API метрик ресурсів для кожного Podʼа, на який спрямований HorizontalPodAutoscaler. Потім, якщо встановлено значення цільового використання, контролер обчислює значення використання як відсоток відповідного запиту на ресурс контейнерів у кожному Podʼі. Якщо встановлено сире цільове значення, безпосередньо використовуються сирі (необроблені) значення метрик. Потім контролер бере середнє значення використання або сире значення (залежно від типу вказаної цілі) для всіх цільових Podʼів і створює співвідношення, яке використовується для масштабування кількості бажаних реплік.

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

  • Для власних метрик на кожен Pod контролер працює аналогічно метрикам ресурсів на кожен Pod, за винятком того, що він працює із сирими значеннями, а не значеннями використання.

  • Для метрик обʼєктів та зовнішніх метрик отримується одна метрика, яка описує обʼєкт. Цю метрику порівнюють з цільовим значенням, щоб отримати співвідношення, як вище. У версії API autoscaling/v2 це значення можна за необхідності розділити на кількість Podʼів до порівняння.

Звичайне використання HorizontalPodAutoscaler — налаштувати його на отримання метрик з агрегованих API (metrics.k8s.io, custom.metrics.k8s.io або external.metrics.k8s.io). API metrics.k8s.io зазвичай надається надбудовою Metrics Server, яку потрібно запускати окремо. Для отримання додаткової інформації про метрики ресурсів див. Metrics Server.

Підтримка API метрик пояснює гарантії стабільності та статус підтримки цих різних API.

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

Подробиці алгоритму

У найпростішому вигляді контролер HorizontalPodAutoscaler працює зі співвідношенням між бажаним значенням метрики та поточним значенням метрики:

$$\begin{equation*} \text{бажаніРепліки} = ceil\left\lceil \text{поточніРепліки} \times \frac {\text{поточнеЗначенняМетрики}}{\text{бажанеЗначенняМетрики}} \right\rceil \end{equation*}$$

Наприклад, якщо поточне значення метрики — 200m, а бажане значення — 100m, кількість реплік буде подвоєна, оскільки \( { 200.0 \div 100.0 } = 2.0 \). Якщо поточне значення натомість — 50m, кількість реплік буде зменшена вдвічі, оскільки \( { 50.0 \div 100.0 } = 0.5 \). Панель управління пропускає будь-яку дію масштабування, якщо співвідношення достатньо близьке до 1,0 (в межах налаштовуваного допуску, стандартно 0,1).

Якщо вказано targetAverageValue або targetAverageUtilization, поточне значення метрики обчислюється шляхом визначення середнього значення вказаної метрики для всіх Podʼів у цілі масштабування HorizontalPodAutoscaler.

Перед перевіркою допуску та визначенням кінцевих значень панель управління також перевіряє, чи не бракує якихось метрик і скільки Podʼів перебувають у стані Ready. Для метрик ресурсів на кожен Pod ігноруються всі Podʼи із заданою позначкою часу видалення (обʼєкти з такою позначкою перебувають у процесі вимкнення/видалення), а всі Podʼи, що зазнали збою, відкидаються. Для зовнішніх метрик та метрик обʼєктів кількість реплік розраховується на основі кількості Podʼів у станах Running та Ready; Podʼи, що завершують роботу, але все ще перебувають у стані Ready, продовжують враховуватися в цій загальній кількості.

Якщо для конкретного Podʼа бракує метрик, його відкладають на потім; Podʼи з відсутніми метриками буде використано для коригування кінцевої величини масштабування.

Під час масштабування за CPU, якщо будь-який Pod ще не став готовим (він все ще ініціалізується або, можливо, несправний) або остання точка метрики для Podʼа була до того, як він став готовим, цей Pod також відкладають.

Через технічні обмеження контролер HorizontalPodAutoscaler не може точно визначити, коли Pod уперше став готовим, вирішуючи, чи відкласти певні метрики CPU. Натомість він вважає Pod «ще не готовим», якщо той не готовий і перейшов у стан готовності протягом короткого налаштовуваного проміжку часу від свого запуску. Це значення налаштовується за допомогою параметра командного рядка --horizontal-pod-autoscaler-initial-readiness-delay, і стандартно воно становить 30 секунд. Після того, як Pod став готовим, будь-який перехід у стан готовності вважається першим, якщо він відбувся протягом довшого налаштовуваного часу від запуску. Це значення налаштовується за допомогою параметра командного рядка --horizontal-pod-autoscaler-cpu-initialization-period, і його стандартне значення — 5 хвилин.

Базове співвідношення масштабу \( \text{поточнеЗначенняМетрики} \over \text{бажанеЗначенняМетрики} \) потім обчислюється за Podʼами, що залишилися, тобто не були відкладені або відкинуті вище.

Якщо були відсутні метрики, панель управління перераховує середнє значення більш консервативно, припускаючи, що ці Podʼи споживають 100% бажаного значення у випадку масштабування вниз і 0% у випадку масштабування вгору. Це зменшує величину можливого масштабування.

Крім того, якщо присутні будь-які ще не готові Podʼи, і робоче навантаження мало б масштабуватися вгору без врахування відсутніх метрик або ще не готових Podʼів, контролер консервативно припускає, що ще не готові Podʼи споживають 0% бажаної метрики, ще більше зменшуючи величину масштабування вгору.

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

Зверніть увагу, що початкове значення для середнього використання повертається через статус HorizontalPodAutoscaler, без врахування ще не готових Podʼів або відсутніх метрик, навіть коли використовується нове співвідношення використання.

Якщо в HorizontalPodAutoscaler вказано кілька метрик, цей розрахунок виконується для кожної метрики, а потім обирається найбільше з бажаних кількостей реплік. Якщо будь-яка з цих метрик не може бути переведена у бажану кількість реплік (наприклад, через помилку отримання метрик з API метрик) і запропоновано масштабування вниз за метриками, які можна отримати, масштабування пропускається. Це означає, що HPA все ще може масштабуватися вгору, якщо одна або кілька метрик дають значення desiredReplicas, більше, ніж поточне значення.

Нарешті, прямо перед тим, як HPA масштабує ціль, рекомендація масштабування записується. Контролер розглядає всі рекомендації в налаштованому вікні та обирає найвищу рекомендацію в межах цього вікна. Це значення можна налаштувати за допомогою параметра командного рядка --horizontal-pod-autoscaler-downscale-stabilization, стандартне значення якого — 5 хвилин. Це означає, що зменшення масштабу відбуватиметься поступово, згладжуючи вплив метрик, що швидко змінюються.

Готовність Podʼа та метрики автомасштабування

Контролер HorizontalPodAutoscaler (HPA) містить два параметри командного рядка, які впливають на те, як збираються метрики CPU з Podʼів під час запуску:

  1. --horizontal-pod-autoscaler-cpu-initialization-period (стандартно: 5 хвилин)

Цей параметр визначає часовий проміжок після запуску Podʼа, протягом якого використання CPU ігнорується, крім випадків, коли: - Pod перебуває у стані Ready та - Зразок метрики було взято повністю протягом періоду, коли він перебував у стані Ready.

Цей параметр командного рядка допомагає виключити оманливо високе споживання CPU Podʼами, що ініціалізуються (наприклад, Java-застосунками, що прогріваються), з рішень HPA щодо масштабування.

  1. --horizontal-pod-autoscaler-initial-readiness-delay (стандартно: 30 секунд)

Цей параметр командного рядка визначає короткий період затримки після запуску Podʼа, протягом якого контролер HPA розглядає Podʼи, що перебувають у стані Unready, як такі, що все ще ініціалізуються, навіть якщо вони раніше ненадовго перейшли у стан Ready.

Він призначений для того, щоб: - Уникнути включення Podʼів, які швидко коливаються між Ready та Unready під час запуску. - Забезпечити стабільність початкового сигналу готовності до того, як HPA вважатиме їх метрики дійсними.

Ви можете встановити ці параметри командного рядка тільки для всього кластера.

Ключова поведінка для готовності Podʼа

  • Якщо Pod перебуває в стані Ready і залишається в цьому стані, він може бути зарахований як такий, що надає метрики навіть протягом затримки.
  • Якщо Pod швидко перемикається між станом Ready та Unready, метрики ігноруються, поки він не стане стабільно Ready.

Поради стосовно готовності Podʼа

  • Налаштуйте startupProbe, який не проходить, поки високе використання CPU не мине, або
  • Переконайтеся, що ваш readinessProbe повідомляє про Ready тільки після того, як пік використання CPU спаде, використовуючи initialDelaySeconds.

А в ідеалі також встановіть --horizontal-pod-autoscaler-cpu-initialization-period, щоб покрити тривалість запуску.

Обʼєкт API

HorizontalPodAutoscaler є типом API в групі API Kubernetes autoscaling. Поточну стабільну версію можна знайти у версії API autoscaling/v2, яка включає підтримку масштабування за памʼяттю та власними метриками. Нові поля, введені в autoscaling/v2, зберігаються як анотації під час роботи з autoscaling/v1.

Під час створення обʼєкта API HorizontalPodAutoscaler переконайтеся, що вказана назва є дійсною назвою піддомену DNS. Більше деталей про обʼєкт API можна знайти на сторінці Обʼєкт HorizontalPodAutoscaler.

Стабільність масштабування робочого навантаження

Під час керування масштабом групи реплік за допомогою HorizontalPodAutoscaler можливі часті коливання кількості реплік через динамічний характер оцінюваних метрик. Це іноді називають thrashing або flapping (коливання). Це схоже на концепцію гістерезису в кібернетиці.

Автомасштабування під час поетапного оновлення

Kubernetes дозволяє виконувати поетапне оновлення для Deployment. У цьому випадку Deployment керує підлеглими ReplicaSets за вас. Коли ви налаштовуєте автомасштабування для Deployment, ви звʼязуєте HorizontalPodAutoscaler з одним Deployment. HorizontalPodAutoscaler керує полем replicas Deployment. Контролер Deployment відповідає за встановлення replicas підлеглих ReplicaSets так, щоб вони складали відповідну кількість під час розгортання, а також після його завершення.

Якщо ви виконуєте поетапне оновлення StatefulSet, у якого є автомасштабована кількість реплік, StatefulSet безпосередньо керує своїм набором Podʼів (немає проміжного ресурсу, аналогічного ReplicaSet).

Підтримка метрик ресурсів

Будь-яку ціль HPA можна масштабувати на основі використання ресурсів Podʼами в цілі масштабування. Під час визначення специфікації Podʼа слід вказувати запити на ресурси, такі як cpu та memory. Вони використовуються для визначення використання ресурсів, а контролер HPA використовує це для масштабування цілі вгору або вниз. Щоб використовувати масштабування на основі використання ресурсів, вкажіть джерело метрики так:

type: Resource
resource:
  name: cpu
  target:
    type: Utilization
    averageUtilization: 60

З цією метрикою контролер HPA буде підтримувати середнє використання ресурсів Podʼами в цілі масштабування на рівні 60%. Використання — це співвідношення між поточним використанням ресурсу та запитаними ресурсами Podʼа. Дивіться Алгоритм для отримання додаткової інформації про те, як обчислюється та усереднюється використання.

Примітка:

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

Метрики ресурсів контейнера

This is a stable feature in Kubernetes, and has been since the 1.30 release. You can no longer toggle this feature (the associated feature gate has been removed).

API HorizontalPodAutoscaler також підтримує джерело метрик контейнера, де HPA може відстежувати використання ресурсів окремих контейнерів у наборі Podʼів, щоб масштабувати цільовий ресурс. Це дозволяє налаштовувати пороги масштабування для контейнерів, які мають найбільше значення в конкретному Podʼі. Наприклад, якщо у вас є вебзастосунок і sidecar-контейнер, який надає логування, ви можете масштабувати на основі використання ресурсів вебзастосунка, ігноруючи sidecar-контейнер та його використання ресурсів.

Якщо ви оновите цільовий ресурс, щоб він мав нову специфікацію Podʼа з іншим набором контейнерів, вам слід оновити специфікацію HPA, якщо щойно доданий контейнер також має використовуватися для масштабування. Якщо вказаний контейнер у джерелі метрики відсутній або присутній лише в підмножині Podʼів, то ці Podʼи ігноруються, і рекомендація перераховується. Дивіться Алгоритм для отримання додаткової інформації про обчислення. Щоб використовувати ресурси контейнера для автомасштабування, визначте джерело метрики таким чином:

type: ContainerResource
containerResource:
  name: cpu
  container: application
  target:
    type: Utilization
    averageUtilization: 60

У наведеному вище прикладі контролер HPA масштабує ціль так, що середнє використання CPU у контейнері application в усіх Podʼах становить 60%.

Примітка:

Якщо ви зміните назву контейнера, який відстежує HorizontalPodAutoscaler, ви можете зробити цю зміну у певному порядку, щоб забезпечити доступність та ефективність масштабування під час застосування змін. Перед тим, як ви оновите ресурс, який визначає контейнер (наприклад, Deployment), вам слід оновити повʼязаний HPA, щоб він відстежував як нову, так і стару назву контейнера. Таким чином, HPA може розраховувати рекомендацію масштабування протягом усього процесу оновлення.

Після того, як ви розгорнули зміну назви контейнера в ресурсі робочого навантаження, приберіть зайве, видаливши стару назву контейнера зі специфікації HPA.

Масштабування на основі власних метрик

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.23

(версія API autoscaling/v2beta2 раніше надавала цю можливість як бета-можливість)

За умови використання версії API autoscaling/v2 ви можете налаштувати HorizontalPodAutoscaler на масштабування на основі власної метрики (яка не є вбудованою в Kubernetes або будь-який компонент Kubernetes). Потім контролер HorizontalPodAutoscaler запитує ці власні метрики з API Kubernetes.

Вимоги наведено в розділі Підтримка API метрик.

Масштабування на основі кількох метрик

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.23

(версія API autoscaling/v2beta2 раніше надавала цю можливість як бета-можливість)

За умови використання версії API autoscaling/v2 ви можете вказати кілька метрик, на основі яких масштабуватиме HorizontalPodAutoscaler. Потім контролер HorizontalPodAutoscaler оцінює кожну метрику і пропонує новий масштаб на основі цієї метрики. HorizontalPodAutoscaler бере максимальний масштаб, рекомендований для кожної метрики, і встановлює робоче навантаження на такий розмір (за умови, що це не більше загального максимуму, який ви налаштували).

Підтримка API метрик

Стандартно контролер HorizontalPodAutoscaler отримує метрики з низки API. Щоб він мав доступ до цих API, адміністратори кластера повинні переконатися, що:

  • Увімкнено шар агрегації API.

  • Відповідні API зареєстровано:

    • Для метрик ресурсів це metrics.k8s.io API, яке зазвичай надає metrics-server. Його можна запустити як надбудову кластера.

      Примітка:

      HorizontalPodAutoscaler наразі підтримує API `metrics.k8s.io/v1beta1` для метрик ресурсів. Він ще не підтримує `metrics.k8s.io/v1`.
      
    • Для власних метрик це custom.metrics.k8s.io API. Його надають API-сервери «адаптера», які постачають розробники рішень для метрик. Перевірте у своєму конвеєрі метрик, чи доступний адаптер метрик Kubernetes.

    • Для зовнішніх метрик це external.metrics.k8s.io API. Він може бути наданий адаптерами власних метрик, які наведено вище.

Для отримання додаткової інформації про ці різні шляхи метрик та їх відмінності дивіться відповідні проєктні пропозиції для HPA V2, custom.metrics.k8s.io та external.metrics.k8s.io.

Для прикладів використання дивіться посібник з використання власних метрик та посібник з використання зовнішніх метрик.

Налаштовувана поведінка масштабування

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.23

(версія API autoscaling/v2beta2 раніше надавала цю можливість як бета-можливість)

Якщо ви використовуєте API HorizontalPodAutoscaler v2, ви можете використовувати поле behavior (див. довідку API) для налаштування окремих поведінок масштабування вгору та вниз. Ви вказуєте ці поведінки, встановлюючи scaleUp та/або scaleDown у полі behavior.

Політики масштабування дозволяють контролювати швидкість зміни кількості реплік під час масштабування. Також можна використати два параметри для запобігання коливанням: ви можете вказати вікно стабілізації для згладжування кількості реплік та допуск для ігнорування незначних коливань метрик нижче вказаного порогового значення.

Політики масштабування

Одну або декілька політик масштабування можна вказати у розділі behavior специфікації. Коли вказано кілька політик, стандартно вибирається та політика, яка дозволяє найбільше змін. Наступний приклад показує цю поведінку під час зменшення масштабу:

behavior:
  scaleDown:
    policies:
    - type: Pods
      value: 4
      periodSeconds: 60
    - type: Percent
      value: 10
      periodSeconds: 60

periodSeconds вказує на проміжок часу в минулому, протягом якого політика має бути істинною. Максимальне значення, яке можна встановити для periodSeconds, — 1800 (пів години). Перша політика (Pods) дозволяє зменшити щонайбільше 4 репліки за одну хвилину. Друга політика (Percent) дозволяє зменшити щонайбільше 10% поточних реплік за одну хвилину.

Оскільки стандартно вибирається політика, яка дозволяє найбільше змін, друга політика буде використовуватися лише тоді, коли кількість реплік буде більше ніж 40. За 40 або менше реплік буде застосована перша політика. Наприклад, якщо є 80 реплік, і ціль потрібно зменшити до 10 реплік, то під час першого кроку буде скорочено 8 реплік. На наступній ітерації, коли кількість реплік становить 72, 10% від Podʼів — 7,2, але число заокруглюється вгору до 8. На кожному циклі контролера автомасштабування кількість Podʼів, які мають бути змінені, перераховується на основі поточної кількості реплік. Коли кількість реплік падає нижче 40, застосовується перша політика (Pods) і зменшується по 4 репліки за раз.

Вибір політики можна змінити, вказавши поле selectPolicy для напрямку масштабування. Встановлення значення Min вибере політику, яка дозволяє найменшу зміну кількості реплік. Встановлення значення Disabled повністю вимикає масштабування в цьому напрямку.

Вікно стабілізації

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

Наприклад, у наступному фрагменті коду вказано вікно стабілізації для scaleDown.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300

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

Це наближено відповідає ковзному максимуму і дає змогу уникнути ситуації, коли алгоритм масштабування часто видаляє Podʼи лише для того, щоб за мить знову створити еквівалентний Pod.

Допуск

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.37
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.37. It was first available in the v1.33 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate HPAConfigurableTolerance, Kubernetes ignores it but does not report any error.

Поле tolerance налаштовує порогове значення для мінливості метрики, не даючи автомасштабувальнику масштабувати через зміни, менші за це значення.

Цей допуск визначається як величина відхилення навколо бажаного значення метрики, нижче якої масштабування не відбуватиметься. Наприклад, розглянемо HorizontalPodAutoscaler, налаштований з цільовим споживанням памʼяті 100MiB та допуском масштабування вгору 5%:

behavior:
  scaleUp:
    tolerance: 0.05 # допуск 5% для масштабування вгору

За такої конфігурації алгоритм HPA розглядатиме масштабування вгору лише в тому випадку, якщо споживання памʼяті перевищує 105MiB (тобто на 5% вище цільового значення).

Якщо це поле не встановлено, HPA застосовуватиме стандартний допуск кластера — 10%. Це стандартне значення може бути оновлено як для масштабування вгору, так і вниз, використовуючи kube-controller-manager з аргументом командного рядка --horizontal-pod-autoscaler-tolerance. (Ви не можете використовувати API Kubernetes для налаштування цього стандартного значення.)

Стандартна поведінка

Для використання власного масштабування не всі поля повинні бути вказані. Можна вказати лише значення, які потрібно налаштувати. Ці власні значення обʼєднуються зі стандартними значеннями. Стандартні значення відповідають наявній поведінці в алгоритмі HPA.

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
  scaleUp:
    stabilizationWindowSeconds: 0
    policies:
    - type: Percent
      value: 100
      periodSeconds: 15
    - type: Pods
      value: 4
      periodSeconds: 15
    selectPolicy: Max

Для зменшення масштабу вікно стабілізації становить 300 секунд (або значення параметра командного рядка --horizontal-pod-autoscaler-downscale-stabilization, якщо воно вказане). Є лише одна політика для зменшення масштабу, яка дозволяє видалити 100% поточно запущених реплік, що означає, що ціль масштабування може бути зменшена до мінімально допустимих реплік. Для збільшення масштабу вікно стабілізації відсутнє. Коли метрики показують, що ціль повинна бути збільшена, ціль збільшується негайно. Є 2 політики, за якими кожні 15 секунд можна додати не більше 4 Podʼів або 100% поточно запущених реплік до тих пір, поки HPA не досягне стабільного стану.

Приклад: зміна вікна стабілізації для зменшення масштабу

Щоб вказати власне значення вікна стабілізації для зменшення масштабу тривалістю в 1 хвилину, до HPA слід додати таку поведінку:

behavior:
  scaleDown:
    stabilizationWindowSeconds: 60

Приклад: обмеження швидкості зменшення масштабу

Щоб обмежити швидкість, з якою HPA видаляє Podʼи, до 10% за хвилину, до HPA слід додати таку поведінку:

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60

Щоб переконатися, що за хвилину видаляється не більше 5 Podʼів, можна додати другу політику зменшення масштабу з фіксованим розміром 5 та встановити selectPolicy на значення Min. Встановлення selectPolicy на Min означає, що автомасштабувальник вибирає політику, яка впливає на найменшу кількість Podʼів:

behavior:
  scaleDown:
    policies:
    - type: Percent
      value: 10
      periodSeconds: 60
    - type: Pods
      value: 5
      periodSeconds: 60
    selectPolicy: Min

Приклад: вимкнення зменшення масштабу

Значення selectPolicy Disabled вимикає масштабування у вказаному напрямку. Щоб запобігти зменшенню масштабу, буде використана наступна політика:

behavior:
  scaleDown:
    selectPolicy: Disabled

Підтримка HorizontalPodAutoscaler в kubectl

HorizontalPodAutoscaler, як і кожний ресурс API, підтримується стандартним чином у kubectl. Ви можете створити новий автомасштабувальник за допомогою команди kubectl create. Ви можете переглянути список автомасштабувальників за допомогою kubectl get hpa або отримати детальний опис за допомогою kubectl describe hpa. Нарешті, ви можете видалити автомасштабувальник за допомогою kubectl delete hpa.

Крім того, є спеціальна команда kubectl autoscale для створення обʼєкта HorizontalPodAutoscaler. Наприклад, виконання kubectl autoscale rs foo --min=2 --max=5 --cpu=80% створить автомасштабувальник для ReplicaSet foo, з цільовим використанням CPU, встановленим на 80% і кількістю реплік від 2 до 5.

Масштабування до нуля та з нуля

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно увімкнено)

Для HorizontalPodAutoscaler, які масштабуються на основі власних (обʼєктних) або зовнішніх метрик, ви можете встановити spec.minReplicas у 0. Тоді робоче навантаження масштабується повністю до нуля реплік, коли немає навантаження, і масштабується назад, коли метрика вказує, що потрібна принаймні одна репліка. Це корисно для робочих навантажень, які простоюють протягом тривалого часу і дорогі в утриманні, наприклад, споживачі черги, якою користуються час від часу, або завдання, що потребують спеціального обладнання, як-от GPU.

Масштабування до нуля підтримується лише для обʼєктних та зовнішніх метрик. Воно недоступне для метрик ресурсів (таких як використання CPU або памʼяті), оскільки їх можна виміряти лише на запущених Podʼах. Встановлення minReplicas: 0 вимагає наявності принаймні однієї обʼєктної або зовнішньої метрики; інакше API-сервер відхиляє HorizontalPodAutoscaler.

Ця поведінка контролюється функціональною можливістю HPAScaleToZero, яка стандартно увімкнена. Функціональна можливість має бути увімкнена як на kube-apiserver (який дозволяє minReplicas: 0), так і на kube-controller-manager (який виконує масштабування).

Поки HPA утримує робоче навантаження на нулі реплік, він записує стан ScaledToZero зі значенням True у статус HorizontalPodAutoscaler. HPA використовує цей стан, щоб відрізнити робоче навантаження, яке він масштабував до нуля (і масштабує назад, коли метрика повертається), від того, яке було деактивовано вручну шляхом встановлення кількості його реплік у 0. Після того, як робоче навантаження масштабовано назад, стан встановлюється в False з причиною NotScaledToZero.

Неявна деактивація в режимі обслуговування

Ви можете неявно деактивувати HPA для цільового обʼєкта без необхідності змінювати саму конфігурацію HPA. Якщо бажана кількість реплік цільового обʼєкта встановлена на 0, а мінімальна кількість реплік HPA більше 0, HPA припиняє коригування цільового обʼєкта (і встановлює для себе стан ScalingActive у false), доки ви знову не активуєте його вручну, змінивши бажану кількість реплік цільового обʼєкта або мінімальну кількість реплік HPA.

Перехід Deployments та StatefulSets на горизонтальне автомасштабування

Під час увімкнення HPA рекомендується видалити значення spec.replicas з Deployment та/або StatefulSet в їхніх маніфестах. Якщо цього не зробити, щоразу, коли до цього обʼєкта застосовується зміна, наприклад, за допомогою kubectl apply -f deployment.yaml, Kubernetes отримуватиме вказівку масштабувати поточну кількість Podʼів до значення ключа spec.replicas. Це може бути небажаним і спричиняти проблеми, коли HPA активний, призводячи до коливань (thrashing або flapping).

Майте на увазі, що видалення spec.replicas може спричинити одноразове зниження кількості Podʼів, оскільки стандартне значення цього ключа — 1 (див. Репліки Deployment). Після оновлення всі Podʼи, крім одного, розпочнуть процедуру завершення. Після цього будь-яке подальше застосування Deployment працюватиме як звичайно і дотримуватиметься конфігурації поетапного оновлення, як і очікується. Ви можете уникнути цього зниження, обравши один із двох наступних методів залежно від того, як ви змінюєте свої Deployments:

  1. kubectl apply edit-last-applied deployment/<deployment_name>
  2. У редакторі видаліть spec.replicas. Після збереження та виходу з редактора kubectl застосовує оновлення. На цьому етапі не відбувається змін кількості Podʼів.
  3. Тепер ви можете видалити spec.replicas з маніфеста. Якщо ви використовуєте систему керування вихідним кодом, також зафіксуйте ваші зміни або виконайте будь-які інші кроки для перегляду вихідного коду, які відповідають вашому способу відстеження оновлень.
  4. Відтепер ви можете запускати kubectl apply -f deployment.yaml

Під час використання Server-Side Apply ви можете дотримуватися вказівок щодо передачі права власності, які охоплюють саме цей випадок використання.

Що далі

Якщо ви налаштовуєте автомасштабування у вашому кластері, вам також може бути корисно розглянути використання автомасштабування вузлів щоб забезпечити запуск потрібної кількості вузлів. Ви також можете дізнатися більше про вертикальне автомасштабування Podʼів.

Для отримання додаткової інформації про HorizontalPodAutoscaler:

6 - Вертикальне автомасштабування Podʼів

У Kubernetes VerticalPodAutoscaler автоматично оновлює ресурс керування робочим навантаженням (такий як Deployment або StatefulSet), щоб автоматично коригувати запити й обмеження ресурсів інфраструктури відповідно до фактичного використання.

Вертикальне масштабування означає, що відповіддю на збільшення попиту на ресурси є виділення більшої кількості ресурсів (наприклад, памʼяті або CPU) для Podʼів, які вже працюють для цього робочого навантаження. Це також відомо як rightsizing, або іноді autopilot. Це відрізняється від горизонтального масштабування, яке для Kubernetes означало б розгортання більшої кількості Podʼів для розподілу навантаження.

Якщо використання ресурсів зменшується, а запити на ресурси від Podʼа перевищують оптимальний рівень, VerticalPodAutoscaler дає вказівку ресурсу робочого навантаження (Deployment, StatefulSet або іншому подібному ресурсу) скоригувати запити на ресурси назад у бік зменшення, запобігаючи марнуванню ресурсів.

VerticalPodAutoscaler реалізовано як ресурс API Kubernetes і контролер. Ресурс визначає поведінку контролера. Контролер вертикального автомасштабування Podʼів, що працює в площині даних Kubernetes, періодично коригує запити на ресурси та обмеження для свого обʼєкта (наприклад, Deployment) на основі аналізу історичного використання ресурсів, кількості доступних ресурсів у кластері та подій у реальному часі, таких як ситуації нестачі памʼяті (OOM).

Обʼєкт API

VerticalPodAutoscaler визначається як Custom Resource Definition (CRD) в Kubernetes. На відміну від HorizontalPodAutoscaler, який є частиною основного API Kubernetes, VPA необхідно встановлювати окремо у вашому кластері.

Поточна стабільна версія API — autoscaling.k8s.io/v1. Більш детальну інформацію про встановлення VPA та API можна знайти в репозиторії VPA на GitHub.

Як працює VerticalPodAutoscaler?

graph BT
    metrics[Metrics Server]
    api[API Server]
    admission[VPA Admission Controller]

    vpa_cr[VerticalPodAutoscaler CRD]
    recommender[VPA recommender]
    updater[VPA updater]

    metrics --> recommender
    recommender -->|Зберігає
рекомендації| vpa_cr subgraph Робоче навантаження застосунку controller[Deployment / RC / StatefulSet] pod[Pod / Container] end vpa_cr -->|Перевірка на
наявність змін| updater updater -->|Виселяє або оновлює
Pod на місці| controller controller -->|Запит на
новий Pod| api api -->|Створення
нового Podʼа| admission admission -->|Отримує останні
рекомендації| vpa_cr admission -->|Інʼєкція нових
значень ресурсів| api api -->|Створює
Pod| controller controller -->|Новий Pod з
оптимальними
ресурсами| pod classDef vpa fill:#9FC5E8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef crd fill:#D5A6BD,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef metrics fill:#FFD966,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; classDef app fill:#B6D7A8,stroke:#1E1E1D,stroke-width:1px,color:#1E1E1D; class recommender,updater,admission vpa; class vpa_cr crd; class metrics metrics; class controller,pod app;

Схема 1. VerticalPodAutoscaler контролює запити на ресурси та обмеження Podʼів у Deployment.

Kubernetes реалізує вертикальне автомасштабування Podʼів за допомогою кількох взаємодіючих компонентів, які працюють з перервами (це не безперервний процес). VPA складається з трьох основних компонентів:

  • recommender, який аналізує використання ресурсів і надає рекомендації.
  • updater, який оновлює запити Podʼів на ресурси, виселяючи Podʼи або змінюючи їх на місці.
  • І вебхук VPA admission controller, який застосовує рекомендації щодо ресурсів до нових або створених заново Podʼів.

Один раз протягом кожного періоду Recommender запитує використання ресурсів для Podʼів, на які спрямовано кожне визначення VerticalPodAutoscaler. Recommender знаходить цільовий ресурс, визначений targetRef, потім вибирає Podʼи на основі міток .spec.selector цільового ресурсу та отримує метрики з API метрик ресурсів для аналізу фактичного споживання CPU та памʼяті.

Recommender аналізує поточні та історичні дані про використання ресурсів (CPU та памʼять) для кожного Podʼа, на який націлений VerticalPodAutoscaler. Він перевіряє:

  • Історичні моделі споживання з часом для виявлення тенденцій
  • Пікове використання та відхилення для забезпечення достатнього запасу
  • Події вичерпання памʼяті (OOM) та інші інциденти, повʼязані з ресурсами

На основі цього аналізу Recommender обчислює три типи рекомендацій:

  • Рекомендація щодо цільового значення (оптимальні ресурси для типового використання)
  • Нижня межа (мінімально необхідні ресурси)
  • Верхня межа (максимально доцільні ресурси).

Ці рекомендації зберігаються в полі .status.recommendation ресурсу VerticalPodAutoscaler.

Компонент updater відстежує ресурси VerticalPodAutoscaler і порівнює поточні запити на ресурси Podʼів з рекомендаціями. Коли різниця перевищує налаштовані порогові значення і політика оновлення дозволяє це, updater може:

  • Виселити Podʼи, ініціюючи їх повторне створення з новими запитами на ресурси (традиційний підхід)
  • Оновити ресурси Podʼа на місці без виселення, якщо кластер підтримує оновлення ресурсів Podʼів на місці

Вибраний метод залежить від налаштованого режиму оновлення, можливостей кластера та типу необхідних змін ресурсів. Оновлення на місці, якщо вони доступні, дозволяють уникнути порушення роботи Podʼа, але можуть мати обмеження щодо ресурсів, які можна модифікувати. Updater дотримується PodDisruptionBudgets, щоб мінімізувати вплив на роботу сервісу.

Контролер допуску працює як змінювальний вебхук, який перехоплює запити на створення Podʼів. Він перевіряє, чи є Pod ціллю VerticalPodAutoscaler, і, якщо так, застосовує рекомендовані запити на ресурси та обмеження перед створенням Podʼа. Конкретніше, контролер допуску використовує рекомендацію Target у розділі .status.recommendation ресурсу VerticalPodAutoscaler як нові запити на ресурси. Контролер допуску гарантує, що нові Podʼи запускаються з належними виділеними ресурсами, незалежно від того, чи вони створені під час початкового розгортання, після виселення компонентом updater або внаслідок операцій масштабування.

VerticalPodAutoscaler вимагає, щоб у кластері було встановлено джерело метрик, таке як надбудова Metrics Server від Kubernetes. Компоненти VPA отримують метрики з API metrics.k8s.io. Metrics Server потрібно запускати окремо, оскільки в більшості кластерів він стандартно не розгортається. Докладнішу інформацію про метрики ресурсів дивіться у розділі Metrics Server.

Режими оновлення

VerticalPodAutoscaler підтримує різні режими оновлення, які контролюють, як і коли рекомендації щодо ресурсів застосовуються до ваших Podʼів. Ви налаштовуєте режим оновлення за допомогою поля updateMode у специфікації VPA в розділі updatePolicy:

---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Recreate"  # Off, Initial, Recreate, InPlaceOrRecreate, InPlace

Off

У режимі оновлення Off recommender VPA все одно аналізує використання ресурсів і генерує рекомендації, але ці рекомендації не застосовуються до Podʼів автоматично. Рекомендації зберігаються лише в полі .status обʼєкта VPA.

Ви можете використовувати такий інструмент, як kubectl, щоб переглянути .status і рекомендації, що містяться в ньому.

Initial

У режимі Initial VPA встановлює запити на ресурси тільки під час першого створення Podʼа. Він не оновлює ресурси для вже запущених Podʼів, навіть якщо рекомендації змінюються з часом. Рекомендації застосовуються тільки під час створення Podʼа.

Recreate

У режимі Recreate VPA активно керує ресурсами Podʼів, виселяючи Podʼи, коли їхні поточні запити на ресурси значно відрізняються від рекомендацій. Коли Pod виселяється, контролер робочого навантаження (який керує Deployment, StatefulSet тощо) створює Pod-замінник, а контролер допуску VPA застосовує оновлені запити на ресурси до нового Podʼа.

InPlaceOrRecreate

У режимі InPlaceOrRecreate VPA намагається оновити запити та обмеження ресурсів Podʼа без перезапуску Podʼа, якщо це можливо. Однак, якщо оновлення на місці не можуть бути виконані для певної зміни ресурсу, VPA повертається до виселення Podʼа (аналогічно режиму Recreate) і дозволяє контролеру робочого навантаження створити Pod-замінник з оновленими ресурсами.

У цьому режимі updater застосовує рекомендації на місці за допомогою можливості Зміна розміру ресурсів контейнера на місці.

InPlace

Цей режим доступний як альфа-можливість у VPA 1.7.0 і вимагає Kubernetes 1.33 або новішої версії з увімкненою функціональною можливістю кластера InPlacePodVerticalScaling, а також увімкненою функціональною можливістю InPlace для updater VPA та контролера допуску. Він використовує можливість зміни розміру Podʼа на місці, щоб застосовувати оновлення без порушення роботи Podʼа.

У режимі InPlace VPA намагається оновити запити та обмеження ресурсів Podʼа без перезапуску або виселення Podʼа. На відміну від InPlaceOrRecreate, цей режим ніколи не повертається до виселення. Якщо оновлення на місці не може бути застосоване (наприклад, через недостатню місткість вузла), VPA відкладає оновлення та повторює спробу в наступному циклі узгодження.

Щоб використовувати режим InPlace, увімкніть функціональну можливість InPlace як для updater VPA, так і для контролера допуску:

--feature-gates=InPlace=true

Потім встановіть updateMode в "InPlace" у вашій специфікації VPA:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "InPlace"

Ключова відмінність від InPlaceOrRecreate: Коли зміна розміру відкладається, виконується або є неможливою, режим InPlace завжди чекає та повторює спробу — він ніколи не виселяє Pod, незалежно від того, як довго оновлення очікує.

Auto (застаріло)

Примітка:

Режим оновлення Auto визнано застарілим починаючи з версії VPA 1.4.0. Використовуйте Recreate для оновлень на основі виселення або InPlaceOrRecreate для оновлень на місці з резервним варіантом виселення.

Режим Auto наразі є синонімом режиму Recreate і працює ідентично. Він був введений для забезпечення можливості майбутнього розширення стратегій автоматичного оновлення.

Політики ресурсів

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

Політики ресурсів визначаються у полі resourcePolicy специфікації VPA:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Recreate"
  resourcePolicy:
    containerPolicies:
    - containerName: "application"
      minAllowed:
        cpu: 100m
        memory: 128Mi
      maxAllowed:
        cpu: 2
        memory: 2Gi
      controlledResources:
      - cpu
      - memory
      controlledValues: RequestsAndLimits

minAllowed та maxAllowed

Ці поля встановлюють межі для рекомендацій VPA. VPA ніколи не рекомендуватиме ресурси нижче minAllowed або вище maxAllowed, навіть якщо фактичні дані про використання вказують на інші значення.

controlledResources

Поле controlledResources визначає, якими типами ресурсів VPA повинен керувати для контейнера в Podʼі. Якщо не вказано, VPA стандартно керує як CPU, так і памʼяттю. Ви можете обмежити VPA, щоб він керував лише певними ресурсами. Допустимі назви ресурсів: cpu та memory.

controlledValues

Поле controlledValues визначає, чи контролює VPA запити на ресурси, обмеження або і те, і інше:

RequestsAndLimits
VPA встановлює як запити, так і обмеження. Обмеження масштабується пропорційно до запиту на основі співвідношення запиту до обмеження, визначеного в специфікації Podʼа. Це стандартний режим.
RequestsOnly
VPA встановлює лише запити, залишаючи обмеження без змін. Обмеження враховуються і можуть спричиняти тротлінг або завершення процесів за нестачі памʼяті (OOM kills), якщо використання їх перевищує.

Дивіться запити та обмеження, щоб дізнатися більше про ці два поняття.

Ресурси LimitRange

Компоненти VPA, контролер допуску та updater, додатково обробляють рекомендації, щоб вони відповідали обмеженням, визначеним у LimitRanges. Ресурси LimitRange з type Pod та Container перевіряються в кластері Kubernetes.

Наприклад, якщо поле max у ресурсі Container LimitRange перевищено, обидва компоненти VPA знижують обмеження до значення, визначеного в полі max, і запит пропорційно зменшується, щоб зберегти співвідношення запиту до обмеження в специфікації Podʼа.

Що далі

Якщо ви налаштовуєте автомасштабування у своєму кластері, ви також можете розглянути можливість використання автомасштабування вузлів, щоб переконатися, що ви використовуєте потрібну кількість вузлів. Ви також можете дізнатися більше про горизонтальне автомасштабування Podʼів.

7 - Workload API

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Ресурс API Workload визначає вимоги до планування та структуру застосунку з кількох Podʼів. У той час як контролери робочого навантаження, такі як Job, керують станом виконання застосунку, Workload визначає, як слід планувати групи Pods. Контролер Job є єдиним вбудованим контролером, який створює обʼєкти PodGroup з PodGroupTemplates ресурсу Workload під час виконання.

Що таке Workload?

Ресурс API Workload є частиною групи API scheduling.k8s.io/v1beta1, і ваш кластер повинен мати цю групу API увімкненою, а також функціональну можливість GenericWorkload, перш ніж ви зможете скористатися цим API.

Workload є статичним, довгоживучим шаблоном політики. Він визначає, які політики планування слід застосовувати до груп Podʼів, але самостійно не відстежує стан виконання. Стан виконання планування підтримується обʼєктами PodGroup, які контролери створюють з PodGroupTemplates ресурсу Workload.

Структура API

Workload складається з двох полів: списку PodGroupTemplates та необовʼязкового посилання на контролер. Вся специфікація Workload є незмінною після створення: ви не можете змінювати наявні шаблони, додавати нові шаблони або видаляти шаблони з podGroupTemplates.

PodGroupTemplates

Список spec.podGroupTemplates визначає окремі компоненти вашого робочого навантаження. Наприклад, завдання машинного навчання може мати шаблон driver та шаблон worker.

Кожен елемент у podGroupTemplates повинен мати:

  1. Унікальне поле name, яке буде використовуватися для посилання на шаблон у spec.podGroupTemplateRef обʼєкта PodGroup.
  2. Політику планування (basic або gang).

Кожен елемент також може мати поля пріоритету та режиму порушення.

Примітка:

У v1.36 поля пріоритету та режиму порушення вмикалися функціональною можливістю WorkloadAwarePreemption. Цю функціональну можливість було обʼєднано з GenericWorkload у v1.37.

Максимальна кількість PodGroupTemplates в одному Workload становить 8.

apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
metadata:
  name: training-job-workload
  namespace: some-ns
spec:
  controllerRef:
    apiGroup: batch
    kind: Job
    name: training-job
  podGroupTemplates:
  - name: workers
    schedulingPolicy:
      gang:
        # gang придатна для планування лише тоді, коли одночасно можуть працювати 4 Podʼи
        minCount: 4
    priorityClassName: high-priority
    disruptionMode:
      all: {}

Коли контролер робочого навантаження створює PodGroup з одного з цих шаблонів, він копіює schedulingPolicy у власну специфікацію PodGroup. Зміни в Workload впливають лише на новостворені PodGroups, а не на наявні.

Посилання на обʼєкт керування робочим навантаженням

Поле controllerRef звʼязує Workload з конкретним обʼєктом вищого рівня, що визначає застосунок, наприклад Job або власний CRD. Це корисно для спостереження та інструментів. Ці дані не використовуються для планування або керування Workload.

CompositePodGroupTemplates

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли увімкнено функціональну можливість CompositePodGroup та групу API scheduling.k8s.io/v1alpha3, ви можете використовувати CompositePodGroupTemplates для визначення багаторівневих ієрархічних вимог до планування у Workload. Ці вимоги можуть включати забезпечення вкладених топологічних обмежень на різних рівнях інфраструктури кластера (багаторівневе топологічно орієнтоване планування), планування «все або нічого» для дочірніх груп (багаторівневе групове планування) або політики порушення на рівні групи.

CompositePodGroupTemplates можна визначити за допомогою поля spec.compositePodGroupTemplates в API Workload. Під час виконання контролери робочого навантаження створюють обʼєкти CompositePodGroup та PodGroup з цих шаблонів для підтримки стану планування ієрархії під час виконання. У той час як обʼєкти PodGroup керують групами Podʼів на кінцевих рівнях, обʼєкти CompositePodGroup представляють проміжні групи, які забезпечують виконання політик планування для дочірніх груп.

Примітка:

У специфікації Workload поля spec.compositePodGroupTemplates та spec.podGroupTemplates утворюють обʼєднання: Workload повинен визначати або spec.podGroupTemplates (для пласких робочих навантажень), або spec.compositePodGroupTemplates (для ієрархічних робочих навантажень), але не може визначати обидва.

Структура та обмеження

Поле spec.compositePodGroupTemplates визначає проміжні шаблони в дереві ієрархії шаблонів груп. Кожен елемент представляє шаблон для CompositePodGroup і може містити:

  • Дочірні шаблони: вкладені CompositePodGroupTemplates (для проміжних груп) або PodGroupTemplates (для кінцевих груп, що містять Podʼи).
  • Політику планування: визначає, як плануються дочірні групи в межах цієї складеної групи:
    • basic: дочірні групи приймаються та плануються незалежно.
    • gang: забезпечує багаторівневе планування «все або нічого» для дочірніх груп. Вимагає minGroupCount, який визначає мінімальну кількість дочірніх груп, які мають бути придатними для планування одночасно, щоб складена група була здійсненною.
  • Обмеження планування: необовʼязкові топологічні обмеження для багаторівневого топологічно орієнтованого планування.
  • Пріоритет, політика витіснення та режим порушення: необовʼязкові priorityClassName, disruptionMode (Single або All) та preemptionPolicy для витіснення з урахуванням робочого навантаження.

Щоб забезпечити стабільність кластера та ефективність панелі управління, ієрархія шаблонів груп застосовує такі обмеження:

  • Максимальна глибина вкладеності: ієрархія шаблонів груп підтримує максимальну глибину 4 рівні.
  • Обмеження списку: кожен список compositePodGroupTemplates та podGroupTemplates суворо обмежений максимум 8 елементами.

Примітка:

Наразі ви не можете додавати нові або видаляти наявні CompositePodGroupTemplates. Ви можете лише змінювати значення minCount у політиці групового планування, визначеній у кінцевих PodGroupTemplates.

Приклад

Наступний приклад визначає ієрархічний Workload з шаблоном CompositePodGroup, який забезпечує групове планування для двох дочірніх шаблонів PodGroup (minGroupCount: 2), кожен з яких визначає власну політику групового планування:

apiVersion: scheduling.k8s.io/v1alpha3
kind: Workload
metadata:
  name: gang-of-gangs-workload
  namespace: default
spec:
  compositePodGroupTemplates:
  - name: root
    schedulingPolicy:
      gang:
        # Вимагає, щоб обидва дочірні PodGroups були придатними для планування разом
        minGroupCount: 2
    podGroupTemplates:
    - name: workers-a
      schedulingPolicy:
        gang:
          # Вимагає, щоб 4 Podʼи в цій групі були придатними для планування
          minCount: 4
    - name: workers-b
      schedulingPolicy:
        gang:
          # Вимагає, щоб 4 Podʼи в цій групі були придатними для планування
          minCount: 4

Групове планування з Job

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.36; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the WorkloadWithJob feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли функціональна можливість WorkloadWithJob увімкнена, контролер Job компілює конфігурацію .spec.scheduling обʼєкта Job в обʼєкти Workload та PodGroup перед тим, як створити будь-які Podʼи. Ви вмикаєте групове планування, встановивши .spec.scheduling.schedulingPolicy.gang у Job; пропущений gang.minCount стандартно дорівнює .spec.parallelism обʼєкта Job, тому всі Podʼи мають бути придатними для планування одночасно, перш ніж будь-який з них буде привʼязаний до вузлів.

Коли .spec.scheduling пропущено, Job стандартно використовує політику basic, яка зберігає звичайне планування Pod за Podʼом. У будь-якому випадку контролер Job створює Workload та PodGroup за вас, тому вам не потрібно створювати їх самостійно. Інші контролери робочих навантажень (наприклад, JobSet) можуть самостійно керувати своїми обʼєктами Workload та PodGroup.

Повний набір полів планування та приклади дивіться у розділі Інтеграція з Workload API.

Що далі

7.1 - Політики планування PodGroup

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Кожен PodGroup повинен оголосити політику планування у своєму полі spec.schedulingPolicy. Ця політика визначає, як планувальник обробляє набір Podʼів у групі.

Типи політик

Поле schedulingPolicy підтримує два типи політик: basic та gang. Ви повинні вказати рівно одну.

Політика basic

Політика basic вказує планувальнику оцінювати всі Podʼи за принципом best-effort. На відміну від політики gang, PodGroup, що використовує політику basic, вважається здійсненним незалежно від того, скільки його Podʼів наразі придатні для планування.

Основною причиною використання політики basic є організація Podʼів у групу для кращої спостережуваності та керування, водночас вони все одно оцінюються разом у рамках єдиного атомарного циклу планування PodGroup.

Ця політика підходить для груп, які не потребують одночасного запуску, але логічно належать до одного цілого, або для створення можливості для обмежень на рівні групи, які не передбачають розміщення за принципом «все або нічого».

schedulingPolicy:
  basic: {}

Політика gang

Політика gang забезпечує планування «все або нічого». Це необхідно для тісно повʼязаних робочих навантажень, де частковий запуск призводить до взаємних блокувань або марнування ресурсів.

Цю політику можна використовувати для Jobs або будь-якого іншого пакетного процесу, де всі робочі процеси повинні працювати одночасно, щоб просуватися в роботі.

Політика gang вимагає поля minCount, яке визначає мінімальну кількість Podʼів, які мають бути придатними для планування одночасно, щоб група була здійсненною:

schedulingPolicy:
  gang:
    # Кількість Podʼів, які повинні бути заплановані одночасно
    # для того, щоб група була прийнята.
    minCount: 4

Встановлення політик через PodGroupTemplates

Під час використання Workload API ви визначаєте політики планування всередині PodGroupTemplates. Контролер робочого навантаження копіює політику з шаблону в кожен створений PodGroup, роблячи PodGroup самодостатнім. Зміни в шаблонах Workload впливають лише на новостворені PodGroups, а не на наявні.

Для автономних PodGroups (створених без Workload) ви встановлюєте spec.schedulingPolicy безпосередньо на самому PodGroup.

Політики в CompositePodGroups

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли увімкнено функціональну можливість CompositePodGroup та групу API scheduling.k8s.io/v1alpha3, CompositePodGroupTemplates у Workload та обʼєкти CompositePodGroup також оголошують політику планування.

У той час як політика планування в PodGroup керує колекцією окремих Podʼів, політика планування CompositePodGroup керує його безпосередніми дочірніми групами (які можуть бути як обʼєктами CompositePodGroup, так і PodGroup).

Типи політик для CompositePodGroups

Подібно до PodGroups, поле spec.schedulingPolicy обʼєкта CompositePodGroup підтримує два типи:

  • basic: дочірні групи в межах CompositePodGroup оцінюються та приймаються незалежно.
  • gang: забезпечує багаторівневе планування «все або нічого» для дочірніх груп. CompositePodGroup придатний для планування, лише якщо принаймні minGroupCount дочірніх груп можуть бути заплановані одночасно.
schedulingPolicy:
  gang:
    # Мінімальна кількість дочірніх груп, які повинні бути заплановані
    # одночасно, щоб ця складова група була прийнята.
    minGroupCount: 2

Встановлення складених політик через шаблони

Під час використання Workload API політики планування для CompositePodGroups визначаються всередині CompositePodGroupTemplates. Контролери робочого навантаження копіюють schedulingPolicy, вказану в шаблонах, у кожен CompositePodGroup, створений під час виконання. На відміну від кінцевих PodGroupTemplates, де minCount можна оновлювати, minGroupCount у CompositePodGroupTemplate є незмінним.

Що далі

7.2 - Порушення та пріоритет групи Podʼів

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

PodGroup може оголосити режим порушення. Цей режим визначає, як планувальник може порушувати роботу запущеного PodGroup, наприклад, щоб розмістити PodGroup з вищим пріоритетом. PodGroup також має пріоритет, який перевизначає пріоритет окремих Podʼів з групи для подій витіснення з урахуванням робочого навантаження.

Типи режимів порушення

Примітка:

У v1.36 поля priority або disruptionMode обʼєкта PodGroup враховуються лише під час витіснення з урахуванням робочого навантаження. Під час фази планування Podʼів планувальник не враховує поля priority або disruptionMode обʼєкта PodGroup. Це обмеження більше не застосовується у v1.37.

API підтримує два режими порушення: Single та All. Стандартний режим — Single.

Single

Режим Single вказує планувальнику розглядати всі Podʼи в групі як окремі сутності, дозволяючи незалежно порушувати роботу окремого Podʼа з PodGroup.

All

Режим All передбачає семантику «все або нічого» для порушення. Він вказує планувальнику, що роботу всіх Podʼів з PodGroup потрібно порушувати разом.

CompositePodGroup

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

CompositePodGroup також може оголосити disruptionMode у своїй специфікації, який визначає, як планувальник порушує роботу дочірніх груп у межах складеної групи під час подій витіснення.

API підтримує два режими порушення для CompositePodGroups:

  • Single: дозволяє незалежно порушувати роботу окремих дочірніх груп у межах CompositePodGroup під час витіснення.
  • All: забезпечує семантику порушення «все або нічого» для всієї ієрархії CompositePodGroup. Якщо будь-який Pod, що міститься в ієрархії нижче цього CompositePodGroup, має бути витіснений, усі Podʼи з усієї ієрархії мають бути витіснені.

Якщо не вказано, стандартний режим — Single.

Примітка:

У v1.37 група може встановити свій режим порушення в All і мати дочірні групи з режимом Single. У такому випадку режим All верхнього рівня перевизначає режими Single нащадків.

Така конфігурація не рекомендується через неоднозначну семантику.

Пріоритет групи Podʼів

PodGroup використовує ту ж концепцію PriorityClass, що й окремі Podʼи. Після створення одного або кількох PriorityClasses ви можете створити PodGroup, який вказує одну з цих назв PriorityClass у своїй специфікації. Контролер допуску пріоритету використовує поле priorityClassName і заповнює ціле значення пріоритету. Якщо клас пріоритету не знайдено, PodGroup відхиляється. Коли priorityClassName не встановлено для PodGroup, Kubernetes шукає стандартне значення (PriorityClass з globalDefault, встановленим у true). Якщо немає PriorityClass з globalDefault, встановленим у true, PodGroup без priorityClassName має пріоритет нуль.

Пріоритет PodGroup є авторитетним пріоритетом для всіх Podʼів у групі під час подій витіснення з урахуванням робочого навантаження. Це значення також використовується для впорядкування PodGroup у черзі планування. Якщо пріоритети окремих Podʼів, що формують цей PodGroup, відрізняються від пріоритету PodGroup, PodGroup не буде заплановано з помилкою all pods in a single pod group should have the same priority as the pod group (усі Podʼи в одній групі Podʼів повинні мати такий самий пріоритет, як і сама група Podʼів).

Коли увімкнено функціональну можливість PodGroupPreemptionPolicy, PodGroup також має поле preemptionPolicy. Це поле також береться з PriorityClass. Воно є авторитетним полем для всіх Podʼів у групі та визначає, чи може PodGroup виконувати витіснення Podʼів і груп Podʼів з нижчим пріоритетом, щоб звільнити місце для себе. Коли функціональну можливість увімкнено, усі Podʼи в PodGroup повинні мати той самий preemptionPolicy, що й PodGroup. Інакше PodGroup не буде заплановано з помилкою all pods in a single pod group should have the same preemption policy as the pod group's preemption policy (усі Podʼи в одній групі Podʼів повинні мати ту саму політику витіснення, що й політика витіснення цієї групи Podʼів). Коли PodGroup має preemptionPolicy: Never, він не виконуватиме витіснення з урахуванням робочого навантаження. Якщо функціональну можливість вимкнено, усі Podʼи, що формують PodGroup, повинні мати однаковий preemptionPolicy. Інакше PodGroup не буде заплановано з помилкою all pods in a single pod group should have the same preemption policy (усі Podʼи в одній групі Podʼів повинні мати однакову політику витіснення).

Наступний YAML є прикладом конфігурації PodGroup, який використовує PriorityClass high-priority, що відповідає цілому значенню пріоритету 1000000. Контролер допуску пріоритету перевіряє специфікацію та визначає пріоритет PodGroup як 1000000.

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  namespace: ns-1
  name: job-1
spec:
  priorityClassName: high-priority

Пріоритет CompositePodGroup

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

API CompositePodGroup також має поля priorityClassName та priority, і їх визначення виконується так само, як і для PodGroups, через контролер допуску пріоритету.

Пріоритет кореневого CompositePodGroup діє як авторитетний пріоритет для всіх дочірніх груп і Podʼів у межах його ієрархії під час подій витіснення з урахуванням робочого навантаження. Усі Podʼи в межах однієї ієрархії груп повинні мати точно такий самий пріоритет, який має дорівнювати пріоритету кореневого CompositePodGroup.

Значення пріоритету також використовується для впорядкування кореневих CompositePodGroups в активній черзі планування.

Примітка:

У v1.37 планувальник не перевіряє, чи мають некореневі групи значення пріоритету, що дорівнює пріоритету кореневого CompositePodGroup.

PreemptionPolicy у CompositePodGroup

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the PodGroupPreemptionPolicy feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

API CompositePodGroup також має поле preemptionPolicy, і його визначення виконується точно так само, як і для API PodGroup.

Значення preemptionPolicy кореневого CompositePodGroup визначає, чи може бути викликане витіснення з урахуванням робочого навантаження для розміщення його Podʼів під час планування, якщо це необхідно:

  • політика PreemptLowerPriority дозволяє витісняти жертв з нижчим пріоритетом;
  • політика Never вимикає витіснення з урахуванням робочого навантаження для цього кореневого CompositePodGroup.

Усі Podʼи в межах однієї ієрархії груп повинні мати точно таку саму політику витіснення, яка має дорівнювати політиці витіснення кореневого CompositePodGroup.

Якщо функціональну можливість вимкнено, кореневому CompositePodGroup буде дозволено виконувати витіснення, якщо жоден з Podʼів, що належить до ієрархії групи, не має preemptionPolicy зі значенням Never.

Примітка:

У v1.37, коли функціональну можливість увімкнено, планувальник не перевіряє, чи мають некореневі групи політику витіснення, що дорівнює політиці витіснення кореневого CompositePodGroup.

Що далі

7.3 - Топологічно орієнтоване планування робочих навантажень

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.36; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the TopologyAwareWorkloadScheduling feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Топологічно орієнтоване планування робочих навантажень (Topology-Aware Scheduling, TAS) є можливістю Workload API, яка оптимізує розміщення Podʼів у межах кластера.

TAS забезпечує, щоб усі Podʼи в межах PodGroup були розміщені в одному топологічному домені, наприклад, в одній серверній стійці або в одній зоні. Це мінімізує затримки між Podʼами та запобігає фрагментації робочого навантаження по інфраструктурі кластера.

Топологічно орієнтоване планування з політикою gang

Під час застосування до PodGroups з політикою планування gang TAS симулює потенційне призначення (placement, розміщення) всієї групи Podʼів одразу. Він гарантує, що принаймні вказана кількість minCount Podʼів може розміститися разом в одному топологічному домені, перш ніж виділяти ресурси. Якщо жодного здійсненного розміщення не знайдено, весь PodGroup стає непридатним для планування.

Цей підхід рекомендується для робочих навантажень, таких як розподілене навчання AI та ML, які суворо потребують близькості для мінімізації затримок між Podʼами.

Якщо нові Podʼи додаються до PodGroup, у якому деякі Podʼи вже заплановані (наприклад, якщо Podʼи створюються повторно), планувальник змусить усі нові Podʼи розміститися саме в тому топологічному домені, де наразі перебувають наявні Podʼи. Якщо в цьому конкретному домені недостатньо ресурсів для нових Podʼів, вони залишаться в стані очікування — навіть якщо це означає, що на даний момент буде заплановано менше ніж minCount Podʼів.

Примітка:

Станом на v1.36 топологічно орієнтоване планування не ініціює витіснення робочих навантажень або Podʼів. Якщо жодного здійсненного розміщення не вдається знайти без витіснення, PodGroup стає непридатним для планування.

Топологічно орієнтоване планування з політикою basic

Використання TAS з політикою планування basic може призводити до непослідовної поведінки. Планувальник може спостерігати лише підмножину Podʼів під час входу в цикл планування PodGroup — тому здійсненність розміщення оцінюється лише для спостережуваних Podʼів, а не для всього PodGroup. Щоб частково помʼякшити це обмеження, можна використовувати шлюзи планування, щоб затримати планування PodGroup до тих пір, поки всі Podʼи в PodGroup не будуть у черзі планування.

Якщо жодного здійсненного розміщення для всього PodGroup не знайдено, може бути запланована лише підмножина Podʼів, і вони гарантовано відповідатимуть обмеженням планування.

Якщо нові Podʼи додаються до PodGroup, у якому деякі Podʼи вже заплановані, планувальник діятиме так само, як у випадку політики gang — змушуючи нові Podʼи розміститися в тому ж домені, якщо є достатньо ресурсів (у протилежному випадку нові Podʼи залишаться в стані очікування).

Налаштування API: обмеження планування

Кожен PodGroup (або PodGroupTemplate) може за бажанням оголосити поле schedulingConstraints, яке інтерпретується алгоритмом планування PodGroup на основі розміщення. Якщо обмеження визначені в PodGroupTemplate, вони будуть скопійовані до PodGroups, що на нього посилаються.

Станом на Kubernetes v1.36 API підтримує топологічні обмеження.

Примітка:

Станом на Kubernetes v1.36 ви можете вказати лише одне топологічне обмеження для кожного PodGroup.

Топологічне обмеження

Щоб визначити топологічне обмеження для PodGroup, потрібно встановити key, який відповідає мітці вузла Kubernetes, що представляє цільовий топологічний домен (наприклад, стійку або зону). Планувальник суворо забезпечує, щоб усі Podʼи в межах PodGroup були розміщені на вузлах, які мають точно однакове значення для цієї мітки.

Ось приклад PodGroup, налаштованого з топологічним обмеженням:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: example-podgroup
spec:
  schedulingPolicy:
    gang:
      minCount: 4
  schedulingConstraints:
    topology:
      - key: topology.example.com/rack

Багаторівневе топологічно орієнтоване планування

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Складні робочі навантаження можуть вимагати спільного розміщення їхніх Podʼів на різних рівнях інфраструктури кластера. Наприклад, усе робоче навантаження може потребувати запуску в межах однієї зони доступності, тоді як різні частини цього робочого навантаження можуть вимагати суворого спільного розміщення в межах конкретних серверних стійок.

Такі багаторівневі вимоги до спільного розміщення можна виразити за допомогою API CompositePodGroup та вказуючи топологічні обмеження на різних рівнях ієрархії груп.

Використання API CompositePodGroup вимагає увімкнення функціональної можливості CompositePodGroup та групи API scheduling.k8s.io/v1alpha3.

Визначення багаторівневих топологічних обмежень

Кожна група в ієрархії CompositePodGroup може вказати топологічне обмеження, яке гарантує, що всі нащадкові Podʼи цієї групи будуть заплановані в тому самому топологічному домені, що відповідає обмеженню цієї групи.

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

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

Примітка:

Станом на Kubernetes v1.37 ви можете вказати лише одне топологічне обмеження в кожному CompositePodGroup.

Приклад

Наступний приклад налаштовує Workload, у якому батьківський CompositePodGroupTemplate обмежує все робоче навантаження однією зоною доступності (topology.example.com/zone), тоді як два дочірні елементи PodGroupTemplate (workers та driver) обмежують свої відповідні Podʼи серверними стійками (topology.example.com/rack) у межах цієї зони:

apiVersion: scheduling.k8s.io/v1alpha3
kind: Workload
metadata:
  name: example-workload
spec:
  compositePodGroupTemplates:
  - name: root
    schedulingPolicy:
      gang:
        minGroupCount: 2
    schedulingConstraints:
      topology:
      - key: topology.example.com/zone
    podGroupTemplates:
    - name: workers
      schedulingPolicy:
        gang:
          minCount: 8
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack
    - name: driver
      schedulingPolicy:
        gang:
          minCount: 1
      schedulingConstraints:
        topology:
        - key: topology.example.com/rack

Після створення обʼєкта Workload відповідні обʼєкти груп створюються таким чином:

  • Кореневий CompositePodGroup, що посилається на шаблон root.
  • Два дочірні обʼєкти PodGroup (workers та driver), кожен з яких посилається на кореневий CompositePodGroup як на свою батьківську групу.
apiVersion: scheduling.k8s.io/v1alpha3
kind: CompositePodGroup
metadata:
  name: workload-root
spec:
  workloadRef:
    workloadName: example-workload
    templateName: root
  schedulingPolicy:
    gang:
      minGroupCount: 2
  schedulingConstraints:
    topology:
    - key: topology.example.com/zone
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: workload-workers
spec:
  parentCompositePodGroupName: workload-root
  workloadRef:
    workloadName: example-workload
    templateName: workers
  schedulingPolicy:
    gang:
      minCount: 8
  schedulingConstraints:
    topology:
    - key: topology.example.com/rack
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: workload-driver
spec:
  parentCompositePodGroupName: workload-root
  workloadRef:
    workloadName: example-workload
    templateName: driver
  schedulingPolicy:
    gang:
      minCount: 1
  schedulingConstraints:
    topology:
    - key: topology.example.com/rack

Під час планування планувальник спочатку обирає зону доступності для workload-root. Потім він поділяє вузли в цій зоні за стійками, щоб знайти здійсненні розміщення на стійках для workload-workers та workload-driver у межах обраної зони.

Наприклад, розглянемо кластер із пʼятьма вузлами, позначеними таким чином:

Вузолtopology.example.com/zonetopology.example.com/rack
node-azone-1rack-1
node-bzone-1rack-1
node-czone-1rack-2
node-dzone-2rack-1
node-ezone-2rack-3

Під час обробки workload-root планувальник оцінює можливі розміщення на всіх вузлах кластера на основі топологічного ключа topology.example.com/zone:

Оцінене можливе розміщенняВузли в можливому розміщенні
zone-1node-a, node-b, node-c
zone-2node-d, node-e

Під час оцінки можливих розміщень для workload-workers планувальник поділяє лише вузли в межах розміщення, прийнятого workload-root, на основі топологічного ключа topology.example.com/rack:

Батьківське розміщенняОцінене можливе розміщенняВузли в можливому розміщенні
zone-1rack-1node-a, node-b
zone-1rack-2node-c
zone-2rack-1node-d
zone-2rack-3node-e

Можливі розміщення, згенеровані для сусіднього PodGroup workload-driver, ідентичні тим, що згенеровані для workload-workers, оскільки обидві групи вказують той самий топологічний ключ (topology.example.com/rack).

Що далі

7.4 - API будівельних блоків планування та бібліотека workloadbuilder

Примітиви API планування багаторазового використання, які контролери робочих навантажень, як вбудовані, так і сторонні, вбудовують у свої власні API, а також спільна бібліотека workloadbuilder, яка компілює їх в обʼєкти Workload, PodGroup та CompositePodGroup.
СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Планування з урахуванням робочого навантаження (Workload-aware Scheduling) визначає набір будівельних блоків API багаторазового використання у групі API scheduling.k8s.io. Автори контролерів вбудовують ці примітиви у свої власні API, щоб користувачі виражали намір щодо планування (групове планування, топологія, поведінка під час порушення) з узгодженою схемою в усій екосистемі, а спільна бібліотека workloadbuilder компілює цей намір в орієнтовані на планувальник обʼєкти Workload, PodGroup та CompositePodGroup.

Вбудованим споживачем цих будівельних блоків наразі є контролер Job, який вмикається функціональною можливістю WorkloadWithJob.

Будівельні блоки багаторазового використання

Будівельні блоки — це строго типізовані структури Go у групі API scheduling.k8s.io/v1alpha3. Вони призначені для авторів контролерів: контролер вбудовує ці структури у свій власний тип API як поля, а бібліотека workloadbuilder компілює їх. Назви типів дотримуються двох конвенцій: типи кінцевого рівня мають префікс WorkloadPodGroup... (наприклад, WorkloadPodGroupSchedulingPolicy), а багаторівневі варіанти — WorkloadCompositePodGroup....

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

Щоб перейняти будівельні блоки, контролер додає ті з них, які хоче підтримувати, як поля у своїх власних типах. Наприклад, API Job групує всі чотири з них в один тип, доступний у spec.scheduling:

type JobSchedulingConfiguration struct {
    SchedulingPolicy      *schedulingv1alpha3.WorkloadPodGroupSchedulingPolicy
    SchedulingConstraints *schedulingv1alpha3.WorkloadPodGroupSchedulingConstraints
    DisruptionMode        *schedulingv1alpha3.WorkloadPodGroupDisruptionMode
    ResourceClaims        []schedulingv1alpha3.WorkloadPodGroupResourceClaim
}

Інший контролер може вкладати ті самі блоки для кожного компонента багаточастинного робочого навантаження або підтримувати лише їх підмножину.

Політика планування

Блок політики планування містить ті самі політики basic та gang, що й spec.schedulingPolicy PodGroup. Див. політики планування PodGroup для пояснення, що означає кожна політика та як планувальник її застосовує.

Єдина відмінність полягає в тому, що мінімальна кількість для gang у блоці є необовʼязковою. Користувачі можуть залишити minCount невстановленим, і в цьому випадку контролер надає стандартне значення, яке має сенс для його предметної області; контролер Job, наприклад, використовує паралелізм Job.

Обмеження планування

Блок обмежень планування містить топологічні обмеження, задокументовані в топологічно орієнтованому плануванні робочих навантажень: ключ мітки вузла, що називає домен (наприклад, стійку або зону), який повинен бути спільним для кожного Podʼа в групі, з не більш ніж одним топологічним обмеженням на групу. Контролери повинні заморожувати поле після створення, оскільки обмеження є незмінними в скомпільованому Workload.

Режим порушення

Блок режиму порушення визначає, чи можна порушувати роботу Podʼів групи окремо (single) або лише як єдиного цілого (all), що відповідає режимам порушення Pod та PodGroup, задокументованим у розділі Порушення та пріоритет групи Podʼів.

Бібліотека відхиляє комбінації, які не мають сенсу. Наприклад, вона забороняє режим порушення all для PodGroups з BasicSchedulingPolicy, оскільки одиниця витіснення не повинна бути більшою за одиницю планування — група, запланована Pod за Podʼом, не має одиниці на рівні групи для витіснення або порушення.

Заявки на ресурси

Блок заявок на ресурси виражає, які заявки динамічного виділення ресурсів є спільними для кожного Podʼа в групі, а не виділяються на кожен Pod окремо. Кожен запис називає заявку в межах групи та вказує або на наявний ResourceClaim, або на ResourceClaimTemplate, з якого вона генерується. Група може оголосити не більше чотирьох заявок.

Podʼи споживають пристрої, виділені групі, оголошуючи відповідну заявку у власній специфікації, використовуючи ту саму назву та посилаючись на той самий обʼєкт.

Складені будівельні блоки

Багаторівневі контролери, які оркеструють інші контролери (наприклад, JobSet, що створює Jobs), координують групу груп. Для цього рівня API надає аналогічний набір примітивів з префіксом WorkloadCompositePodGroup... (наприклад, WorkloadCompositePodGroupSchedulingPolicy). Вони мають таку саму форму, що й блоки кінцевого рівня, за винятком того, що складена політика gang використовує minGroupCount (мінімальну кількість дочірніх груп, які мають бути придатними для планування разом) замість minCount кінцевого рівня. Збереження окремих типів кінцевого та складеного рівнів дозволяє кожному рівню ієрархії розвиватися незалежно.

Приклад: інтеграція з Job

Контролер Job є вбудованим прикладом використання цих блоків. Користувач заповнює spec.scheduling Job, а контролер компілює його в Workload та PodGroup. Див. інтеграцію з Workload API для повного маніфесту Job, стандартних значень, які застосовуються, коли spec.scheduling пропущено, та які поля ви можете змінювати після створення.

Бібліотека workloadbuilder

workloadbuilder — це спільна бібліотека Go, яка перетворює намір контролера щодо планування в орієнтовані на планувальник Workload та його обʼєкти PodGroup/CompositePodGroup під час виконання, тож контролерам не потрібно заново реалізовувати застосування стандартних значень, перевірку та компіляцію шаблонів. Вона розроблена як для вбудованих контролерів (таких як контролер Job), так і для сторонніх контролерів (таких як JobSet або Kubeflow TrainJob), які підключають її через vendor, як будь-яку іншу залежність Go. Вона постачається з k8s.io/component-helpers/scheduling/schedulingv1/workloadbuilder.

Бібліотека споживає будівельні блоки scheduling.k8s.io/v1alpha3 та компілює їх в обʼєкти Workload та PodGroup scheduling.k8s.io/v1beta1, тоді як обʼєкти CompositePodGroup залишаються scheduling.k8s.io/v1alpha3.

Як контролер її використовує

Контролер описує своє робоче навантаження як дерево вузлів WorkloadItem, по одному на кожен логічний компонент. Вузол без дочірніх елементів стає одним PodGroupTemplate, тоді як вузол з дочірніми елементами стає CompositePodGroupTemplate над ними — саме так багаторівневий контролер представляє групу груп. Кожен вузол містить:

  • стандартну конфігурацію — власні стандартні значення контролера для всього, що користувач залишає невстановленим. Саме тут контролер вирішує, наприклад, що неналаштований Job залишається на плануванні basic.
  • вхідні дані — намір користувача, взятий з API контролера. Контролер записує кожен будівельний блок разом із шляхом до поля, на якому він розташований, щоб помилки перевірки вказували на точне поле, яке встановив користувач.
  • необовʼязкові зворотні виклики, які коригують обʼєднану конфігурацію. Саме так контролер надає контекстно-залежне стандартне значення, наприклад, заповнює невстановлену мінімальну кількість gang з паралелізму Job.

Потім контролер передає це дерево до Builder і виконує чотири виклики:

  1. NewBuilder створює builder із дерева разом із назвою, простором імен та посиланням на власника для обʼєкта, який буде створено. Власник стає посиланням на контролер Workload, яке використовується для виявлення та збору сміття.
  2. Validate розвʼязує дерево та повідомляє про будь-які проблеми як список помилок полів, які контролер повертає з власної перевірки API.
  3. BuildWorkload компілює дерево в Workload. Результат кешується, тому з одного скомпільованого результату можна створити кілька PodGroups.
  4. NewPodGroup створює PodGroup під час виконання з одного зі скомпільованих шаблонів, називаючи шаблон, з якого він повинен бути створений.
builder := workloadbuilder.NewBuilder(item, opts)
if errs := builder.Validate(ctx, workloadbuilder.ValidationInput{}); len(errs) > 0 {
    // reject the request
}
workload, err := builder.BuildWorkload()
podGroup, err := builder.NewPodGroup("trainer-pg", item.Name)

Повні робочі версії цього процесу, включаючи те, як контролер Job його підключає, дивіться в прикладах у довіднику пакета.

Перевірка конфігурації планування

Validate перевіряє конфігурацію на двох рівнях:

  • Структурна перевірка самих будівельних блоків: обовʼязкові поля, діапазони значень, правило, що рівно один член обʼєднання встановлений, та незмінність. Ці перевірки походять з правил декларативної перевірки, згенерованих з типів API.
  • Перевірки політики контролера, які декларативна перевірка не може виразити: списки дозволених значень, описані нижче, та міжпольові правила, такі як відхилення режиму порушення all разом з політикою basic.

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

Відмова від декларативної перевірки

Чи потрібен вам перший рівень, залежить від того, де працює ваш контролер, і одна опція керує ним:

  • Сторонні контролери залишають декларативну перевірку увімкненою, що є стандартною поведінкою. Ніщо інше не застосовує ці структурні правила до власного ресурсу, тому один виклик Validate покриває обидва рівні.
  • Вбудовані контролери встановлюють DisableDeclarativeValidation, оскільки API-сервер вже виконує декларативну перевірку вбудованих блоків під час перевірки батьківського обʼєкта. Пропуск першого рівня дозволяє уникнути перевірки тих самих полів двічі, залишаючи Validate виконувати лише перевірки політики контролера.

Вибір опцій планування

Оскільки типи будівельних блоків є спільними для контролерів, майбутні випуски можуть додавати опції планування, які не мають сенсу для кожного контролера. Щоб нові опції не просочувалися непомітно, workloadbuilder використовує модель списку дозволених значень: контролер оголошує політики та режими порушення, які він підтримує, а Validate відхиляє все, що виходить за межі цього набору, повідомляючи про помилку за шляхом до поля блоку, що порушує правила.

Тому опції стандартно заборонені. Коли вводиться нова політика, наявний контролер продовжує її відхиляти, доки його супроводжувачі не розширять список дозволених значень, що для стороннього контролера означає також оновлення його копії бібліотеки у vendor.

builder := workloadbuilder.NewBuilder(item, workloadbuilder.BuildOptions{
    Owner:                  owner,
    AllowedPolicies:        []workloadbuilder.SchedulingPolicyOption{workloadbuilder.BasicPolicy, workloadbuilder.GangPolicy},
    AllowedDisruptionModes: []workloadbuilder.DisruptionModeOption{workloadbuilder.SingleMode, workloadbuilder.AllMode},
})
allErrs := builder.Validate(ctx, workloadbuilder.ValidationInput{})

Створення PodGroups з наявного Workload

Коли Workload вже існує, незалежно від того, чи він скомпільований батьківським контролером, чи створений вручну, дочірній контролер, який керує лише PodGroup під час виконання, використовує натомість NewBuilderFromExistingWorkload. Цей builder створює обʼєкти PodGroup з наданого Workload, використовуючи власне посилання на власника. Він нічого не перевіряє та не компілює, тому наявний Workload ніколи не перекомпілюється.

builder := workloadbuilder.NewBuilderFromExistingWorkload(parentWorkload, workloadbuilder.BuildOptions{Owner: owner})
podGroup, err := builder.NewPodGroup("trainer-pg", "trainer-pgt-0")

Що далі

8 - PodGroup API

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

PodGroup — це обʼєкт часу виконання, який представляє групу Podʼів, запланованих разом як єдине ціле. У той час як Workload API визначає шаблони політик планування, PodGroups є їхніми аналогами часу виконання, які містять як саму політику, так і статус планування для конкретного екземпляра цієї групи.

Що таке PodGroup?

Ресурс API PodGroup є частиною групи API scheduling.k8s.io/v1beta1, і ваш кластер повинен мати цю групу API увімкненою, а також функціональну можливість GenericWorkload, перш ніж ви зможете використовувати цей API.

PodGroup — це самостійна одиниця планування. Він визначає групу Podʼів, які мають бути заплановані разом, містить політику планування, що регулює розміщення, і фіксує статус часу виконання цього рішення про планування.

Структура API

PodGroup складається з розділів spec, який визначає бажану поведінку планування, та status, який відображає поточний стан планування.

Політика планування

Кожен PodGroup містить політику планування (basic або gang) у spec.schedulingPolicy. Коли контролер робочого навантаження створює PodGroup, ця політика копіюється з PodGroupTemplate обʼєкта Workload під час створення. Для автономних PodGroups ви встановлюєте політику безпосередньо.

spec:
  schedulingPolicy:
    gang:
      minCount: 4

Посилання на шаблон

Необовʼязкове поле spec.podGroupTemplateRef повʼязує PodGroup з PodGroupTemplate у Workload, з якого його було створено. Це корисно для спостереження та інструментів.

spec:
  podGroupTemplateRef:
    workload:
      workloadName: training-policy
      podGroupTemplateName: worker

Пріоритет і режим порушення

Кожен PodGroup також може визначати власні spec.priority, spec.preemptionPolicy та spec.disruptionMode. Пріоритет і політика витіснення встановлюються за допомогою поля spec.priorityClassName, яке вказує на ресурс PriorityClass. Див. Порушення та пріоритет групи Podʼів для детального опису цих полів.

Коли контролер робочого навантаження створює PodGroup, ці поля копіюються з PodGroupTemplate обʼєкта Workload під час створення. Для автономних PodGroups ви встановлюєте поля безпосередньо.

spec:
  disruptionMode:
    all: {}
  priorityClassName: high-priority

Запит пристроїв DRA для PodGroup

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the DRAWorkloadResourceClaims feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Пристрої, доступні через Динамічне виділення ресурсів (DRA), можуть бути запитані PodGroup через поле spec.resourceClaims:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-group
  namespace: some-ns
spec:
  ...
  resourceClaims:
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template

ResourceClaims, повʼязані з PodGroups, можуть бути спільно використані всіма Podʼами, що належать до групи. Замість того, щоб мати посилання на кожен окремий Pod у status.reservedFor ResourceClaim, достатньо посилання на PodGroup, і будь-яка кількість Podʼів у тому самому PodGroup може спільно використовувати ResourceClaim. ResourceClaims також можуть бути створені з ResourceClaimTemplates для кожного PodGroup, що дозволяє пристроям, виділеним для кожного створеного ResourceClaim, бути спільно використаними Podʼами в кожному PodGroup.

За докладною інформацією та більш повним прикладом звертайтесь до документації DRA.

Статус

Планувальник оновлює status.conditions, щоб повідомити, чи група була успішно запланована. Основним станом є PodGroupInitiallyScheduled, який є True, коли всі необхідні Podʼи були розміщені, і False, коли планування не вдається.

Примітка:

Стан PodGroupInitiallyScheduled відображає лише початкове рішення планувальника. Планувальник не оновлює її, якщо Podʼи пізніше зазнають збою або будуть виселені. Детальніше див. у розділі Обмеження.

Див. сторінку Життєвий цикл PodGroup для повного списку станів та причин.

Створення PodGroup

Ресурс API PodGroup є частиною групи API scheduling.k8s.io/v1beta1 (і ваш кластер повинен мати цю групу API увімкненою, а також функціональну можливість GenericWorkload, перш ніж ви зможете використовувати цей API).

Наступний маніфест створює PodGroup з політикою планування gang, яка вимагає, щоб щонайменше 4 Podʼи були придатними для планування одночасно:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-worker-0
  namespace: default
spec:
  schedulingPolicy:
    gang:
      minCount: 4

Ви можете переглянути PodGroups у вашому кластері:

kubectl get podgroups

Щоб побачити повний статус, включаючи стани планування:

kubectl describe podgroup training-worker-0

Як це все поєднується

Взаємозвʼязок між контролерами, Workloads, PodGroups та Podʼами побудовано за такою схемою:

  1. Контролер робочого навантаження створює Workload, який визначає PodGroupTemplates з політиками планування.
  2. Для кожного екземпляра часу виконання контролер створює PodGroup з одного з PodGroupTemplates обʼєкта Workload.
  3. Контролер створює Podʼи, які посилаються на PodGroup через поле spec.schedulingGroup.podGroupName.

Контролер Job є єдиним вбудованим контролером робочого навантаження, який наразі дотримується цієї схеми. Власні контролери можуть реалізувати той самий процес для своїх власних типів робочих навантажень.

apiVersion: scheduling.k8s.io/v1beta1
kind: Workload
metadata:
  name: training-policy
spec:
  podGroupTemplates:
  - name: worker
    schedulingPolicy:
      gang:
        minCount: 4
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-worker-0
spec:
  podGroupTemplateRef:
    workload:
      workloadName: training-policy
      podGroupTemplateName: worker
  schedulingPolicy:
    gang:
      minCount: 4
---
apiVersion: v1
kind: Pod
metadata:
  name: worker-0
spec:
  schedulingGroup:
    podGroupName: training-worker-0
  containers:
  - name: ml-worker
    image: training:v1

Workload виступає як довговічне визначення політики, тоді як PodGroups обробляють тимчасовий стан часу виконання для кожного екземпляра. Це розділення означає, що оновлення статусу окремих PodGroups не конкурують за спільний обʼєкт Workload.

Батьківська група

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

Коли функціональну можливість CompositePodGroup увімкнено, PodGroup може діяти як кінцевий вузол у багаторівневій ієрархії груп, що складається з PodGroups та CompositePodGroups. PodGroup може вказати свою батьківську групу за допомогою поля spec.parentCompositePodGroupName. Організація робочого навантаження в ієрархію груп може використовуватися для вираження багаторівневих вимог групового планування, багаторівневих обмежень топології та спільної долі під час порушення для частин робочого навантаження.

Для отримання додаткових відомостей про ієрархічні структури груп та багаторівневе групове планування див. огляд CompositePodGroup API.

Примітка:

PodGroup, який вказує spec.parentCompositePodGroupName, також повинен вказувати spec.workloadRef, повʼязуючи PodGroup з його шаблоном у Workload. Автономним обʼєктам PodGroup (створеним без spec.workloadRef) не дозволяється вказувати батьківський CompositePodGroup.

Що далі

8.1 - Життєвий цикл PodGroup

СТАН ФУНКЦІОНАЛУ: Beta since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

PodGroup планується як єдине ціле і захищений від передчасного видалення, поки його Podʼи все ще працюють.

Володіння та життєвий цикл

PodGroups належать контролеру робочого навантаження, який їх створив (наприклад, Job), через стандартні ownerReferences. Коли обʼєкт-власник видаляється, PodGroups автоматично видаляються збирачем сміття.

Назви PodGroup повинні бути унікальними в межах простору імен і бути дійсними DNS-піддоменами.

Порядок створення

Контролери повинні створювати обʼєкти в такому порядку:

  1. Workload — шаблон політики планування.
  2. PodGroup — екземпляр під час виконання.
  3. Pods — з spec.schedulingGroup.podGroupName, що вказує на PodGroup.

Якщо PodGroup включає podGroupTemplateRef, який вказує на Workload, що не існує (або видаляється), API-сервер відхиляє запит на створення PodGroup. Вказаний Workload повинен існувати перед створенням PodGroup.

Якщо Pod посилається на PodGroup, який ще не існує, Pod залишається в стані очікування. Планувальник автоматично ставить Pod у чергу для планування, як тільки PodGroup буде створено.

Захист від видалення

PodGroup не може бути повністю видалено, поки будь-які його Podʼи все ще працюють. Спеціальний завершувач забезпечує блокування видалення, поки всі Pods, що посилаються на PodGroup, не досягнуть термінальної фази (Succeeded або Failed).

PodGroups, керовані контролером та користувачем

У більшості випадків контролери робочих навантажень (наприклад, Job) створюють PodGroups автоматично (керовані контролером). Контролер визначає podGroupName для кожного Podʼа під час створення, аналогічно тому, як DaemonSet встановлює спорідненість вузлів для кожного Podʼа.

Якщо вам потрібно більше контролю над іменуванням та життєвим циклом, ви можете безпосередньо створювати обʼєкти PodGroup та самостійно встановлювати spec.schedulingGroup.podGroupName у своїх шаблонах Podʼів (керовані користувачем). Це надає вам повний контроль над створенням та іменуванням PodGroup.

Обмеження

  • Всі Podʼи в PodGroup повинні використовувати той самий .spec.schedulerName. Якщо виявлено невідповідність, планувальник відхиляє всі Podʼи в групі як такі, що не можуть бути заплановані.
  • Всі Podʼи в PodGroup повинні використовувати той самий .spec.priority. Якщо виявлено невідповідність, планувальник відхиляє всі Podʼи в групі як такі, що не можуть бути заплановані.
  • Всі Podʼи в PodGroup повинні використовувати той самий .spec.preemptionPolicy. Якщо виявлено невідповідність, планувальник відхиляє всі Podʼи в групі як такі, що не можуть бути заплановані.
  • Поле spec.schedulingGroup у Podʼа є незмінним. Після встановлення Pod не може перейти до іншого PodGroup.
  • Максимальна кількість PodGroupTemplates в одному Workload становить 8.
  • Планувальник не оновлює інформацію про статус щодо поточного робочого стану PodGroup або подальших спроб планування після початкового розміщення. Отже, статус PodGroup не оновлюється, коли наявні Podʼи зазнають збою, виселяються або завершуються, або коли нововиявлені Podʼи не можуть бути заплановані.

Що далі

9 - CompositePodGroup API

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

CompositePodGroup — це обʼєкт часу виконання, який представляє некінцевий вузол у багаторівневій ієрархії робочого навантаження. У той час як Workload API визначає статичні шаблони політик планування, обʼєкти CompositePodGroup та PodGroup є їхніми аналогами часу виконання, які містять політики та посилання на ієрархію для конкретного екземпляра робочого навантаження.

Що таке CompositePodGroup?

Ресурс API CompositePodGroup є частиною групи API scheduling.k8s.io/v1alpha3. Ваш кластер повинен мати цю групу API увімкненою, а також функціональну можливість CompositePodGroup, перш ніж ви зможете використовувати цей API.

CompositePodGroup представляє групування дочірніх груп (які можуть бути обʼєктами CompositePodGroup або PodGroup). Він містить політики планування, режими порушення, налаштування пріоритету та необовʼязкові топологічні обмеження, які застосовуються колективно до його дочірніх груп.

Структура API

CompositePodGroup складається з розділу spec, який визначає бажану поведінку планування для його дочірніх груп, та субресурсу status.

Політика планування

Кожен CompositePodGroup містить політику планування (basic або gang) у spec.schedulingPolicy. Коли контролер робочого навантаження створює CompositePodGroup, ця політика копіюється з CompositePodGroupTemplate обʼєкта Workload під час створення.

Для політики gang на CompositePodGroup поле minGroupCount визначає мінімальну кількість дочірніх груп, які мають бути придатними для планування одночасно:

spec:
  schedulingPolicy:
    gang:
      minGroupCount: 2

Посилання на батьківську групу

Некореневі ресурси CompositePodGroup вказують свою батьківську групу за допомогою spec.parentCompositePodGroupName. Кореневі обʼєкти CompositePodGroup залишають це поле невстановленим.

spec:
  parentCompositePodGroupName: root-group-0

Посилання на робоче навантаження

Поле spec.workloadRef повʼязує CompositePodGroup з CompositePodGroupTemplate в обʼєкті Workload, з якого він був створений.

spec:
  workloadRef:
    workloadName: hierarchical-workload
    templateName: replica-group

Статус

Схема API CompositePodGroup включає субресурс status. В альфа-версії поле status присутнє в типі API, але kube-scheduler не оновлює та не заповнює стани статусу для обʼєктів CompositePodGroup. Відстеження статусу для складених груп буде реалізовано в майбутніх випусках.

Створення CompositePodGroup

Контролери робочого навантаження створюють обʼєкти CompositePodGroup автоматично з шаблонів Workload під час виконання.

Наступний маніфест створює кореневий CompositePodGroup з політикою планування gang, яка вимагає, щоб щонайменше 2 дочірні групи були придатними для планування одночасно:

apiVersion: scheduling.k8s.io/v1alpha3
kind: CompositePodGroup
metadata:
  name: root-group-0
  namespace: default
spec:
  workloadRef:
    workloadName: hierarchical-workload
    templateName: root
  schedulingPolicy:
    gang:
      minGroupCount: 2

Ви можете переглянути ресурси CompositePodGroup у вашому кластері:

kubectl get compositepodgroups

Щоб переглянути деталі конкретної складеної групи:

kubectl describe compositepodgroup root-group-0

Як це все поєднується

Взаємозвʼязок між контролерами, Workloads, CompositePodGroups, PodGroups та Podʼами побудовано за такою схемою:

  1. Контролер робочого навантаження створює Workload, який визначає дерево CompositePodGroupTemplates та кінцевих PodGroupTemplates.
  2. Для кожного екземпляра часу виконання контролер створює кореневий CompositePodGroup, дочірні обʼєкти CompositePodGroup та кінцеві обʼєкти PodGroup у порядку зверху вниз.
  3. Контролер створює Pods, які посилаються на свій кінцевий PodGroup через spec.schedulingGroup.podGroupName.

Наступний приклад ілюструє повну ієрархію маніфестів для дворівневого робочого навантаження:

apiVersion: scheduling.k8s.io/v1alpha3
kind: Workload
metadata:
  name: hierarchical-workload
  namespace: default
spec:
  compositePodGroupTemplates:
  - name: root
    schedulingPolicy:
      gang:
        minGroupCount: 2
    podGroupTemplates:
    - name: workers-a
      schedulingPolicy:
        gang:
          minCount: 4
    - name: workers-b
      schedulingPolicy:
        gang:
          minCount: 4
---
apiVersion: scheduling.k8s.io/v1alpha3
kind: CompositePodGroup
metadata:
  name: root-group-0
  namespace: default
spec:
  workloadRef:
    workloadName: hierarchical-workload
    templateName: root
  schedulingPolicy:
    gang:
      minGroupCount: 2
---
apiVersion: scheduling.k8s.io/v1alpha3
kind: PodGroup
metadata:
  name: workers-a-0
  namespace: default
spec:
  parentCompositePodGroupName: root-group-0
  workloadRef:
    workloadName: hierarchical-workload
    templateName: workers-a
  schedulingPolicy:
    gang:
      minCount: 4
---
apiVersion: scheduling.k8s.io/v1alpha3
kind: PodGroup
metadata:
  name: workers-b-0
  namespace: default
spec:
  parentCompositePodGroupName: root-group-0
  workloadRef:
    workloadName: hierarchical-workload
    templateName: workers-b
  schedulingPolicy:
    gang:
      minCount: 4
---
apiVersion: v1
kind: Pod
metadata:
  name: worker-a-0
  namespace: default
spec:
  schedulingGroup:
    podGroupName: workers-a-0
  containers:
  - name: worker
    image: registry.k8s.io/pause:3.9

Workload виступає як довговічний шаблон політики, тоді як ресурси CompositePodGroup та PodGroup обробляють стан планування під час виконання для кожного екземпляра.

Що далі

9.1 - Життєвий цикл CompositePodGroup

СТАН ФУНКЦІОНАЛУ: Alpha since Kubernetes v1.37; (стандартно вимкнено)
More information about this feature

To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.

See Enable Or Disable Feature Gates for more information.

CompositePodGroup представляє некінцевий вузол у багаторівневій ієрархії PodGroup. На відміну від ресурсів PodGroup, ресурси CompositePodGroup не містять Podʼів безпосередньо. Натомість вони підтримують ієрархію дочірніх обʼєктів CompositePodGroup та PodGroup і містять політики планування, які застосовуються до їхніх дочірніх груп.

Володіння та збір сміття

Обʼєкт CompositePodGroup разом зі своїми дочірніми ресурсами CompositePodGroup та PodGroup належить контролеру робочого навантаження, який його створив, через ownerReferences Kubernetes. Коли обʼєкт-власник робочого навантаження видаляється, каскадний збір сміття автоматично видаляє повʼязану ієрархію груп.

Назви CompositePodGroup повинні бути унікальними в межах простору імен і бути дійсними DNS-піддоменами.

Порядок створення

Щоб забезпечити правильне розвʼязання ієрархії та планування, контролери робочого навантаження створюють ресурси в порядку зверху вниз:

  1. Workload: визначає статичні шаблони (CompositePodGroupTemplates та PodGroupTemplates).
  2. Кореневий CompositePodGroup: створюється з spec.workloadRef, що вказує на кореневий шаблон у Workload.
  3. Дочірні CompositePodGroups та PodGroups: створюються зверху вниз. Кожна дочірня група вказує свого батька за допомогою spec.parentCompositePodGroupName, а свій шаблон — за допомогою spec.workloadRef.
  4. Pods: створюються з spec.schedulingGroup.podGroupName, що вказує на їхній кінцевий PodGroup.

Якщо група посилається на батьківський CompositePodGroup, який не існує, або якщо Pod посилається на PodGroup, який ще не створено, планувальник відкладає планування, доки всі батьківські ресурси в ієрархії не існуватимуть.

Обмеження та правила перевірки

  • Узгоджена назва планувальника: всі Podʼи в усій ієрархії CompositePodGroup повинні використовувати той самий spec.schedulerName. Якщо виявлено невідповідність, планувальник відхиляє ієрархію як непридатну для планування.
  • Узгоджений пріоритет: всі Podʼи в усій ієрархії CompositePodGroup повинні вказувати те саме значення spec.priority, яке має дорівнювати пріоритету, вказаному кореневою групою. Якщо виявлено невідповідність, планувальник відхиляє ієрархію як непридатну для планування.
  • Узгоджена політика витіснення: всі Podʼи в усій ієрархії CompositePodGroup повинні використовувати той самий spec.preemptionPolicy. Крім того, коли функціональну можливість PodGroupPreemptionPolicy увімкнено, політика витіснення кореневої групи повинна дорівнювати політиці, вказаній Podʼами. Якщо виявлено невідповідність, планувальник відхиляє ієрархію як непридатну для планування.
  • Максимальна глибина вкладеності: ієрархія шаблонів груп підтримує максимальну глибину 4 рівні.
  • Обмеження списку: максимальна кількість дочірніх CompositePodGroupTemplates та PodGroupTemplates на будь-якому рівні Workload становить 8.
  • Незмінна кількість груп gang: поле spec.schedulingPolicy.gang.minGroupCount на CompositePodGroup є незмінним після створення.
  • Незмінні посилання на ієрархію: spec.parentCompositePodGroupName на групах та spec.schedulingGroup на Podʼах є незмінними після встановлення.

Що далі