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

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

Podʼи

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

Pod (як у випадку з групою китів або гороховим стручком) — це група з одного або кількох контейнерів, які мають спільні ресурси зберігання та мережі, а також специфікацію щодо того, як запускати контейнери. Вміст Podʼа завжди розташований та запускається разом, та працює в спільному контексті. 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 напряму в Kubernetes, навіть одиничних Podʼів. Натомість створюйте їх за допомогою ресурсів робочих навантажень, таких як Deployment або Job. Якщо ваші Podʼи потребують відстеження стану, розгляньте використання ресурсу StatefulSet.

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

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

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

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

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

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

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

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.25 [stable]

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

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

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

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

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

Pod templates

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

PodTemplate — це специфікація для створення Pod, і вона включена в ресурси робочих навантажень, такі як Deployment, Job та DaemonSet.

Кожен контролер ресурсів робочих навантажень використовує 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ʼа

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

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

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

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

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

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

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

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

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

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

Збереження в Podʼах

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

Мережі та Pod

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

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

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

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

  • Відкидайте конкретні можливості Linux, щоб уникнути впливу CVE.
  • Примусово запускайте всі процеси в Podʼі як користувач не-root або як певний користувач або ідентифікатор групи.
  • Встановлюйте конкретний профіль seccomp.
  • Встановлюйте параметри безпеки Windows, такі як те, чи працюють контейнери як HostProcess.

Статичні Podʼи

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.22 [stable]

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

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

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

Як Podʼи керують кількома контейнерами

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

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

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

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

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

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

У вас також може бути "sidecar" контейнер, який виконує додаткові функції для контейнера застосунку, наприклад, реалізує service mesh.

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.29 [beta]

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

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

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

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

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

Що далі

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

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

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

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

Тривалість життя Podʼа

Поки Pod працює, kubelet може перезапускати контейнери, щоб вирішити деякі види несправностей. У межах Podʼа Kubernetes відстежує різні стани контейнера і визначає дії, які слід вжити, щоб знову забезпечити справність 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, наприклад volume, це означає, що ця річ існує стільки часу, скільки існує цей конкретний Pod (з таким самим UID). Якщо цей Pod буде видалений з будь-якої причини, і навіть якщо буде створений ідентичний замінник, повʼязана річ (у цьому прикладі — том) також буде знищена і створена знову.

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

Малюнок 1.

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

Фази Pod

Поле status обʼєкта PodStatus Podʼа містить поле phase.

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

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

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

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

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

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

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

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

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

Щоб перевірити стан контейнерів Podʼа, ви можете використовувати kubectl describe 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ʼів за допомогою політики перезапуску, визначеної в spec Podʼа. Ця політика визначає, як Kubernetes реагує на виходи контейнерів через помилки або інші причини, які складаються з наступних етапів:

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

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

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

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

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

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

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

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

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

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

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

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

Стани Podʼа

У Podʼа є статус, який містить масив PodConditions, через які Pod проходить чи не проходить. Kubelet управляє наступними PodConditions:

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

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

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.14 [stable]

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

Стани готовності визначаються поточним станом полів 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 оцінюється як готовий тільки коли застосовуються обидва наступні твердження:

  • Всі контейнери в Podʼі готові.
  • Всі стани, вказані в readinessGates, рівні True.

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

Готовність мережі Podʼа

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.29 [beta]

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

Стан PodReadyToStartContainers встановлюється в False kubeletʼом, коли він виявляє, що у Podʼа немає ізольованого середовища виконання із налаштованою мережею. Це трапляється в наступних випадках:

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

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

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

Діагностика контейнера

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

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

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

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

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

Кожна проба має один із трьох результатів:

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

Типи проб

Kubelet може опціонально виконувати та реагувати на три типи проб для робочих контейнерів:

livenessProbe
Вказує, чи контейнер працює. Якщо ця проба не проходить, kubelet припиняє роботу контейнера, і він підлягає перезапуску відповідно до своєї політики перезапуску. Якщо в контейнері не впроваджено пробу життєздатності, стандартний стан — Success.
readinessProbe
Вказує, чи готовий контейнер відповідати на запити. Якщо проба готовності завершиться невдачею, контролер endpoint видаляє IP-адресу Podʼа з endpoint усіх служб, які збігаються з Podʼом. Стандартний стан готовності перед початковою затримкою — Failure. Якщо в контейнері не проваджено пробу готовності, стандартний стан — Success.
startupProbe
Вказує, чи запущено застосунок всередині контейнера. Усі інші проби вимкнено, якщо впроваджено пробу запуску, поки вона не стане успішною. Якщо проба запуску завершиться невдачею, kubelet вбиває контейнер, і він підлягає перезапуску відповідно до політики перезапуску. Якщо в контейнері не впроваджено пробу запуску, стандартний стан — Success.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Припинення роботи 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 секунд.

    2. Kubelet робить виклик до середовища виконання контейнера для надсилання сигналу TERM процесу 1 всередині кожного контейнера.

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

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

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

    Будь-які endpoint, які представляють Podʼи, що закінчують свою роботу, не вилучаються негайно з EndpointSlices, а статус, який вказує на стан завершення, викладається з EndpointSlice API (та застарілого API Endpoints). Endpointʼи, які завершуть роботу, завжди мають статус 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ʼів

Типово всі видалення є належними протягом 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ʼами у стані завершення, привʼязаними до непрацюючого вузла з позначкою node.kubernetes.io/out-of-service, коли ввімкнено функціонал NodeOutOfServiceVolumeDetach.

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

Що далі

2 - Контейнери ініціалізації

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

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

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

Контейнери ініціалізації

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

Контейнери ініціалізації абсолютно такі ж, як і звичайні контейнери, окрім того:

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

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

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

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

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

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

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

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

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

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

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

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

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

Використання контейнерів ініціалізації

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

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

Приклади

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

  • Очікування на створення 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.

Використання контейнерів ініціалізації

У цьому прикладі визначається простий Pod, який має два контейнери ініціалізації. Перший чекає на myservice, а другий — на mydb. Як тільки обидва контейнери ініціалізації завершаться, 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

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

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

На цей момент ці контейнери ініціалізації будуть чекати виявлення Сервісів з іменами 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

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

kubectl get -f myapp.yaml

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Контейнери ініціалізація та cgroups Linux

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

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

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

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

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

Що далі

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

3 - Контейнери sidecar

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.29 [beta]

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

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

Контейнери sidecar в Kubernetes

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

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

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

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

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

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
          restartPolicy: Always
          command: ['sh', '-c', 'tail -F /opt/logs.txt']
          volumeMounts:
            - name: data
              mountPath: /opt
      volumes:
        - name: data
          emptyDir: {}

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

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

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

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

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

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

Завдання з контейнерами sidecar

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

Ось приклад 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
          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ʼа, і зазвичай їх слід ігнорувати зовнішньому інструментарію.

Відмінності від контейнерів ініціалізації

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

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

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

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

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

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

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

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

Контейнери sidecar та cgroups Linux

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

Що далі

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

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.25 [stable]

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

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

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

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

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

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

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

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

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

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

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

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

Що далі

5 - Розлади

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

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

Добровільні та невідворотні розлади

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

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

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

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

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

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

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

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

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

Управління розладами

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

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

Бюджет розладів Podʼів

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.21 [stable]

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

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

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

Наприклад, команда 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 ресурсу робочого навантаження (Workload), який управляє цими Podʼами. Панель управління визначає ресурс робочого навантаження, оглядаючи .metadata.ownerReferences Podʼа.

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

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

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

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

Приклад бюджету розладів поди

Припустимо, що у кластері є 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 drainingnode-2node-3
pod-a terminatingpod-b availablepod-c available
pod-x terminating

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

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

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

node-1 drainingnode-2node-3
pod-a terminatingpod-b availablepod-c available
pod-x terminatingpod-d startingpod-y

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

node-1 drainednode-2node-3
pod-b availablepod-c available
pod-d startingpod-y

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

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

node-1 drainednode-2node-3
pod-b availablepod-c available
pod-d availablepod-y

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

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

node-1 drainednode-2node-3no node
pod-b terminatingpod-c availablepod-e pending
pod-d availablepod-y

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

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

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

Умови розладу поду

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.31 [stable] (стандартно увімкнено: true)

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

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

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

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

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

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

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

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

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

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

Як виконати дії з розладу у вашому кластері

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

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

Що далі

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

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

Класи обслуговування (QoS)

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

Guaranteed

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

Критерії

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

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

Burstable

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

Критерії

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

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

BestEffort

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

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

Критерії

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

QoS памʼяті з cgroup v2

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.22 [alpha] (стандартно увімкнено: false)

QoS памʼяті використовує контролер памʼяті cgroup v2 для гарантування ресурсів памʼяті в Kubernetes. Запити та ліміти памʼяті контейнерів у Podʼі використовуються для встановлення конкретних інтерфейсів memory.min та memory.high, які надає контролер памʼяті. Коли memory.min встановлено на запити памʼяті, ресурси памʼяті резервуються і ніколи не звільняються ядром; саме так QoS памʼяті забезпечує наявність памʼяті для Podʼів Kubernetes. Якщо в контейнері встановлено ліміти памʼяті, це означає, що системі потрібно обмежити використання памʼяті контейнера; QoS памʼяті використовує memory.high для обмеження роботи навантаження, що наближається до свого ліміту памʼяті, забезпечуючи, що систему не перевантажено миттєвим виділенням памʼяті.

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

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

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

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

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

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

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

Що далі

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

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.30 [beta]

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

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

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

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

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

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

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

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

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

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

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

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

containerd v1.7 несумісний із підтримкою userns в Kubernetes v1.27 по v1.31. Kubernetes v1.25 і v1.26 використовували попередню реалізацію, яка є сумісною з containerd v1.7 з точки зору підтримки userns. Якщо ви використовуєте версію Kubernetes, відмінну від 1.31, перевірте документацію для цієї версії Kubernetes для найбільш актуальної інформації. Якщо є новіша версія containerd, ніж v1.7, яка доступна для використання, також перевірте документацію containerd щодо інформації про сумісність.

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

Вступ

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

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

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

Поля runAsUser, runAsGroup, fsGroup тощо в pod.spec завжди звертаються до користувача всередині контейнера.

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

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

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

Розуміння просторів користувачів для Podʼів

Кілька середовищ виконання контейнерів із їхньою типовою конфігурацією (таких як Docker Engine, containerd, CRI-O) використовують простори імен Linux для ізоляції. Існують інші технології, які також можна використовувати з цими середовищами (наприклад, Kata Containers використовує віртуальні машини замість просторів імен Linux). Ця стосується середовищ виконання контейнерів, які використовують простори імен Linux для ізоляції.

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

Це означає, що контейнери можуть працювати як root та зіставлятись з не-root користувачами на хості. Всередині контейнера процес буде вважати себе root (і, отже, інструменти типу apt, yum, ін. працюватимуть нормально), тоді як насправді процес не має привілеїв на хості. Ви можете перевірити це, наприклад, якщо ви перевірите, як користувач запущений у контейнері, виконавши 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:

# Формат такий
#   імʼя:першийID:кількість ідентифікаторів
# де
# - першийID - 65536 (мінімально можливt значення)
# - кількість ідентифікаторів - 110 (стандартний ліміт кількості) * 65536
kubelet:65536:7208960

Інтеграція з перевірками безпеки доступу в Podʼи

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.29 [alpha]

Для Podʼів Linux, які увімкнули простори користувачів, Kubernetes послаблює застосування Стандартів безпеки Podʼа контрольованим способом. Цю поведінку можна контролювати за допомогою функціональної можливості UserNamespacesPodSecurityStandards, що дозволяє раннє включення для кінцевих користувачів. Адміністраторам слід забезпечити увімкнення просторів користувачів на всіх вузлах в межах кластера при використанні feature gate.

Якщо ви увімкнете відповідний feature gate та створите Pod, який використовує простори користувачів, yfcnegys поля не будуть обмежені навіть в контекстах, які застосовують Baseline чи Restricted Podʼа. Це не становить проблему безпеки, оскільки 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ʼа заборонено використовувати інші простори імен хосту. Зокрема, якщо ви встановите hostUsers: false, ви не маєте права встановлювати будь-яке з наступного:

  • hostNetwork: true
  • hostIPC: true
  • hostPID: true

Що далі

8 - Downward API

Є два способи використання полів обʼєкта Pod та контейнера у працюючому контейнері: як змінні середовища та як файли, які заповнюються спеціальним типом тома. Разом ці два способи використання полів обʼєкта Pod та контейнера називають Downward API.

Іноді корисно, щоб контейнер мав інформацію про себе, не будучи занадто повʼязаним із Kubernetes. downward API дозволяє контейнерам використовувати інформацію про себе чи кластер, не використовуючи клієнт Kubernetes або API-сервер.

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

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

Разом ці два способи використання полів обʼєкта Pod та контейнера називають downward API.

Доступні поля

Через downward API доступні не всі поля обʼєкта Kubernetes API. У цьому розділі перераховано доступні поля.

Ви можете передавати інформацію з доступних полів рівня Pod, використовуючи fieldRef. На рівні API spec для Pod завжди визначає принаймні один Контейнер. Ви можете передавати інформацію з доступних полів рівня Container, використовуючи resourceFieldRef.

Інформація, доступна за допомогою fieldRef

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

metadata.name
імʼя Pod
metadata.namespace
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
імʼя service account 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

Наступна інформація доступна через том downwardAPI fieldRef, але не як змінні середовища:

metadata.labels
всі мітки Pod, в форматі label-key="escaped-label-value" з однією міткою на рядок
metadata.annotations
всі аннотації поду, у форматі annotation-key="escaped-annotation-value" з однією аннотацією на рядок

Інформація, доступна за допомогою resourceFieldRef

Ці поля рівня контейнера дозволяють надавати інформацію про вимоги та обмеження для ресурсів, таких як 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: