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

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

Налаштування Podʼів та контейнерів

Виконайте загальні завдання конфігурації для Pod і контейнерів.

1 - Виділення ресурсів памʼяті для контейнерів та Podʼів

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

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

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

Для перевірки версії введіть kubectl version.

Кожен вузол у вашому кластері повинен мати принаймні 300 МіБ памʼяті.

Деякі кроки на цій сторінці вимагають запуску служби metrics-server у вашому кластері. Якщо у вас запущено metrics-server, ви можете пропустити ці кроки.

Якщо ви використовуєте Minikube, виконайте таку команду, щоб увімкнути metrics-server:

minikube addons enable metrics-server

Щоб перевірити, чи запущений metrics-server, або інший постачальник API ресурсів метрик (metrics.k8s.io), виконайте таку команду:

kubectl get apiservices

Якщо API ресурсів метрик доступне, у виводі буде міститися посилання на metrics.k8s.io.

NAME
v1beta1.metrics.k8s.io

Створення простору імен

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

kubectl create namespace mem-example

Визначення запитів та лімітів памʼяті

Щоб вказати запит памʼяті для Контейнера, включіть поле resources:requests у маніфесті ресурсів Контейнера. Для вказівки ліміти памʼяті включіть resources:limits.

У цьому завданні ви створюєте Pod, який має один Контейнер. У Контейнера вказано запит памʼяті 100 МіБ і ліміти памʼяті 200 МіБ. Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Розділ args у файлі конфігурації надає аргументи для Контейнера при його запуску. Аргументи "--vm-bytes", "150M" вказують Контейнеру спробувати виділити 150 МіБ памʼяті.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example

Перевірте, що Контейнер Podʼа працює:

kubectl get pod memory-demo --namespace=mem-example

Перегляньте детальну інформацію про Pod:

kubectl get pod memory-demo --output=yaml --namespace=mem-example

Вивід показує, що один Контейнер у Podʼі має запит памʼяті 100 МіБ та ліміти памʼяті 200 МіБ.

...
resources:
  requests:
    memory: 100Mi
  limits:
    memory: 200Mi
...

Виконайте команду kubectl top, щоб отримати метрики для Podʼа:

kubectl top pod memory-demo --namespace=mem-example

Вивід показує, що Pod використовує приблизно 162,900,000 байт памʼяті, що становить близько 150 МіБ. Це більше, ніж запит Podʼа на 100 МіБ, але в межах ліміти Podʼа на 200 МіБ.

NAME                        CPU(cores)   MEMORY(bytes)
memory-demo                 <something>  162856960

Видаліть свій Pod:

kubectl delete pod memory-demo --namespace=mem-example

Перевищення лімітів памʼяті Контейнера

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

У цьому завданні ви створюєте Pod, який намагається виділити більше памʼяті, ніж його ліміт. Ось файл конфігурації для Podʼа, який має один Контейнер з запитом памʼяті 50 МіБ та лімітом памʼяті 100 МіБ:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

У розділі args файлу конфігурації видно, що Контейнер спробує використати 250 МіБ памʼяті, що значно перевищує ліміт в 100 МіБ.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

Перегляньте детальну інформацію про Pod:

kubectl get pod memory-demo-2 --namespace=mem-example

На цей момент Контейнер може працювати або бути знищеним. Повторіть попередню команду, доки Контейнер не буде знищено:

NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          24s

Отримайте більш детальний огляд стану Контейнера:

kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

Вивід показує, що Контейнер був знищений через вичерпання памʼяті (OOM):

lastState:
   terminated:
     containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
     exitCode: 137
     finishedAt: 2017-06-20T20:52:19Z
     reason: OOMKilled
     startedAt: null

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

kubectl get pod memory-demo-2 --namespace=mem-example

Вивід показує, що Контейнер знищується, перезапускається, знищується знову, знову перезапускається і так далі:

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          37s
kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-2   1/1       Running   2          40s

Перегляньте детальну інформацію про історію Podʼа:

kubectʼ describe pod лімітомo-2 ʼ-namespace=mem-example

Вивід показує, що Контейнер починається і знову не вдається:

... Normal  Created   Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff   Back-off restarting failed container

Перегляньте детальну інформацію про вузли вашого кластера:

kubectl describe nodes

Вивід містить запис про знищення Контейнера через умову вичерпання памʼяті:

Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

Видаліть свій Pod:

kubectl delete pod memory-demo-2 --namespace=mem-example

Визначення запиту памʼяті, що є завеликим для вашого вузла

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

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

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

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-3
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "1000Gi"
      limits:
        memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

Перегляньте статус Podʼа:

kubectl get pod memory-demo-3 --namespace=mem-example

Вивід показує, що статус Podʼа — PENDING. Це означає, що Pod не заплановано для запуску на жодному вузлі, і він залишатиметься у стані PENDING безстроково:

kubectl get pod memory-demo-3 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-3   0/1       Pending   0          25s

Перегляньте детальну інформацію про Pod, включаючи події:

kubectl describe pod memory-demo-3 --namespace=mem-example

Вивід показує, що Контейнер не може бути запланований через нестачу памʼяті на вузлах:

Events:
  ...  Reason            Message
       ------            -------
  ...  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient memory (3).

Одиниці памʼяті

Ресурс памʼяті вимірюється у байтах. Ви можете виразити памʼять як ціле число або ціле число з одним із наступних суфіксів: E, P, T, G, M, K, Ei, Pi, Ti, Gi, Mi, Ki. Наприклад, наступні значення приблизно однакові:

128974848, 129e6, 129M, 123Mi

Видаліть свій Pod:

kubectl delete pod memory-demo-3 --namespace=mem-example

Якщо ви не вказуєте ліміт памʼяті

Якщо ви не вказуєте ліміт памʼяті для Контейнера, відбувається одне з наступного:

  • Контейнер не має верхньої межі на кількість використаної памʼяті. Контейнер може використовувати всю доступну памʼять на вузлі, де він працює, що, своєю чергою, може спричинити активацію "OOM Killer". Крім того, в разі активації "OOM Kill" Контейнер без обмежень ресурсів матиме більше шансів на знищення.

  • Контейнер працює в просторі імен, який має стандартний ліміт памʼяті, і Контейнер автоматично отримує визначений стандартний ліміт. Адміністратори кластера можуть використовувати LimitRange для зазначення стандартного ліміту памʼяті.

Для чого вказувати запит та ліміт памʼяті

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

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

Очищення

Видаліть простір імен. Це видалить всі Podʼи, які ви створили для цього завдання:

kubectl delete namespace mem-example

Що далі

Для розробників застосунків #for-application-developers

Для адміністраторів кластера

2 - Виділення ресурсів CPU контейнерам та Podʼам

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

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

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

Для перевірки версії введіть kubectl version.

Кожен вузол у вашому кластері повинен мати принаймні 1 CPU.

Деякі кроки на цій сторінці вимагають запуску служби metrics-server у вашому кластері. Якщо у вас запущено metrics-server, ви можете пропустити ці кроки.

Якщо ви використовуєте Minikube, виконайте таку команду, щоб увімкнути metrics-server:

minikube addons enable metrics-server

Щоб перевірити, чи запущений metrics-server, або інший постачальник API ресурсів метрик (metrics.k8s.io), виконайте таку команду:

kubectl get apiservices

Якщо API ресурсів метрик доступне, у виводі буде міститися посилання на metrics.k8s.io.

NAME
v1beta1.metrics.k8s.io

Створення простору імен

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

kubectl create namespace cpu-example

Визначте запит ЦП та ліміт ЦП

Для вказання запиту ЦП для контейнера включіть поле resources:requests в маніфест ресурсів Контейнера. Щоб вказати ліміт ЦП, включіть resources:limits.

У цьому завданні ви створюєте Pod, у якого є один контейнер. Контейнер має запит на 0,5 CPU та ліміт 1 CPU. Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
  namespace: cpu-example
spec:
  containers:
  - name: cpu-demo-ctr
    image: vish/stress
    resources:
      limits:
        cpu: "1"
      requests:
        cpu: "0.5"
    args:
    - -cpus
    - "2"

Секція args у файлі конфігурації надає аргументи для контейнера при його запуску. Аргумент -cpus "2" каже Контейнеру спробувати використовувати 2 CPU.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit.yaml --namespace=cpu-example

Перевірте, що Pod працює:

kubectl get pod cpu-demo --namespace=cpu-example

Перегляньте детальну інформацію про Pod:

kubectl get pod cpu-demo --output=yaml --namespace=cpu-example

Вивід показує, що один контейнер у Podʼі має запит ЦП 500 міліCPU та ліміт ЦП 1 CPU.

resources:
  limits:
    cpu: "1"
  requests:
    cpu: 500m

Використовуйте kubectl top, щоб отримати метрики для Podʼа:

kubectl top pod cpu-demo --namespace=cpu-example

У цьому прикладі виводу показано, що Pod використовує 974 міліCPU, що незначно менше, ніж ліміт 1 CPU, вказане в конфігурації Podʼа.

NAME                        CPU(cores)   MEMORY(bytes)
cpu-demo                    974m         <something>

Нагадуємо, що, встановивши -cpu "2", ви налаштували контейнер на спробу використати 2 CPU, але контейнер може використовувати лише близько 1 CPU. Використання ЦП контейнером обмежується, оскільки контейнер намагається використовувати більше ресурсів ЦП, ніж його ліміт.

Одиниці ЦП

Ресурс ЦП вимірюється в одиницях ЦП. Одна одиниця ЦП в Kubernetes еквівалентна:

  • 1 AWS vCPU
  • 1 GCP Core
  • 1 Azure vCore
  • 1 Hyperthread на процесорі Intel з гіперпотоками

Дозволені дробові значення. Контейнер, який запитує 0,5 ЦП, гарантовано отримує половину ЦП порівняно з контейнером, який запитує 1 ЦП. Ви можете використовувати суфікс m для позначення мілі. Наприклад, 100m ЦП, 100 міліЦП і 0,1 ЦП — це все одне й те саме. Точність, більша за 1m, не допускається.

ЦП завжди запитується як абсолютна кількість, ніколи як відносна кількість; 0.1 — це та сама кількість ЦП на одноядерному, двоядерному або 48-ядерному компʼютері.

Видаліть свій Pod:

kubectl delete pod cpu-demo --namespace=cpu-example

Визначте запит ЦП, який перевищує можливості ваших вузлів

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

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

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

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo-2
  namespace: cpu-example
spec:
  containers:
  - name: cpu-demo-ctr-2
    image: vish/stress
    resources:
      limits:
        cpu: "100"
      requests:
        cpu: "100"
    args:
    - -cpus
    - "2"

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/cpu-request-limit-2.yaml --namespace=cpu-example

Перегляньте статус Podʼа:

kubectl get pod cpu-demo-2 --namespace=cpu-example

Вивід показує, що статус Podʼа — Pending. Тобто Pod не був запланований для запуску на будь-якому вузлі, і він буде залишатися в стані Pending нескінченно:

NAME         READY     STATUS    RESTARTS   AGE
cpu-demo-2   0/1       Pending   0          7m

Перегляньте детальну інформацію про Pod, включаючи події:

kubectl describe pod cpu-demo-2 --namespace=cpu-example

Вивід показує, що контейнер не може бути запланований через недостатні ресурси ЦП на вузлах:

Events:
  Reason                        Message
  ------                        -------
  FailedScheduling      No nodes are available that match all of the following predicates:: Insufficient cpu (3).

Видаліть свій Pod:

kubectl delete pod cpu-demo-2 --namespace=cpu-example

Якщо ви не вказуєте ліміт ЦП

Якщо ви не вказуєте ліміт ЦП для контейнера, то застосовується одне з наступного:

  • Контейнер не має верхньої межі ресурсів ЦП, які він може використовувати. Контейнер може використовувати всі доступні ресурси ЦП на вузлі, на якому він працює.

  • Контейнер працює в просторі імен, який має стандартний ліміт ЦП, і контейнеру автоматично призначається цей стандартний ліміт. Адміністратори кластера можуть використовувати LimitRange для зазначення стандартних значень лімітів ЦП.

Якщо ви вказуєте ліміт ЦП, але не вказуєте запит ЦП

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

Для чого вказувати запит та ліміт ЦП

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

  • Pod може мати періоди підвищеної активності, коли він використовує доступні ресурси ЦП.
  • Кількість ресурсів ЦП, які Pod може використовувати під час такої активності, обмежена розумною кількістю.

Очищення

Видаліть ваш простір імен:

kubectl delete namespace cpu-example

Що далі

Для розробників застосунків

Для адміністраторів кластерів

3 - Надання ресурсів CPU та памʼяті на рівні Podʼів

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

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

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

Щоб вказати ресурси на рівні podʼа, необхідно увімкнути функціональну можливість PodLevelResources.

Для ресурсів на рівні Podʼа:

  • Пріоритет: Коли вказані як ресурси на рівні podʼа, так і на рівні контейнера, ресурси на рівні podʼа мають пріоритет.
  • QoS: Ресурси на рівні podʼа мають пріоритет у впливі на клас QoS podʼа.
  • OOM Score: Розрахунок коригування OOM score враховує як ресурси на рівні podʼа, так і на рівні контейнера.
  • Сумісність: Ресурси на рівні pod розроблені для сумісності з наявними функціями.

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

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

Версія вашого Kubernetes сервера має бути не старішою ніж 1.32. Для перевірки версії введіть kubectl version.

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

Створіть простір імен

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

kubectl create namespace pod-resources-example

Створіть pod із запитами та лімітами памʼяті на рівні podʼа

Щоб вказати запити памʼяті для pod на рівні podʼа, включіть поле resources.requests.memory у маніфест pod. Щоб вказати ліміт памʼяті, включіть resources.limits.memory.

У цій вправі ви створюєте pod, який має один контейнер. Pod має запит памʼяті 100 MiB і ліміт памʼяті 200 MiB. Ось конфігураційний файл для podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: pod-resources-example
spec:
  resources:
    requests:
      memory: "100Mi"
    limits:
      memory: "200Mi"
  containers:
  - name: memory-demo-ctr
    image: nginx
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

Розділ args у маніфесті надає аргументи для контейнера під час його запуску. Аргументи "--vm-bytes", "150M" вказують контейнеру спробувати виділити 150 MiB памʼаяті.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-memory-request-limit.yaml --namespace=pod-resources-example

Перевірте, що Pod працює:

kubectl get pod memory-demo --namespace=pod-resources-example

Перегляньте детальну інформацію про Pod:

kubectl get pod memory-demo --output=yaml --namespace=pod-resources-example

Вивід показує, що Pod має запит памʼяті 100 MiB і ліміт памʼяті 200 MiB.

...
spec:
  containers:
  ...
  resources:
    requests:
      memory: 100Mi
    limits:
      memory: 200Mi
...

Запустіть kubectl top, щоб отримати метрики для pod:

kubectl top pod memory-demo --namespace=pod-resources-example

Вивід показує, що Pod використовує близько 162,900,000 байтів памʼяті, що становить близько 150 MiB. Це більше, ніж запит Pod у 100 MiB, але в межах ліміту Pod у 200 MiB.

NAME                        CPU(cores)   MEMORY(bytes)
memory-demo                 <something>  162856960

Створіть pod із запитами та лімітами CPU на рівні podʼа

Щоб вказати запит CPU для Pod, включіть поле resources.requests.cpu у маніфест Pod. Щоб вказати ліміт CPU, включіть resources.limits.cpu.

У цій вправі ви створюєте Pod, який має один контейнер. Pod має запит 0.5 CPU і ліміт 1 CPU. Ось конфігураційний файл для Pod:

apiVersion: v1
kind: Pod
metadata:
  name: cpu-demo
  namespace: pod-resources-example
spec:
  resources:
    limits:
      cpu: "1"
    requests:
      cpu: "0.5"
  containers:
  - name: cpu-demo-ctr
    image: vish/stress
    args:
    - -cpus
    - "2"

Розділ args конфігураційного файлу надає аргументи для контейнера під час його запуску. Аргумент -cpus "2" вказує контейнеру спробувати використовувати 2 CPU.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-cpu-request-limit.yaml --namespace=pod-resources-example

Перевірте, що Pod працює:

kubectl get pod cpu-demo --namespace=pod-resources-example

Перегляньте детальну інформацію про Pod:

kubectl get pod cpu-demo --output=yaml --namespace=pod-resources-example

Вивід показує, що Pod має запит CPU 500 milliCPU і ліміт CPU 1 CPU.

spec:
  containers:
  ...
  resources:
    limits:
      cpu: "1"
    requests:
      cpu: 500m

Використовуйте kubectl top, щоб отримати метрики для Pod:

kubectl top pod cpu-demo --namespace=pod-resources-example

Цей приклад виходу показує, що Pod використовує 974 milliCPU, що трохи менше ліміту 1 CPU, вказаного в конфігурації Pod.

NAME                        CPU(cores)   MEMORY(bytes)
cpu-demo                    974m         <something>

Нагадаємо, що встановивши -cpu "2", ви налаштували контейнер на спробу використовувати 2 CPU, але контейнеру дозволено використовувати лише близько 1 CPU. Використання CPU контейнера обмежується, оскільки контейнер намагається використовувати більше ресурсів CPU, ніж ліміт CPU Pod.

Створіть pod із запитами та лімітами ресурсів як на рівні podʼа, так і на рівні контейнера

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

У цій вправі ви створите Pod із двома контейнерами, щоб дослідити взаємодію специфікацій ресурсів на рівні podʼа і контейнера. Сам Pod матиме визначені запити та ліміти CPU, тоді як лише один із контейнерів матиме власні явні запити та ліміти ресурсів. Інший контейнер успадкує обмеження ресурсів від налаштувань на рівні podʼа. Ось конфігураційний файл для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: pod-resources-demo
  namespace: pod-resources-example
spec:
  resources:
    limits:
      cpu: "1"
      memory: "200Mi"
    requests:
      cpu: "1"
      memory: "100Mi"
  containers:
  - name: pod-resources-demo-ctr-1
    image: nginx
    resources:
      limits:
        cpu: "0.5"
        memory: "100Mi"
      requests:
        cpu: "0.5"
        memory: "50Mi"
  - name: pod-resources-demo-ctr-2
    image: fedora
    command:
    - sleep
    - inf 

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/pod-level-resources.yaml --namespace=pod-resources-example

Перевірте, що контейнер Podʼа працює:

kubectl get pod-resources-demo --namespace=pod-resources-example

Перегляньте детальну інформацію про Pod:

kubectl get pod memory-demo --output=yaml --namespace=pod-resources-example

Вивід показує, що один контейнер у Pod має запит памʼяті 50 MiB і запит CPU 0.5 ядер, з лімітом памʼяті 100 MiB і лімітом CPU 0.5 ядер. Сам Pod має запит памʼяті 100 MiB і запит CPU 1 ядро, і ліміт памʼяті 200 MiB і ліміт CPU 1 ядро.

...
containers:
  name: pod-resources-demo-ctr-1
  resources:
      requests:
        cpu: 500m
        memory: 50Mi
      limits:
        cpu: 500m
        memory: 100Mi
  ...
  name: pod-resources-demo-ctr-2
  resources: {}
resources:
  limits:
      cpu: 1
      memory: 200Mi
    requests:
      cpu: 1
      memory: 100Mi
...

Оскільки вказані запити та ліміти на рівні podʼа, гарантії запитів для обох контейнерів у podʼі будуть рівні 1 ядру CPU та 100Mi памʼяті. Крім того, обидва контейнери разом не зможуть використовувати більше ресурсів, ніж вказано в лімітах на рівні podʼа, забезпечуючи, що вони не можуть перевищити загальну суму 200 MiB памʼяті та 1 ядро CPU.

Очищення

Видаліть простір імен:

kubectl delete namespace pod-resources-example

Що далі

Для розробників застосунків

Для адміністраторів кластера

4 - Налаштування GMSA для Windows Podʼів та контейнерів

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

Ця сторінка показує, як налаштувати Group Managed Service Accounts (GMSA) для Podʼів та контейнерів, які будуть запущені на вузлах Windows. Group Managed Service Accounts це специфічний тип облікового запису Active Directory, який забезпечує автоматичне управління паролями, спрощене управління іменами служб (SPN) та можливість делегування управління іншим адміністраторам на кількох серверах.

У Kubernetes специфікації облікових даних GMSA налаштовуються на рівні кластера Kubernetes як Custom Resources. Windows Podʼи, також як і окремі контейнери в Podʼі, можуть бути налаштовані для використання GMSA для доменних функцій (наприклад, автентифікація Kerberos) при взаємодії з іншими службами Windows.

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

Вам необхідно мати кластер Kubernetes і інструмент командного рядка kubectl, налаштований для керування з вашим кластером. Очікується, що в кластері будуть вузли Windows. Цей розділ охоплює набір початкових кроків, необхідних один раз для кожного кластера:

Встановлення CRD для GMSACredentialSpec

CustomResourceDefinition(CRD) для ресурсів специфікації облікових даних GMSA потрібно налаштувати на кластері, щоб визначити тип настроюваного ресурсу GMSACredentialSpec. Завантажте GMSA CRD YAML і збережіть як gmsa-crd.yaml. Далі встановіть CRD за допомогою kubectl apply -f gmsa-crd.yaml.

Встановлення вебхуків для перевірки користувачів GMSA

Два вебхуки потрібно налаштувати на кластері Kubernetes для заповнення та перевірки посилань на специфікації облікових даних GMSA на рівні Podʼа або контейнера:

  1. Модифікаційний вебхук, який розширює посилання на GMSAs (за іменем зі специфікації Podʼа) до повної специфікації облікових даних у форматі JSON у специфікації Podʼа.

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

Встановлення зазначених вище вебхуків та повʼязаних обʼєктів вимагає наступних кроків:

  1. Створіть пару ключів сертифікатів (яка буде використовуватися для забезпечення звʼязку контейнера вебхука з кластером)

  2. Встановіть Secret із вищезазначеним сертифікатом.

  3. Створіть Deployment для основної логіки вебхука.

  4. Створіть конфігурації валідаційного та модифікаційного вебхуків, посилаючись на Deployment.

Скрипт можна використовувати для розгортання та налаштування вебхуків GMSA та повʼязаних з ними обʼєктів, зазначених вище. Скрипт можна запускати з опцією --dry-run=server, щоб ви могли переглянути зміни, які будуть внесені в ваш кластер.

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

Налаштування GMSA та вузлів Windows в Active Directory

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

Створення ресурсів GMSA Credential Spec

Після встановлення CRD GMSACredentialSpec (як описано раніше), можна налаштувати власні ресурси, що містять специфікації облікових даних GMSA. Специфікація облікових даних GMSA не містить конфіденційні або секретні дані. Це інформація, яку контейнерне середовище може використовувати для опису бажаної GMSA контейнера для Windows. Специфікації облікових даних GMSA можуть бути створені у форматі YAML за допомогою утиліти сценарію PowerShell.

Ось кроки для створення YAML-файлу специфікації облікових даних GMSA вручну у форматі JSON і подальше його конвертування:

  1. Імпортуйте модуль CredentialSpec module: ipmo CredentialSpec.psm1.

  2. Створіть специфікацію облікових даних у форматі JSON за допомогою команди New-CredentialSpec. Щоб створити специфікацію облікових даних GMSA з іменем WebApp1, викличте New-CredentialSpec -Name WebApp1 -AccountName WebApp1 -Domain $(Get-ADDomain -Current LocalComputer).

  3. Використайте команду Get-CredentialSpec, щоб показати шлях до файлу JSON.

  4. Конвертуйте файл credspec з формату JSON у YAML та застосуйте необхідні заголовкові поля apiVersion, kind, metadata та credspec, щоб зробити його специфікацією GMSACredentialSpec, яку можна налаштувати в Kubernetes.

Наступна конфігурація YAML описує специфікацію облікових даних GMSA з іменем gmsa-WebApp1:

apiVersion: windows.k8s.io/v1
kind: GMSACredentialSpec
metadata:
  name: gmsa-WebApp1  # Це довільне імʼя, але воно буде використовуватися як посилання
credspec:
  ActiveDirectoryConfig:
    GroupManagedServiceAccounts:
    - Name: WebApp1   # Імʼя користувача облікового запису GMSA
      Scope: CONTOSO  # Імʼя домену NETBIOS
    - Name: WebApp1   # Імʼя користувача облікового запису GMSA
      Scope: contoso.com # Імʼя домену DNS
  CmsPlugins:
  - ActiveDirectory
  DomainJoinConfig:
    DnsName: contoso.com  # Імʼя домену DNS
    DnsTreeName: contoso.com # Корінь імені домену DNS
    Guid: 244818ae-87ac-4fcd-92ec-e79e5252348a  # GUID для Domain
    MachineAccountName: WebApp1 # Імʼя користувача облікового запису GMSA
    NetBiosName: CONTOSO  # Імʼя домену NETBIOS
    Sid: S-1-5-21-2126449477-2524075714-3094792973 # SID для Domain

Вищезазначений ресурс специфікації облікових даних може бути збережений як gmsa-Webapp1-credspec.yaml і застосований до кластера за допомогою: kubectl apply -f gmsa-Webapp1-credspec.yaml.

Налаштування ролі кластера для включення RBAC у конкретні специфікації облікових даних GMSA

Для кожного ресурсу специфікації облікових даних GMSA потрібно визначити роль в кластері. Це авторизує дію use ("використовувати") на конкретному ресурсі GMSA певним субʼєктом, який, як правило, є службовим обліковим записом. Наведений нижче приклад показує роль в кластері, яка авторизує використання специфікації облікових даних gmsa-WebApp1 зверху. Збережіть файл як gmsa-webapp1-role.yaml і застосуйте його за допомогою kubectl apply -f gmsa-webapp1-role.yaml.

# Створення ролі для читання credspec
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: webapp1-role
rules:
- apiGroups: ["windows.k8s.io"]
  resources: ["gmsacredentialspecs"]
  verbs: ["use"]
  resourceNames: ["gmsa-WebApp1"]

Призначення ролі службовому обліковому запису для використання конкретних специфікацій облікових даних GMSA

Службовий обліковий запис (з якими будуть налаштовані Podʼи) повинен бути привʼязаний до ролі в кластері, створеної вище. Це авторизує службовий обліковий запис використовувати бажаний ресурс специфікації облікових даних GMSA. Нижче показано, як стандартний службовий обліковий запис привʼязується до ролі в кластера webapp1-role для використання ресурсу специфікації облікових даних gmsa-WebApp1, створеного вище.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: allow-default-svc-account-read-on-gmsa-WebApp1
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: ClusterRole
  name: webapp1-role
  apiGroup: rbac.authorization.k8s.io

Налаштування посилання на специфікацію облікових даних GMSA в специфікації Pod

Поле securityContext.windowsOptions.gmsaCredentialSpecName у специфікації Pod використовується для вказівки посилань на бажані ресурси специфікації облікових даних GMSA в специфікаціях Pod. Це налаштовує всі контейнери в специфікації Pod на використання вказаного GMSA. Нижче наведено приклад специфікації Pod з анотацією, заповненою для посилання на gmsa-WebApp1:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      securityContext:
        windowsOptions:
          gmsaCredentialSpecName: gmsa-webapp1
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
      nodeSelector:
        kubernetes.io/os: windows

Індивідуальні контейнери в специфікації Pod також можуть вказати бажану специфікацію облікових даних GMSA, використовуючи поле securityContext.windowsOptions.gmsaCredentialSpecName на рівні окремого контейнера. Наприклад:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: with-creds
  name: with-creds
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: with-creds
  template:
    metadata:
      labels:
        run: with-creds
    spec:
      containers:
      - image: mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019
        imagePullPolicy: Always
        name: iis
        securityContext:
          windowsOptions:
            gmsaCredentialSpecName: gmsa-Webapp1
      nodeSelector:
        kubernetes.io/os: windows

Під час застосування специфікацій Pod з заповненими полями GMSA (як описано вище) в кластері відбувається наступна послідовність подій:

  1. Модифікаційний вебхук розвʼязує та розширює всі посилання на ресурси специфікації облікових даних GMSA до вмісту специфікації облікових даних GMSA.

  2. Валідаційний вебхук переконується, що обліковий запис служби, повʼязаний з Pod, авторизований для дії use на вказаній специфікації облікових даних GMSA.

  3. Контейнерне середовище налаштовує кожен контейнер Windows із вказаною специфікацією облікових даних GMSA, щоб контейнер міг прийняти елемент GMSA в Active Directory та отримати доступ до служб в домені, використовуючи цей елемент.

Автентифікація на мережевих ресурсах за допомогою імені хосту або повного доменного імені

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

reg add "HKLM\SYSTEM\CurrentControlSet\Services\hns\State" /v EnableCompartmentNamespace /t REG_DWORD /d 1

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

Усунення несправностей

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

Спочатку переконайтеся, що credspec був переданий до Podʼа. Для цього вам потрібно виконати команду exec в одному з ваших Podʼів і перевірити вивід команди nltest.exe /parentdomain.

У наступному прикладі Pod не отримав credspec правильно:

kubectl exec -it iis-auth-7776966999-n5nzr powershell.exe

Результат команди nltest.exe /parentdomain показує наступну помилку:

Getting parent domain failed: Status = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

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

Це дозволить нам визначити 3 речі:

  1. Pod може досягти контролера домену (DC).
  2. Контролер домену (DC) може досягти Podʼа.
  3. DNS працює правильно.

Якщо тест DNS та комунікації успішний, наступним буде перевірка, чи Pod встановив захищений канал звʼязку з доменом. Для цього, знову ж таки, виконайте команду exec в вашому Podʼі та запустіть команду nltest.exe /query.

nltest.exe /query

Результат буде наступним:

I_NetLogonControl failed: Статус = 1722 0x6ba RPC_S_SERVER_UNAVAILABLE

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

nltest /sc_reset:domain.example

Якщо команда успішна, ви побачите подібний вивід:

Flags: 30 HAS_IP  HAS_TIMESERV
Trusted DC Name \\dc10.domain.example
Trusted DC Connection Status Status = 0 0x0 NERR_Success
The command completed successfully

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

        image: registry.domain.example/iis-auth:1809v1
        lifecycle:
          postStart:
            exec:
              command: ["powershell.exe","-command","do { Restart-Service -Name netlogon } while ( $($Result = (nltest.exe /query); if ($Result -like '*0x0 NERR_Success*') {return $true} else {return $false}) -eq $false)"]
        imagePullPolicy: IfNotPresent

Якщо ви додасте розділ lifecycle до специфікації вашого Podʼа, Pod виконає вказані команди для перезапуску служби netlogon до того, як команда nltest.exe /query вийде без помилок.

5 - Зміна обсягів CPU та памʼяті, призначених для контейнерів

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

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

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

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

Запит на зміну розміру виконується через підресурс pod /resize, який отримує повністю оновлений pod для запиту на оновлення, або патч на обʼєкті pod для запиту на виправлення.

Для зміни ресурсів Podʼа на місці:

  • Ресурси запитів та лімітів контейнера є змінними для ресурсів CPU та памʼяті. Ці поля представляють бажані ресурси для контейнера.
  • Поле resources у containerStatuses статусу Podʼа відображає фактичні ресурси requests та limits, які виділені для контейнерів podʼів. Для запущених контейнерів це відображає фактичні ресурси requests і limits контейнерів, це ресурси, виділені для контейнера під час його запуску. Для не запущених контейнерів це ресурси, виділені для контейнера під час його запуску.
  • Поле resize у статусі Podʼа показує статус останнього запиту очікуваної зміни розміру. Воно може мати наступні значення:
    • Proposed: Це значення вказує на те, що розмір podʼа було змінено, але Kubelet ще не обробив зміну розміру.
    • InProgress: Це значення вказує, що вузол прийняв запит на зміну розміру та знаходиться у процесі застосування його до контейнерів Podʼа.
    • Deferred: Це значення означає, що запитаної зміни розміру наразі не можна виконати, і вузол буде спробувати її виконати пізніше. Зміна розміру може бути виконана, коли інші Podʼи будуть вилучені та звільнять ресурси вузла.
    • Infeasible: це сигнал того, що вузол не може задовольнити запит на зміну розміру. Це може статися, якщо запит на зміну розміру перевищує максимальні ресурси, які вузол може виділити для Podʼа.
    • "": Порожнє або не встановлене значення вказує на те, що останню зміну розміру завершено. Це має відбуватися лише у випадку, якщо ресурси у специфікації контейнера збігаються з ресурсами у статусі контейнера.

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

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

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

Версія вашого Kubernetes сервера має бути не старішою ніж 1.27. Для перевірки версії введіть kubectl version.

Має бути увімкнено функціональну можливість InPlacePodVerticalScaling для вашої панелі управління і для всіх вузлів вашого кластера.

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

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

Для активації цього користувачам дозволяється вказати resizePolicy у специфікації контейнера. Наступні політики перезапуску можна вказати для зміни розміру CPU та памʼяті:

  • NotRequired: Змінити ресурси контейнера під час його роботи.
  • RestartContainer: Перезапустити контейнер та застосувати нові ресурси після перезапуску.

Якщо resizePolicy[*].restartPolicy не вказано, воно стандартно встановлюється в NotRequired.

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

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-5
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr-5
    image: nginx
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired
    - resourceName: memory
      restartPolicy: RestartContainer
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

Обмеження

Зміна розміру ресурсів на місці наразі має наступні обмеження:

  • Можна змінити лише ресурси процесора та памʼяті.
  • Клас QoS не може бути змінений. Це означає, що запити повинні продовжувати дорівнювати лімітам для Guaranteed podʼам, Burstable podʼам не можуть встановлювати запити і ліміти рівними для CPU і памʼяті, і ви не можете додавати вимоги до ресурсів для Best Effort podʼів.
  • Init-контейнери та Ефемерні контейнери не можуть бути змінені за розміром.
  • Вимоги до ресурсів та ліміти не можна видалити після встановлення.
  • Ліміт памʼяті контейнера не може бути зменшений нижче рівня його використання. Якщо запит переводить контейнер у цей стан, статус зміни розміру залишатиметься у стані InProgress доти, доки бажаний ліміт памʼяті не стане можливим.
  • Розмір Windows-podʼів не може бути змінений.

Створення Podʼа із запитами та лімітами ресурсів

Ви можете створити Guaranteed або Burstable клас якості обслуговування Podʼу, вказавши запити та/або ліміти для контейнерів Podʼа.

Розгляньте наступний маніфест для Podʼа, який має один контейнер.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-5
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr-5
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

Створіть Pod у просторі імен qos-example:

kubectl create namespace qos-example
kubectl create -f https://k8s.io/examples/pods/qos/qos-pod-5.yaml

Цей Pod класифікується як Pod класу якості обслуговування Guaranteed, і має запит 700 мілі CPU та 200 мегабайтів памʼяті.

Перегляньте детальну інформацію про Pod:

kubectl get pod qos-demo-5 --output=yaml --namespace=qos-example

Також погляньте, що значення resizePolicy[*].restartPolicy типово встановлено в NotRequired, що вказує, що CPU та памʼять можна змінити, поки контейнер працює.

spec:
  containers:
    ...
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired
    - resourceName: memory
      restartPolicy: NotRequired
    resources:
      limits:
        cpu: 700m
        memory: 200Mi
      requests:
        cpu: 700m
        memory: 200Mi
...
  containerStatuses:
...
    name: qos-demo-ctr-5
    ready: true
...
    resources:
      limits:
        cpu: 700m
        memory: 200Mi
      requests:
        cpu: 700m
        memory: 200Mi
    restartCount: 0
    started: true
...
  qosClass: Guaranteed

Оновлення ресурсів Podʼа

Скажімо, вимоги до CPU зросли, і тепер потрібно 0.8 CPU. Це можна вказати вручну, або визначити і застосувати програмно, наприклад, за допомогою таких засобів, як VerticalPodAutoscaler (VPA).

Тепер відредагуйте контейнер Podʼа, встановивши як запити, так і ліміти CPU на 800m:

kubectl -n qos-example patch pod qos-demo-5 --subresource resize --patch '{"spec":{"containers":[{"name":"qos-demo-ctr-5", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'

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

kubectl get pod qos-demo-5 --output=yaml --namespace=qos-example

Специфікація Podʼа нижче показує оновлені запити та ліміти CPU.

spec:
  containers:
    ...
    resources:
      limits:
        cpu: 800m
        memory: 200Mi
      requests:
        cpu: 800m
        memory: 200Mi
...
  containerStatuses:
...
    resources:
      limits:
        cpu: 800m
        memory: 200Mi
      requests:
        cpu: 800m
        memory: 200Mi
    restartCount: 0
    started: true

Зверніть увагу, що resources у containerStatuses було оновлено, щоб відобразити нові бажані запити на CPU. Це вказує на те, що вузол зміг задовольнити збільшені потреби у ресурсах CPU, і нові ресурси CPU було застосовано. Параметр restartCount контейнера залишився незмінним, що вказує на те, що розмір ресурсів CPU контейнера було змінено без перезапуску контейнера.

Очищення

Видаліть ваш простір імен:

kubectl delete namespace qos-example

Для розробників застосунків

Для адміністраторів кластерів

6 - Налаштування RunAsUserName для Podʼів та контейнерів Windows

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

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

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

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

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

Щоб вказати імʼя користувача, з яким потрібно виконати процеси контейнера Podʼа, включіть поле securityContext (PodSecurityContext) в специфікацію Podʼа, а всередині нього — поле windowsOptions (WindowsSecurityContextOptions), що містить поле runAsUserName.

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

Ось конфігураційний файл для Podʼа Windows зі встановленим полем runAsUserName:

apiVersion: v1
kind: Pod
metadata:
  name: run-as-username-pod-demo
spec:
  securityContext:
    windowsOptions:
      runAsUserName: "ContainerUser"
  containers:
  - name: run-as-username-demo
    image: mcr.microsoft.com/windows/servercore:ltsc2019
    command: ["ping", "-t", "localhost"]
  nodeSelector:
    kubernetes.io/os: windows

Створіть Pod:

kubectl apply -f https://k8s.io/examples/windows/run-as-username-pod.yaml

Перевірте, що Контейнер Podʼа працює:

kubectl get pod run-as-username-pod-demo

Отримайте доступ до оболонки контейнера:

kubectl exec -it run-as-username-pod-demo -- powershell

Перевірте, що оболонка працює від імені відповідного користувача:

echo $env:USERNAME

Вивід повинен бути:

ContainerUser

Встановлення імені користувача для контейнера

Щоб вказати імʼя користувача, з яким потрібно виконати процеси контейнера, включіть поле securityContext (SecurityContext) у маніфесті контейнера, а всередині нього — поле windowsOptions (WindowsSecurityContextOptions), що містить поле runAsUserName.

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

Ось конфігураційний файл для Podʼа, який має один Контейнер, а поле runAsUserName встановлене на рівні Podʼа та на рівні Контейнера:

apiVersion: v1
kind: Pod
metadata:
  name: run-as-username-container-demo
spec:
  securityContext:
    windowsOptions:
      runAsUserName: "ContainerUser"
  containers:
  - name: run-as-username-demo
    image: mcr.microsoft.com/windows/servercore:ltsc2019
    command: ["ping", "-t", "localhost"]
    securityContext:
        windowsOptions:
            runAsUserName: "ContainerAdministrator"
  nodeSelector:
    kubernetes.io/os: windows

Створіть Pod:

kubectl apply -f https://k8s.io/examples/windows/run-as-username-container.yaml

Перевірте, що Контейнер Podʼа працює:

kubectl get pod run-as-username-container-demo

Отримайте доступ до оболонки контейнера:

kubectl exec -it run-as-username-container-demo -- powershell

Перевірте, що оболонка працює від імені відповідного користувача (того, який встановлений на рівні контейнера):

echo $env:USERNAME

Вивід повинен бути:

ContainerAdministrator

Обмеження імен користувачів Windows

Для використання цієї функції значення, встановлене у полі runAsUserName, повинно бути дійсним імʼям користувача. Воно повинно мати наступний формат: DOMAIN\USER, де DOMAIN\ є необовʼязковим. Імена користувачів Windows регістронезалежні. Крім того, існують деякі обмеження стосовно DOMAIN та USER:

  • Поле runAsUserName не може бути порожнім і не може містити керуючі символи (ASCII значення: 0x00-0x1F, 0x7F)
  • DOMAIN може бути або NetBios-імʼям, або DNS-імʼям, кожне з власними обмеженнями:
    • NetBios імена: максимум 15 символів, не можуть починатися з . (крапка), і не можуть містити наступні символи: \ / : * ? " < > |
    • DNS-імена: максимум 255 символів, містять тільки буквено-цифрові символи, крапки та дефіси, і не можуть починатися або закінчуватися . (крапка) або - (дефіс).
  • USER може мати не більше 20 символів, не може містити тільки крапки або пробіли, і не може містити наступні символи: " / \ [ ] : ; | = , + * ? < > @.

Приклади припустимих значень для поля runAsUserName: ContainerAdministrator, ContainerUser, NT AUTHORITY\NETWORK SERVICE, NT AUTHORITY\LOCAL SERVICE.

Для отримання додаткової інформації про ці обмеження, перевірте тут та тут.

Що далі

7 - Створення Podʼа Windows HostProcess

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

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

Адміністративні завдання, такі як встановлення патчів безпеки, збір подій логів тощо, можна виконувати без потреби входу операторів кластера на кожен вузол Windows. Контейнери HostProcess можуть працювати як будь-який користувач, що доступний на хості або в домені машини хосту, що дозволяє адміністраторам обмежити доступ до ресурсів через дозволи користувача. Хоча і не підтримуються ізоляція файлової системи або процесу, при запуску контейнера на хості створюється новий том, щоб надати йому чисте та обʼєднане робоче середовище. Контейнери HostProcess також можуть бути побудовані на базі наявних образів базової системи Windows і не успадковують ті ж вимоги сумісності як контейнери Windows server, що означає, що версія базового образу не повинна відповідати версії хосту. Однак рекомендується використовувати ту ж версію базового образу, що й ваші робочі навантаження контейнерів Windows Server, щоб уникнути зайвого використання місця на вузлі. Контейнери HostProcess також підтримують монтування томів всередині тома контейнера.

Коли варто використовувати контейнери Windows HostProcess?

  • Коли потрібно виконати завдання, які потребують мережевого простору імен хосту. Контейнери HostProcess мають доступ до мережевих інтерфейсів хосту та IP-адрес.
  • Вам потрібен доступ до ресурсів на хості, таких як файлова система, події логів тощо.
  • Встановлення конкретних драйверів пристроїв або служб Windows.
  • Обʼєднання адміністративних завдань та політик безпеки. Це зменшує ступінь привілеїв, які потрібні вузлам Windows.

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

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

У Kubernetes 1.32 контейнери HostProcess є типово увімкненими. kubelet буде спілкуватися з containerd безпосередньо, передаючи прапорець hostprocess через CRI. Ви можете використовувати останню версію containerd (v1.6+) для запуску контейнерів HostProcess. Як встановити containerd.

Обмеження

Ці обмеження стосуються Kubernetes v1.32:

  • Контейнери HostProcess вимагають середовища виконання контейнерів containerd 1.6 або вище, рекомендується використовувати containerd 1.7.
  • Podʼи HostProcess можуть містити лише контейнери HostProcess. Це поточне обмеження ОС Windows; непривілейовані контейнери Windows не можуть спільно використовувати vNIC з простором імен IP хосту.
  • Контейнери HostProcess запускаються як процес на хості та не мають жодного рівня ізоляції, окрім обмежень ресурсів, накладених на обліковий запис користувача HostProcess. Ізоляція ні файлової системи, ні ізоляції Hyper-V не підтримуються для контейнерів HostProcess.
  • Монтування томів підтримуються і монтуватимуться як томом контейнера. Див. Монтування томів
  • Стандартно для контейнерів HostProcess доступний обмежений набір облікових записів користувачів хосту. Див. Вибір облікового запису користувача.
  • Обмеження ресурсів (диск, памʼять, кількість процесорів) підтримуються так само як і процеси на хості.
  • Як іменовані канали, так і сокети Unix-домену не підтримуються і замість цього слід отримувати доступ до них через їх шлях на хості (наприклад, \\.\pipe\*)

Вимоги до конфігурації HostProcess Pod

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

Під час роботи з привілейованою політикою, ось конфігурації, які потрібно встановити для активації створення HostProcess Pod:

Специфікація привілейованої політики
ЕлементПолітика
securityContext.windowsOptions.hostProcess

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

Дозволені значення

  • true
hostNetwork

Контейнери HostProcess Podʼи повинні використовувати мережевий простір хоста.

Дозволені значення

  • true
securityContext.windowsOptions.runAsUserName

Необхідно вказати, яким користувачем має виконуватися контейнер HostProcess в специфікації Podʼа.

Дозволені значення

  • NT AUTHORITY\SYSTEM
  • NT AUTHORITY\Local service
  • NT AUTHORITY\NetworkService
  • Назви локальних груп користувачів (див. нижче)
runAsNonRoot

Оскільки контейнери HostProcess мають привілейований доступ до хоста, поле runAsNonRoot не може бути встановлене в true.

Дозволені значення

  • Undefined/Nil
  • false

Приклад маніфесту (частково)

spec:
  securityContext:
    windowsOptions:
      hostProcess: true
      runAsUserName: "NT AUTHORITY\\Local service"
  hostNetwork: true
  containers:
  - name: test
    image: image1:latest
    command:
      - ping
      - -t
      - 127.0.0.1
  nodeSelector:
    "kubernetes.io/os": windows

Монтування томів

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

Containerd v1.6

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

Для доступу до токенів облікового запису служби (наприклад) у контейнері підтримуються такі структури шляхів:

  • .\var\run\secrets\kubernetes.io\serviceaccount\
  • $CONTAINER_SANDBOX_MOUNT_POINT\var\run\secrets\kubernetes.io\serviceaccount\

Containerd v1.7 (та новіші версії)

Застосунки, які працюють усередині контейнера, можуть отримувати доступ до підключених томів безпосередньо через вказаний mountPath тому (аналогічно Linux і не-HostProcess контейнерам Windows).

Для забезпечення зворотної сумісності зі старими версіями, доступ до томів також може бути здійснений через використання тих самих відносних шляхів, які були налаштовані у containerd v1.6.

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

  • c:\var\run\secrets\kubernetes.io\serviceaccount
  • /var/run/secrets/kubernetes.io/serviceaccount/
  • $CONTAINER_SANDBOX_MOUNT_POINT\var\run\secrets\kubernetes.io\serviceaccount\

Обмеження ресурсів

Обмеження ресурсів (диск, памʼять, кількість CPU) застосовуються до задачі і є загальними для всієї задачі. Наприклад, при обмеженні в 10 МБ памʼяті, памʼять, виділена для будь-якого обʼєкта задачі HostProcess, буде обмежена 10 МБ. Це така ж поведінка, як і в інших типах контейнерів Windows. Ці обмеження вказуються так само як і зараз для будь-якого середовища виконання контейнерів або оркестрування, яке використовується. Єдина відмінність полягає у розрахунку використання дискових ресурсів для відстеження ресурсів через відмінності у способі ініціалізації контейнерів HostProcess.

Вибір облікового запису користувача

Системні облікові записи

Типово контейнери HostProcess підтримують можливість запуску з одного з трьох підтримуваних облікових записів служб Windows:

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

Локальні облікові записи

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

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

Приклад:

  1. Створіть локальну групу користувачів на вузлі (це може бути зроблено в іншому контейнері HostProcess).

    net localgroup hpc-localgroup /add
    
  2. Надайте доступ до потрібних ресурсів на вузлі локальній групі користувачів. Це можна зробити за допомогою інструментів, таких як icacls.

  3. Встановіть runAsUserName на імʼя локальної групи користувачів для Podʼа або окремих контейнерів.

    securityContext:
      windowsOptions:
        hostProcess: true
        runAsUserName: hpc-localgroup
    
  4. Заплануйте Pod!

Базовий образ для контейнерів HostProcess

Контейнери HostProcess можуть бути побудовані з будь-яких наявних базових образів контейнерів Windows.

Крім того, був створений новий базовий образ спеціально для контейнерів HostProcess! Для отримання додаткової інформації перегляньте проєкт windows-host-process-containers-base-image на github.

Розвʼязання проблем з контейнерами HostProcess

  • Контейнери HostProcess не запускаються, помилка failed to create user process token: failed to logon user: Access is denied.: unknown.

    Переконайтеся, що containerd працює як службовий обліковий запис LocalSystem або LocalService. Облікові записи користувачів (навіть адміністраторські облікові записи) не мають дозволів на створення токенів входу для будь-яких підтримуваних облікових записів користувачів.

8 - Налаштування якості обслуговування для Podʼів

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

Коли Kubernetes створює Pod, він призначає один з таких класів QoS для Podʼа:

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

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

Також вам потрібно мати можливість створювати та видаляти простори імен.

Створення простору імен

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

kubectl create namespace qos-example

Створення Podʼа, якому призначено клас QoS Guaranteed

Щоб Podʼа був наданий клас QoS Guaranteed:

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

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

Нижче подано маніфест для Podʼа з одним контейнером. Контейнер має ліміт памʼяті та запит памʼяті, обидва дорівнюють 200 MiB. Контейнер має ліміт CPU та запит CPU, обидва дорівнюють 700 міліCPU:

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod.yaml --namespace=qos-example

Перегляньте докладну інформацію про Pod:

kubectl get pod qos-demo --namespace=qos-example --output=yaml

Вивід показує, що Kubernetes призначив Podʼу клас QoS Guaranteed. Також вивід підтверджує, що у контейнера Podʼа є запит памʼяті, який відповідає його ліміту памʼяті, і є запит CPU, який відповідає його ліміту CPU.

spec:
  containers:
    ...
    resources:
      limits:
        cpu: 700m
        memory: 200Mi
      requests:
        cpu: 700m
        memory: 200Mi
    ...
status:
  qosClass: Guaranteed

Очищення

Видаліть свій Pod:

kubectl delete pod qos-demo --namespace=qos-example

Створення Podʼа, якому призначено клас QoS Burstable

Podʼу надається клас QoS Burstable, якщо:

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

Нижче подано маніфест для Podʼа з одним контейнером. Контейнер має ліміт памʼяті 200 MiB та запит памʼяті 100 MiB.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-2-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-2.yaml --namespace=qos-example

Перегляньте докладну інформацію про Pod:

kubectl get pod qos-demo-2 --namespace=qos-example --output=yaml

Вивід показує, що Kubernetes призначив Podʼу клас QoS Burstable:

spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: qos-demo-2-ctr
    resources:
      limits:
        memory: 200Mi
      requests:
        memory: 100Mi
  ...
status:
  qosClass: Burstable

Очищення

Видаліть свій Pod:

kubectl delete pod qos-demo-2 --namespace=qos-example

Створення Podʼа, якому призначено клас QoS BestEffort

Для того, щоб Podʼу був призначений клас QoS BestEffort, контейнери у Podʼі не повинні мати жодних лімітів або запитів памʼяті чи CPU.

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

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-3-ctr
    image: nginx

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-3.yaml --namespace=qos-example

Перегляньте докладну інформацію про Pod:

kubectl get pod qos-demo-3 --namespace=qos-example --output=yaml

Вивід показує, що Kubernetes призначив Podʼа клас QoS BestEffort:

spec:
  containers:
    ...
    resources: {}
  ...
status:
  qosClass: BestEffort

Очищення

Видаліть свій Pod:

kubectl delete pod qos-demo-3 --namespace=qos-example

Створення Podʼа з двома контейнерами

Нижче подано маніфест для Podʼа з двома контейнерами. Один контейнер вказує запит памʼяті 200 MiB. Інший контейнер не вказує жодних запитів або лімітів.

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-4
  namespace: qos-example
spec:
  containers:

  - name: qos-demo-4-ctr-1
    image: nginx
    resources:
      requests:
        memory: "200Mi"

  - name: qos-demo-4-ctr-2
    image: redis

Зверніть увагу, що цей Pod відповідає критеріям класу QoS Burstable. Тобто, він не відповідає критеріям для класу QoS Guaranteed, і один з його контейнерів має запит памʼяті.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/qos/qos-pod-4.yaml --namespace=qos-example

Перегляньте докладну інформацію про Pod:

kubectl get pod qos-demo-4 --namespace=qos-example --output=yaml

Вивід показує, що Kubernetes призначив Podʼу клас QoS Burstable:

spec:
  containers:
    ...
    name: qos-demo-4-ctr-1
    resources:
      requests:
        memory: 200Mi
    ...
    name: qos-demo-4-ctr-2
    resources: {}
    ...
status:
  qosClass: Burstable

Отримання класу QoS Podʼа

Замість того, щоб бачити всі поля, ви можете переглянути лише поле, яке вам потрібно:

kubectl --namespace=qos-example get pod qos-demo-4 -o jsonpath='{ .status.qosClass}{"\n"}'
Burstable

Очищення

Видаліть ваш простір імен:

kubectl delete namespace qos-example

Що далі

Для розробників застосунків

Для адміністраторів кластера

9 - Призначення розширених ресурсів контейнеру

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

Ця сторінка показує, як призначити розширені ресурси контейнеру.

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

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

Для перевірки версії введіть kubectl version.

Перш ніж виконувати це завдання, виконайте завдання Оголошення розширених ресурсів для вузла. Це налаштує один з ваших вузлів для оголошення ресурсу "dongle".

Призначте розширений ресурс Podʼу

Щоб запитати розширений ресурс, включіть поле resources:requests у ваш маніфест контейнера. Розширені ресурси повністю кваліфікуються будь-яким доменом поза *.kubernetes.io/. Дійсні імена розширених ресурсів мають форму example.com/foo, де example.com замінено на домен вашої організації, а foo — це описове імʼя ресурсу.

Нижче подано конфігураційний файл для Podʼа з одним контейнером:

apiVersion: v1
kind: Pod
metadata:
  name: extended-resource-demo
spec:
  containers:
  - name: extended-resource-demo-ctr
    image: nginx
    resources:
      requests:
        example.com/dongle: 3
      limits:
        example.com/dongle: 3

У конфігураційному файлі можна побачити, що контейнер запитує 3 розширених ресурси "dongle".

Створіть Pod:

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

Перевірте, що Pod працює:

kubectl get pod extended-resource-demo

Опишіть Pod:

kubectl describe pod extended-resource-demo

Виведений текст показує запити донглів:

Limits:
  example.com/dongle: 3
Requests:
  example.com/dongle: 3

Спроба створення другого Podʼа

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

apiVersion: v1
kind: Pod
metadata:
  name: extended-resource-demo-2
spec:
  containers:
  - name: extended-resource-demo-2-ctr
    image: nginx
    resources:
      requests:
        example.com/dongle: 2
      limits:
        example.com/dongle: 2

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

Спроба створити Pod:

kubectl apply -f https://k8s.io/examples/pods/resource/extended-resource-pod-2.yaml

Опишіть Pod:

kubectl describe pod extended-resource-demo-2

Текст виводу показує, що Pod не може бути запланованим, оскільки немає вузла, на якому було б доступно 2 донгли:

Conditions:
  Type    Status
  PodScheduled  False
...
Events:
  ...
  ... Warning   FailedScheduling  pod (extended-resource-demo-2) failed to fit in any node
fit failure summary on nodes : Insufficient example.com/dongle (1)

Перегляньте статус Podʼа:

kubectl get pod extended-resource-demo-2

Текст виводу показує, що Pod було створено, але не заплановано для виконання на вузлі. Він має статус Pending:

NAME                       READY     STATUS    RESTARTS   AGE
extended-resource-demo-2   0/1       Pending   0          6m

Очищення

Видаліть Podʼи, які ви створили для цього завдання:

kubectl delete pod extended-resource-demo
kubectl delete pod extended-resource-demo-2

Для розробників застосунків

Для адміністраторів кластера

10 - Налаштування Podʼа для використання тому для зберігання

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

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

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

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

Для перевірки версії введіть kubectl version.

Налаштування тому для Podʼа

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

apiVersion: v1
kind: Pod
metadata:
  name: redis
spec:
  containers:
  - name: redis
    image: redis
    volumeMounts:
    - name: redis-storage
      mountPath: /data/redis
  volumes:
  - name: redis-storage
    emptyDir: {}
  1. Створіть Pod:

    kubectl apply -f https://k8s.io/examples/pods/storage/redis.yaml
    
  2. Перевірте, що контейнер Podʼа працює, а потім спостерігайте за змінами в Podʼі:

    kubectl get pod redis --watch
    

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

    NAME      READY     STATUS    RESTARTS   AGE
    redis     1/1       Running   0          13s
    
  3. В іншому терміналі отримайте доступ до оболонки запущеного контейнера:

    kubectl exec -it redis -- /bin/bash
    
  4. У вашій оболонці перейдіть до /data/redis, а потім створіть файл:

    root@redis:/data# cd /data/redis/
    root@redis:/data/redis# echo Hello > test-file
    
  5. У вашій оболонці виведіть список запущених процесів:

    root@redis:/data/redis# apt-get update
    root@redis:/data/redis# apt-get install procps
    root@redis:/data/redis# ps aux
    

    Вивід буде схожий на це:

    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    redis        1  0.1  0.1  33308  3828 ?        Ssl  00:46   0:00 redis-server *:6379
    root        12  0.0  0.0  20228  3020 ?        Ss   00:47   0:00 /bin/bash
    root        15  0.0  0.0  17500  2072 ?        R+   00:48   0:00 ps aux
    
  6. У вашій оболонці завершіть процес Redis:

    root@redis:/data/redis# kill <pid>
    

    де <pid> — це ідентифікатор процесу Redis (PID).

  7. У вашому початковому терміналі спостерігайте за змінами в Podʼі Redis. В кінцевому результаті ви побачите щось подібне:

    NAME      READY     STATUS     RESTARTS   AGE
    redis     1/1       Running    0          13s
    redis     0/1       Completed  0         6m
    redis     1/1       Running    1         6m
    

На цьому етапі контейнер завершився та перезапустився. Це тому, що Pod Redis має restartPolicy Always.

  1. Отримайте доступ до оболонки в перезапущеному контейнері:

    kubectl exec -it redis -- /bin/bash
    
  2. У вашій оболонці перейдіть до /data/redis та перевірте, що test-file все ще там.

    root@redis:/data/redis# cd /data/redis/
    root@redis:/data/redis# ls
    test-file
    
  3. Видаліть Pod, який ви створили для цього завдання:

    kubectl delete pod redis
    

Що далі

  • Дивіться Volume.

  • Дивіться Pod.

  • Крім локального сховища на диску, яке надає emptyDir, Kubernetes підтримує багато різних рішень для мережевого сховища, включаючи PD на GCE та EBS на EC2, які бажані для критичних даних та будуть обробляти деталі, такі як монтування та розмонтування пристроїв на вузлах. Дивіться Volumes для отримання додаткової інформації.

11 - Налаштування Podʼа для використання PersistentVolume для зберігання

Ця сторінка показує, як налаштувати Pod для використання PersistentVolumeClaim для зберігання. Ось короткий опис процесу:

  1. Ви, як адміністратор кластера, створюєте PersistentVolume на основі фізичного сховища. Ви не повʼязуєте том з жодним Podʼом.

  2. Ви, як розробник / користувач кластера, створюєте PersistentVolumeClaim, який автоматично привʼязується до відповідного PersistentVolume.

  3. Ви створюєте Pod, який використовує вищезгаданий PersistentVolumeClaim для зберігання.

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

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

  • Ознайомтеся з матеріалом в Постійні томи.

Створіть файл index.html на вашому вузлі

Відкрийте оболонку на єдиному вузлі вашого кластера. Спосіб відкриття оболонки залежить від того, як ви налаштували ваш кластер. Наприклад, якщо ви використовуєте Minikube, ви можете відкрити оболонку до вашого вузла, введенням minikube ssh.

У вашій оболонці на цьому вузлі створіть теку /mnt/data:

# Це передбачає, що ваш вузол використовує "sudo" для запуску команд
# як суперкористувач
sudo mkdir /mnt/data

У теці /mnt/data створіть файл index.html:

# Це також передбачає, що ваш вузол використовує "sudo" для запуску команд
# як суперкористувач
sudo sh -c "echo 'Hello from Kubernetes storage' > /mnt/data/index.html"

Перевірте, що файл index.html існує:

cat /mnt/data/index.html

Виведення повинно бути:

Hello from Kubernetes storage

Тепер ви можете закрити оболонку вашого вузла.

Створення PersistentVolume

У цьому завданні ви створюєте hostPath PersistentVolume. Kubernetes підтримує hostPath для розробки та тестування на одновузловому кластері. PersistentVolume типу hostPath використовує файл або теку на вузлі для емуляції мережевого сховища.

В операційному кластері ви не використовували б hostPath. Замість цього адміністратор кластера створив би мережевий ресурс, такий як постійний диск Google Compute Engine, розділ NFS або том Amazon Elastic Block Store. Адміністратори кластера також можуть використовувати StorageClasses для динамічного налаштування.

Ось файл конфігурації для PersistentVolume типу hostPath:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: task-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

Файл конфігурації вказує, що том знаходиться в /mnt/data на вузлі кластера. Конфігурація також вказує розмір 10 гібібайт та режим доступу ReadWriteOnce, що означає, що том може бути підключений як для читання-запису лише одним вузлом. Визначається імʼя StorageClass manual для PersistentVolume, яке буде використовуватися для привʼязки запитів PersistentVolumeClaim до цього PersistentVolume.

Створіть PersistentVolume:

kubectl apply -f https://k8s.io/examples/pods/storage/pv-volume.yaml

Перегляньте інформацію про PersistentVolume:

kubectl get pv task-pv-volume

Вивід показує, що PersistentVolume має STATUS Available. Це означає, що він ще не був привʼязаний до PersistentVolumeClaim.

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Available             manual                   4s

Створення PersistentVolumeClaim

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

Ось файл конфігурації для PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: task-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

Створіть PersistentVolumeClaim:

kubectl apply -f https://k8s.io/examples/pods/storage/pv-claim.yaml

Після створення PersistentVolumeClaim панель управління Kubernetes шукає PersistentVolume, який відповідає вимогам заявки. Якщо панель управління знаходить відповідний PersistentVolume з тим самим StorageClass, вона привʼязує заявку до тому.

Знову подивіться на PersistentVolume:

kubectl get pv task-pv-volume

Тепер вивід показує STATUS як Bound.

NAME             CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                   STORAGECLASS   REASON    AGE
task-pv-volume   10Gi       RWO           Retain          Bound     default/task-pv-claim   manual                   2m

Подивіться на PersistentVolumeClaim:

kubectl get pvc task-pv-claim

Вивід показує, що PersistentVolumeClaim привʼязаний до вашого PersistentVolume, task-pv-volume.

NAME            STATUS    VOLUME           CAPACITY   ACCESSMODES   STORAGECLASS   AGE
task-pv-claim   Bound     task-pv-volume   10Gi       RWO           manual         30s

Створення Podʼа

Наступним кроком є створення Podʼа, який використовує ваш PersistentVolumeClaim як том.

Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: task-pv-pod
spec:
  volumes:
    - name: task-pv-storage
      persistentVolumeClaim:
        claimName: task-pv-claim
  containers:
    - name: task-pv-container
      image: nginx
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: task-pv-storage


Зверніть увагу, що файл конфігурації Podʼа вказує PersistentVolumeClaim, але не вказує PersistentVolume. З погляду Podʼа, заявка є томом.

Створіть Pod:

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

Перевірте, що контейнер у Podʼі працює:

kubectl get pod task-pv-pod

Відкрийте оболонку для контейнера, що працює у вашому Podʼі:

kubectl exec -it task-pv-pod -- /bin/bash

У вашій оболонці перевірте, що nginx обслуговує файл index.html з тому hostPath:

# Обовʼязково запустіть ці 3 команди всередині кореневої оболонки, яка є результатом
# виконання "kubectl exec" на попередньому кроці
apt update
apt install curl
curl http://localhost/

Вивід показує текст, який ви записали у файл index.html у томі hostPath:

Hello from Kubernetes storage

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

Очищення

Видаліть Pod, PersistentVolumeClaim та PersistentVolume:

kubectl delete pod task-pv-pod
kubectl delete pvc task-pv-claim
kubectl delete pv task-pv-volume

Якщо у вас ще не відкрито оболонку до вузла у вашому кластері, відкрийте нову оболонку так само як ви робили це раніше.

У оболонці на вашому вузлі видаліть файл і теку, які ви створили:

# Це передбачає, що ваш вузол використовує "sudo" для виконання команд
# з правами суперкористувача
sudo rm /mnt/data/index.html
sudo rmdir /mnt/data

Тепер ви можете закрити оболонку доступу до вашого вузла.

Монтування одного PersistentVolume у два місця


apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
    - name: test
      image: nginx
      volumeMounts:
        # a mount for site-data
        - name: config
          mountPath: /usr/share/nginx/html
          subPath: html
        # another mount for nginx config
        - name: config
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
  volumes:
    - name: config
      persistentVolumeClaim:
        claimName: test-nfs-claim

Ви можете виконати монтування томуу двох місцях у вашому контейнері nginx:

  • /usr/share/nginx/html для статичного вебсайту
  • /etc/nginx/nginx.conf для стандартної конфігурації

Контроль доступу

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

Використовуйте анотацію pv.beta.kubernetes.io/gid наступним чином:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
  annotations:
    pv.beta.kubernetes.io/gid: "1234"

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

Що далі

Довідка

12 - Налаштування Pod для використання projected тому для зберігання

Ця сторінка показує, як використовувати projected том, щоб змонтувати декілька наявних джерел томів у одну теку. Наразі можна проєктувати томи типів secret, configMap, downwardAPI, та serviceAccountToken.

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

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

Для перевірки версії введіть kubectl version.

Налаштування projected тому для Pod

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

Ось файл конфігурації для Pod:

apiVersion: v1
kind: Pod
metadata:
  name: test-projected-volume
spec:
  containers:
  - name: test-projected-volume
    image: busybox:1.28
    args:
    - sleep
    - "86400"
    volumeMounts:
    - name: all-in-one
      mountPath: "/projected-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: user
      - secret:
          name: pass
  1. Створіть Secrets:

    # Створіть файли, що містять імʼя користувача та пароль:
    echo -n "admin" > ./username.txt
    echo -n "1f2d1e2e67df" > ./password.txt
    
    # Запакуйте ці файли у секрети:
    kubectl create secret generic user --from-file=./username.txt
    kubectl create secret generic pass --from-file=./password.txt
    
  2. Створіть Pod:

    kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml
    
  3. Перевірте, що контейнер Pod запущено, а потім слідкуйте за змінами в Podʼі:

    kubectl get --watch pod test-projected-volume
    

    Вивід буде виглядати так:

    NAME                    READY     STATUS    RESTARTS   AGE
    test-projected-volume   1/1       Running   0          14s
    
  4. В іншому терміналі отримайте оболонку до запущеного контейнера:

    kubectl exec -it test-projected-volume -- /bin/sh
    
  5. У вашій оболонці перевірте, що тека projected-volume містить ваші projected джерела:

    ls /projected-volume/
    

Очищення

Видаліть Pod та Secrets:

kubectl delete pod test-projected-volume
kubectl delete secret user pass

Що далі

  • Дізнайтеся більше про projected томи.
  • Прочитайте документ про проєктування all-in-one volume.

13 - Налаштування контексту безпеки для Podʼа або контейнера

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

  • Дискреційний контроль доступу: Дозвіл на доступ до обʼєкта, такого як файл, базується на ідентифікаторі користувача (UID) та ідентифікаторі групи (GID).

  • Security Enhanced Linux (SELinux): Обʼєкти призначаються мітки безпеки.

  • Виконання з привілеями або без них.

  • Linux Capabilities: Надає процесу деякі привілеї, але не всі привілеї користувача root.

  • AppArmor: Використовуйте профілі програм для обмеження можливостей окремих програм.

  • Seccomp: Фільтрує системні виклики процесу.

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

    • запущений з привілеями, або
    • має CAP_SYS_ADMIN
  • readOnlyRootFilesystem: Підключає кореневу файлову систему контейнера тільки для читання.

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

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

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

Для перевірки версії введіть kubectl version.

Встановлення контексту безпеки для Pod

Щоб вказати параметри безпеки для Podʼа, включіть поле securityContext в специфікацію Pod. Поле securityContext є обʼєктом PodSecurityContext. Параметри безпеки, які ви вказуєте для Pod, застосовуються до всіх контейнерів в Podʼі. Ось файл конфігурації для Podʼа з securityContext та томом emptyDir:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    supplementalGroups: [4000]
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox:1.28
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

У файлі конфігурації поле runAsUser вказує, що для будь-яких контейнерів в Podʼі, всі процеси виконуються з ідентифікатором користувача 1000. Поле runAsGroup вказує основний ідентифікатор групи 3000 для усіх процесів у контейнерах Pod. Якщо це поле відсутнє, основний ідентифікатор групи контейнерів буде root(0). Будь-які створені файли також належатимуть користувачу 1000 та групі 3000 при вказанні runAsGroup. Оскільки вказано поле fsGroup, всі процеси контейнера також належать до додаткової групи ідентифікатора 2000. Власником тому /data/demo та всіх створених файлів у цьому томі буде груповий ідентифікатор 2000. Додатково, коли вказане поле supplementalGroups, всі процеси контейнера також є частиною вказаних груп. Якщо це поле пропущене, це означає, що воно порожнє.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo -- sh

У вашій оболонці перелічіть запущені процеси:

ps

Виведений результат показує, що процеси виконуються від імені користувача 1000, що є значенням runAsUser:

PID   USER     TIME  COMMAND
    1 1000      0:00 sleep 1h
    6 1000      0:00 sh
...

У вашій оболонці перейдіть до /data, та виведіть список тек:

cd /data
ls -l

Виведений результат показує, що тека /data/demo має ідентифікатор групи 2000, що є значенням fsGroup.

drwxrwsrwx 2 root 2000 4096 Jun  6 20:08 demo

У вашій оболонці перейдіть до /data/demo, та створіть файл:

cd demo
echo hello > testfile

Виведіть список файлів у теці /data/demo:

ls -l

Виведений результат показує, що testfile має ідентифікатор групи 2000, що є значенням fsGroup.

-rw-r--r-- 1 1000 2000 6 Jun  6 20:08 testfile

Виконайте наступну команду:

id

Результат буде схожий на цей:

uid=1000 gid=3000 groups=2000,3000,4000

З результату видно, що gid дорівнює 3000, що є таким самим, як поле runAsGroup. Якби поле runAsGroup було пропущено, gid залишився б 0 (root), і процес зміг би взаємодіяти з файлами, які належать групі root(0) та групам, які мають необхідні права групи для групи root (0). Ви також можете побачити, що groups містить ідентифікатори груп, які вказані в fsGroup і supplementalGroups, поряд з gid.

Вийдіть з оболонки:

exit

Неявні членства груп, визначені в /etc/group в контейнерному образі

Стандартно Kubernetes обʼєднує інформацію про групи з Podʼа з інформацією, визначеною в /etc/group в контейнерному образі.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
  containers:
  - name: sec-ctx-demo
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

Цей контекст безпеки Podʼа містить runAsUser, runAsGroup та supplementalGroups. Проте ви можете побачити, що фактичні додаткові групи, що прикріплені до процесу контейнера, включатимуть ідентифікатори груп, які походять з /etc/group всередині контейнерного образу.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-5.yaml

Перевірте, чи контейнер Pod запущений:

kubectl get pod security-context-demo

Отримайте оболонку для запущеного контейнера:

kubectl exec -it security-context-demo -- sh

Перевірте ідентичність процесу:

$ id

Вивід буде схожий на:

uid=1000 gid=3000 groups=3000,4000,50000

Ви можете побачити, що groups включає ідентифікатор групи 50000. Це тому, що користувач (uid=1000), який визначений в образі, належить до групи (gid=50000), яка визначена в /etc/group всередині контейнерного образу.

Перевірте /etc/group в контейнерному образі:

$ cat /etc/group

Ви побачите, що uid 1000 належить до групи 50000.

...
user-defined-in-image:x:1000:
group-defined-in-image:x:50000:user-defined-in-image

Вийдіть з оболонки:

exit

Налаштування SupplementalGroups для Podʼа

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

Цю функцію можна увімкнути, встановивши функціональну можливість SupplementalGroupsPolicy для kubelet та kube-apiserver, а також налаштувавши поле .spec.securityContext.supplementalGroupsPolicy для Podʼа.

Поле supplementalGroupsPolicy визначає політику для розрахунку додаткових груп для процесів контейнера в Podʼі. Для цього поля є два дійсних значення:

  • Merge: Членство в групах, визначене в /etc/group для основного користувача контейнера, буде обʼєднано. Це є стандартною політикою, якщо не зазначено інше.

  • Strict: Тільки ідентифікатори груп у полях fsGroup, supplementalGroups або runAsGroup прикріплюються як додаткові групи для процесів контейнера. Це означає, що жодне членство в групах з /etc/group для основного користувача контейнера не буде обʼєднано.

Коли функція увімкнена, вона також надає ідентичність процесу, прикріплену до першого процесу контейнера в полі .status.containerStatuses[].user.linux. Це буде корисно для виявлення, чи прикріплені неявні ідентифікатори груп.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    supplementalGroups: [4000]
    supplementalGroupsPolicy: Strict
  containers:
  - name: sec-ctx-demo
    image: registry.k8s.io/e2e-test-images/agnhost:2.45
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

Цей маніфест Podʼа визначає supplementalGroupsPolicy=Strict. Ви можете побачити, що жодне членство в групах, визначене в /etc/group, не обʼєднується в додаткові групи для процесів контейнера.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-6.yaml

Перевірте, що контейнер Podʼа працює:

kubectl get pod security-context-demo

Перевірте ідентичність процесу:

kubectl exec -it security-context-demo -- id

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

uid=1000 gid=3000 groups=3000,4000

Перегляньте статус Podʼа:

kubectl get pod security-context-demo -o yaml

Ви можете побачити, що поле status.containerStatuses[].user.linux надає ідентичність процесу, прикріплену до першого процесу контейнера.

...
status:
  containerStatuses:
  - name: sec-ctx-demo
    user:
      linux:
        gid: 3000
        supplementalGroups:
        - 3000
        - 4000
        uid: 1000
...

Реалізації

Відомо, що наступні середовища виконання контейнерів підтримують контроль додаткових груп з тонкою настройкою.

На рівні CRI:

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

apiVersion: v1
kind: Node
...
status:
  features:
    supplementalGroupsPolicy: true

Налаштування політики зміни дозволів та прав власності тому для Pod

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

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

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

  • OnRootMismatch: Змінювати дозволи та права власності тільки у випадку, якщо дозволи та права кореневої теки не відповідають очікуваним дозволам тому. Це може допомогти скоротити час зміни власності та дозволів тому.
  • Always: Завжди змінювати дозволи та права власності тому під час підключення.

Наприклад:

securityContext:
  runAsUser: 1000
  runAsGroup: 3000
  fsGroup: 2000
  fsGroupChangePolicy: "OnRootMismatch"

Делегування зміни прав власності та дозволів тому до драйвера CSI

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

Якщо ви розгортаєте драйвер Container Storage Interface (CSI), який підтримує VOLUME_MOUNT_GROUP NodeServiceCapability, процес встановлення права власності та дозволів файлу на основі fsGroup, вказаного в securityContext, буде виконуватися драйвером CSI, а не Kubernetes. У цьому випадку, оскільки Kubernetes не виконує жодної зміни права власності та дозволів, fsGroupChangePolicy не набуває чинності, і згідно з вказаним CSI, очікується, що драйвер монтує том з наданим fsGroup, що призводить до отримання тому, який є доступними для читаання/запису для fsGroup.

Встановлення контексту безпеки для контейнера

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

Ось файл конфігурації для Podʼа з одним контейнером. Як Pod, так і контейнер мають поле securityContext:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-2
spec:
  securityContext:
    runAsUser: 1000
  containers:
  - name: sec-ctx-demo-2
    image: gcr.io/google-samples/hello-app:2.0
    securityContext:
      runAsUser: 2000
      allowPrivilegeEscalation: false

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-2.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo-2

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-2 -- sh

У вашій оболонці перегляньте запущені процеси:

ps aux

Виведений результат показує, що процеси виконуються від імені користувача 2000. Це значення runAsUser, вказане для контейнера. Воно перевизначає значення 1000, вказане для Pod.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
2000         1  0.0  0.0   4336   764 ?        Ss   20:36   0:00 /bin/sh -c node server.js
2000         8  0.1  0.5 772124 22604 ?        Sl   20:36   0:00 node server.js
...

Вийдіть з оболонки:

exit

Встановлення можливостей для контейнера

За допомогою можливостей Linux, ви можете надати певні привілеї процесу, не надаючи всі привілеї користувачеві з правами root. Щоб додати або видалити можливості Linux для контейнера, включіть поле capabilities в розділ securityContext маніфесту контейнера.

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

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-3
spec:
  containers:
  - name: sec-ctx-3
    image: gcr.io/google-samples/hello-app:2.0

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml

Перевірте, що контейнер Pod запущений:

kubectl get pod security-context-demo-3

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-3 -- sh

У вашій оболонці перегляньте запущені процеси:

ps aux

Виведений результат показує ідентифікатори процесів (PID) для контейнера:

USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js

У вашій оболонці перегляньте статус для процесу 1:

cd /proc/1
cat status

Виведений результат показує bitmap можливостей для процесу:

...
CapPrm:	00000000a80425fb
CapEff:	00000000a80425fb
...

Запамʼятайте bitmap можливостей, а потім вийдіть з оболонки:

exit

Далі, запустіть контейнер, який є такий самий, як попередній контейнер, за винятком того, що він має додаткові можливості.

Ось файл конфігурації для Pod, який запускає один контейнер. Конфігурація додає можливості CAP_NET_ADMIN та CAP_SYS_TIME:

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo-4
spec:
  containers:
  - name: sec-ctx-4
    image: gcr.io/google-samples/hello-app:2.0
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/security/security-context-4.yaml

Отримайте оболонку до запущеного контейнера:

kubectl exec -it security-context-demo-4 -- sh

У вашій оболонці перегляньте можливості для процесу 1:

cd /proc/1
cat status

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

...
CapPrm:	00000000aa0435fb
CapEff:	00000000aa0435fb
...

Порівняйте можливості двох контейнерів:

00000000a80425fb
00000000aa0435fb

У bitmap можливостей першого контейнера біти 12 і 25 не встановлені. У другому контейнері, біти 12 і 25 встановлені. Біт 12 — це CAP_NET_ADMIN, а біт 25 — це CAP_SYS_TIME. Дивіться capability.h для визначень констант можливостей.

Встановлення профілю Seccomp для контейнера

Щоб встановити профіль Seccomp для контейнера, включіть поле seccompProfile в розділ securityContext вашого маніфесту Pod або контейнера. Поле seccompProfile є обʼєктом SeccompProfile, який складається з type та localhostProfile. Допустимі варіанти для type включають RuntimeDefault, Unconfined та Localhost. localhostProfile повинен бути встановлений лише якщо type: Localhost. Він вказує шлях до попередньо налаштованого профілю на вузлі, повʼязаного з розташуванням налаштованого профілю Seccomp kubelet (налаштованого за допомогою прапорця --root-dir).

Ось приклад, який встановлює профіль Seccomp до стандартного профілю контейнера вузла:

...
securityContext:
  seccompProfile:
    type: RuntimeDefault

Ось приклад, який встановлює профіль Seccomp до попередньо налаштованого файлу за шляхом <kubelet-root-dir>/seccomp/my-profiles/profile-allow.json:

...
securityContext:
  seccompProfile:
    type: Localhost
    localhostProfile: my-profiles/profile-allow.json

Налаштування профілю AppArmor для контейнера

Щоб налаштувати профіль AppArmor для контейнера, включіть поле appArmorProfile в секцію securityContext вашого контейнера. Поле appArmorProfile є обʼєктом AppArmorProfile, що складається з type та localhostProfile. Дійсні опції для type включають RuntimeDefault (стандартно), Unconfined і Localhost. localhostProfile слід встановлювати тільки якщо type є Localhost. Це вказує на назву попередньо налаштованого профілю на вузлі. Профіль повинен бути завантажений на всіх вузлах, які підходять для Podʼа, оскільки ви не знаєте, де буде розгорнуто Pod. Підходи до налаштування власних профілів обговорюються в Налаштування вузлів з профілями.

Примітка: Якщо containers[*].securityContext.appArmorProfile.type явно встановлено на RuntimeDefault, то Pod не буде допущено, якщо AppArmor не включено на вузлі. Однак, якщо containers[*].securityContext.appArmorProfile.type не зазначено, то стандартне значення (що також є RuntimeDefault) буде застосовано тільки якщо вузол має увімкнений AppArmor. Якщо вузол має вимкнений AppArmor, Pod буде допущено, але контейнер не буде обмежено профілем RuntimeDefault.

Ось приклад, який встановлює профіль AppArmor на стандартний профіль контейнерного середовища вузла:

...
containers:
- name: container-1
  securityContext:
    appArmorProfile:
      type: RuntimeDefault

Ось приклад, який встановлює профіль AppArmor на попередньо налаштований профіль з назвою k8s-apparmor-example-deny-write:

...
containers:
- name: container-1
  securityContext:
    appArmorProfile:
      type: Localhost
      localhostProfile: k8s-apparmor-example-deny-write

Для отримання додаткової інформації дивіться Обмеження доступу контейнера до ресурсів з AppArmor.

Призначення міток SELinux контейнеру

Щоб призначити мітки SELinux контейнеру, включіть поле seLinuxOptions в розділ securityContext вашого маніфесту Podʼа або контейнера. Поле seLinuxOptions є обʼєктом SELinuxOptions. Ось приклад, який застосовує рівень SELinux:

...
securityContext:
  seLinuxOptions:
    level: "s0:c123,c456"

Ефективне переозначення обʼєктів SELinux в томах

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

Стандартно, контейнерне середовище рекурсивно призначає мітку SELinux для всіх файлів на всіх томах Pod. Щоб прискорити цей процес, Kubernetes може миттєво змінити мітку SELinux тому за допомогою параметра монтування -o context=<мітка>.

Щоб скористатися цим прискоренням, мають бути виконані всі ці умови:

  • Функціональні можливості ReadWriteOncePod та SELinuxMountReadWriteOncePod повинні бути увімкнені.
  • Pod повинен використовувати PersistentVolumeClaim з відповідними accessModes та функціональною можливстю:
    • Або том має accessModes: ["ReadWriteOncePod"], і властивість включення SELinuxMountReadWriteOncePod увімкнена.
    • Або том може використовувати будь-які інші режими доступу та SELinuxMountReadWriteOncePod, SELinuxChangePolicy та SELinuxMount повинні бути увімкнені, а Pod мати spec.securityContext.seLinuxChangePolicy або nil (стандартно), або MountOption.
  • Pod (або всі його контейнери, які використовують PersistentVolumeClaim) повинні мати встановлені параметри seLinuxOptions.
  • Відповідний PersistentVolume повинен бути або:
    • Том, який використовує старі типи томів iscsi, rbd або fc.
    • Або том, який використовує драйвер CSI CSI. Драйвер CSI повинен оголосити, що він підтримує монтування з -o context, встановивши spec.seLinuxMount: true у його екземплярі CSIDriver.

Для будь-яких інших типів томів переозначення SELinux відбувається іншим шляхом: контейнерне середовище рекурсивно змінює мітку SELinux для всіх inodes (файлів і тек) у томі.

СТАН ФУНКЦІОНАЛУ: Kubernetes v1.32 [alpha] (стандартно увімкнено: false)
Для Podʼів, які хочуть відмовитися від зміни міток за допомогою параметрів монтування, вони можуть встановити spec.securityContext.seLinuxChangePolicy у значення Recursive. Це потрібно у випадку, коли декілька podʼів використовують один том на одному вузлі, але вони працюють з різними мітками SELinux, що дозволяє одночасний доступ до тома. Наприклад, привілейований pod працює з міткою spc_t, а непривілейований pod працює зі стандартною міткою container_file_t. За відсутності значення spec.securityContext.seLinuxChangePolicy (або зі стандартним значенням MountOption) на вузлі може працювати лише один з таких podʼів, інший отримує ContainerCreating з помилкою conflicting SELinux labels of volume <назва тома>: <мітка виконуваного тома> і <мітка тома, який не може запуститися>.

SELinuxWarningController

Щоб полегшити ідентифікацію Podʼів, на які вплинула зміна міток томів SELinux, у kube-controller-manager було додано новий контролер, який називається SELinuxWarningController. Стандартно він вимкнений і може бути увімкнений або встановленням --controllers=*,selinux-warning-controller прапорець командного рядка, або за допомогою параметра genericControllerManagerConfiguration.controllers поле у KubeControllerManagerConfiguration. Цей контролер потребує увімкнення функціональної можливості SELinuxChangePolicy.

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

  1. Він надсилає подію обом Podʼам. kubectl describe pod <назва podʼа> показує, що SELinuxLabel "<мітка на podʼі>" конфліктує з podʼом <назва іншого podʼа>, який використовує той самий том, що і цей pod з SELinuxLabel "<мітка іншого podʼа>". Якщо обидва podʼи розміщено на одному вузлі, лише один з них може отримати доступ до тома.
  2. Підніміть метрику selinux_warning_controller_selinux_volume_conflict. Метрика містить назви томів + простори імен у якості міток для легкої ідентифікації постраждалих томів.

Адміністратор кластера може використовувати цю інформацію, щоб визначити, на які саме Podʼи впливає зміна планування, і проактивно виключити їх з оптимізації (наприклад, встановити spec.securityContext.seLinuxChangePolicy: Recursive).

Функціональні можливості

Наступні функціональні можливості керують поведінкою перепризначення томів SELinux:

  • SELinuxMountReadWriteOncePod: вмикає оптимізацію для томів з accessModes: ["ReadWriteOncePod"]. Це дуже безпечна можливість, оскільки не може статися так, що два пристрої можуть використовувати один том з таким режимом доступу. Стандартно її увімкнено з v1.28.
  • SELinuxChangePolicy: вмикає поле spec.securityContext.seLinuxChangePolicy у Pod і повʼязаний з ним SELinuxWarningController у kube-controller-manager. Ця функція може бути використана перед увімкненням SELinuxMount для перевірки Podʼів, запущених на кластері, і для проактивного виключення Podʼів з оптимізації. Ця функція вимагає увімкнення SELinuxMountReadWriteOncePod. Це альфа-версія і стандартно вимкнена у версії 1.32.
  • SELinuxMount вмикає оптимізацію для всіх допустимих томів. Оскільки це може порушити роботу наявних робочих навантажень, ми рекомендуємо спочатку увімкнути SELinuxChangePolicy + SELinuxWarningController, щоб перевірити вплив змін. Ця функціональна можливість вимагає увімкнення SELinuxMountReadWriteOncePod і SELinuxChangePolicy. Це альфа-версія і стандартно вимкнена у 1.32.

Управління доступом до файлової системи /proc

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

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

  • Промасковані шляхи:

    • /proc/asound
    • /proc/acpi
    • /proc/kcore
    • /proc/keys
    • /proc/latency_stats
    • /proc/timer_list
    • /proc/timer_stats
    • /proc/sched_debug
    • /proc/scsi
    • /sys/firmware
    • /sys/devices/virtual/powercap
  • Шляхи доступні тільки для читання:

    • /proc/bus
    • /proc/fs
    • /proc/irq
    • /proc/sys
    • /proc/sysrq-trigger

Для деяких Podʼів вам може знадобитися обійти стандартний шлях маскування. Найбільш поширений контекст, коли це потрібно, — це спроба запуску контейнерів у межах контейнера Kubernetes (у межах Podʼа).

Поле procMount в securityContext дозволяє користувачеві запитати, щоб /proc контейнера був Unmasked, або міг бути підмонтований для читання-запису контейнерним процесом. Це також стосується /sys/firmware, який не знаходиться в /proc.

...
securityContext:
  procMount: Unmasked

Обговорення

Контекст безпеки для Pod застосовується до Контейнерів Pod і також до Томів Pod при необхідності. Зокрема, fsGroup та seLinuxOptions застосовуються до Томів наступним чином:

  • fsGroup: Томи, які підтримують управління власністю, модифікуються так, щоб бути власністю та доступними для запису за GID, вказаним у fsGroup. Докладніше див. Документ із проєктування управління власністю томів.

  • seLinuxOptions: Томи, які підтримують мітку SELinux, переозначаються так, щоб бути доступними за міткою, вказаною у seLinuxOptions. Зазвичай вам потрібно лише встановити розділ level. Це встановлює мітку Multi-Category Security (MCS), яку отримують всі Контейнери у Pod, а також Томи.

Очищення

Видаліть Pod:

kubectl delete pod security-context-demo
kubectl delete pod security-context-demo-2
kubectl delete pod security-context-demo-3
kubectl delete pod security-context-demo-4

Що далі

14 - Налаштування службових облікових записів для Podʼів

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

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

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

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

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

Використання стандартного службового облікового запису для доступу до API-сервера

Коли Podʼи звертаються до API-сервера, вони автентифікуються як певний Службовий обліковий запис (наприклад, default). В кожному просторі імен завжди є принаймні один Службовий обліковий запис.

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

Ви можете отримати деталі для Podʼа, який ви створили. Наприклад:

kubectl get pods/<імʼя_пода> -o yaml

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

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

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

Облікові дані API автоматично відкликаються, коли Pod видаляється, навіть якщо є завершувачі. Зокрема, облікові дані API відкликаються через 60 секунд після встановленого на Pod значення .metadata.deletionTimestamp (час видалення зазвичай дорівнює часу, коли запит на видалення був прийнятий плюс період належного завершення роботи Pod).

Відмова від автоматичного монтування облікових даних API

Якщо ви не бажаєте, щоб kubelet автоматично монтував облікові дані API ServiceAccount, ви можете відмовитися від такої стандартної поведінки. Ви можете відмовитися від автоматичного монтування облікових даних API у /var/run/secrets/kubernetes.io/serviceaccount/token для службового облікового запису, встановивши значення automountServiceAccountToken: false у ServiceAccount:

Наприклад:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
automountServiceAccountToken: false
...

Ви також можете відмовитися від автоматичного монтування облікових даних API для певного Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: build-robot
  automountServiceAccountToken: false
  ...

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

Використання більше ніж одного ServiceAccount

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

kubectl get serviceaccounts

Вихідні дані схожі на наступні:

NAME      SECRETS    AGE
default   1          1d

Ви можете створити додаткові обʼєкти ServiceAccount таким чином:

kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
EOF

Імʼя обʼєкта ServiceAccount повинно бути дійсним DNS-піддоменним імʼям.

Якщо ви отримуєте повний дамп обʼєкта ServiceAccount, подібний до цього:

kubectl get serviceaccounts/build-robot -o yaml

Вихідні дані схожі на наступні:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2019-06-16T00:12:34Z
  name: build-robot
  namespace: default
  resourceVersion: "272500"
  uid: 721ab723-13bc-11e5-aec2-42010af0021e

Ви можете використовувати розширення дозволів для встановлення дозволів на облікові записи служб.

Щоб використовувати не-стандартний обліковий запис, встановіть поле spec.serviceAccountName Podʼа на імʼя ServiceAccount, який ви хочете використовувати.

Ви можете встановити лише поле serviceAccountName при створенні Podʼа або в шаблоні для нового Podʼа. Ви не можете оновлювати поле .spec.serviceAccountName Podʼа, який вже існує.

Очищення

Якщо ви спробували створити ServiceAccount build-robot з прикладу вище, ви можете видалити його виконавши:

kubectl delete serviceaccount/build-robot

Вручну створіть API-токен для ServiceAccount

Припустимо, у вас вже є службовий обліковий запис з назвою "build-robot", як зазначено вище.

Ви можете отримати тимчасовий API-токен для цього ServiceAccount за допомогою kubectl:

kubectl create token build-robot

Вихідні дані з цієї команди — це токен, який ви можете використовувати для автентифікації цього ServiceAccount. Ви можете запросити певний час дії токена, використовуючи аргумент командного рядка --duration для kubectl create token (фактичний час дії виданого токену може бути коротшим або навіть довшим).

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

Використовуючи kubectl v1.31 або новішу версію, можна створити токен службового облікового запису, який буде безпосередньо привʼязано до вузла:

kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456

Токен буде чинний до закінчення його терміну дії або до видалення відповідного вузла чи службового облікового запису.

Вручну створіть довговічний API-токен для ServiceAccount

Якщо ви бажаєте отримати API-токен для службового облікового запису, ви створюєте новий Secret з особливою анотацією kubernetes.io/service-account.name.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: build-robot-secret
  annotations:
    kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF

Якщо ви переглянете Secret використовуючи:

kubectl get secret/build-robot-secret -o yaml

ви побачите, що тепер Secret містить API-токен для ServiceAccount "build-robot".

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

kubectl describe secrets/build-robot-secret

Вивід схожий на такий:

Name:           build-robot-secret
Namespace:      default
Labels:         <none>
Annotations:    kubernetes.io/service-account.name: build-robot
                kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da

Type:   kubernetes.io/service-account-token

Data
====
ca.crt:         1338 байтів
namespace:      7 байтів
token:          ...

При видаленні ServiceAccount, який має відповідний Secret, панель управління Kubernetes автоматично очищає довговічний токен з цього Secret.

Додайте ImagePullSecrets до ServiceAccount

Спочатку створіть imagePullSecret. Потім перевірте, чи він був створений. Наприклад:

  • Створіть imagePullSecret, як описано в Вказування ImagePullSecrets в контейнері.

    kubectl create secret docker-registry myregistrykey --docker-server=<імʼя реєстру> \
            --docker-username=ІМ'Я_КОРИСТУВАЧА --docker-password=ПАРОЛЬ_ДЛЯ_DOCKER \
            --docker-email=ЕЛЕКТРОННА_ПОШТА_ДЛЯ_DOCKER
    
  • Перевірте, чи він був створений.

    kubectl get secrets myregistrykey
    

    Вивід схожий на такий:

    NAME             TYPE                              DATA    AGE
    myregistrykey    kubernetes.io/.dockerconfigjson   1       1д
    

Додайте imagePullSecret до ServiceAccount

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

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

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

kubectl edit serviceaccount/default

Вивід файлу sa.yaml буде схожий на такий:

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

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2021-07-07T22:02:39Z
  name: default
  namespace: default
  resourceVersion: "243024"
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6

За допомогою вашого редактора видаліть рядок з ключем resourceVersion, додайте рядки для imagePullSecrets: та збережіть це. Залиште значення uid таким же, як ви його знайшли.

Після внесення змін, відредагований ServiceAccount виглядатиме схоже на це:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2021-07-07T22:02:39Z
  name: default
  namespace: default
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
imagePullSecrets:
  - name: myregistrykey

Перевірте, що imagePullSecrets встановлені для нових Podʼів

Тепер, коли створюється новий Pod у поточному просторі імен і використовується типовий ServiceAccount, у новому Podʼі автоматично встановлюється поле spec.imagePullSecrets:

kubectl run nginx --image=<імʼя реєстру>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'

Вивід:

myregistrykey

Проєцювання токенів ServiceAccount

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

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

Ви можете налаштувати цю поведінку для spec Podʼа за допомогою типу projected тому, що називається ServiceAccountToken.

Токен з цього projected тому — JSON Web Token (JWT). JSON-вміст цього токена слідує чітко визначеній схемі — приклад вмісту для токена, повʼязаного з Pod:

{
  "aud": [  # відповідає запитаним аудиторіям або стандартним аудиторіям API-сервера, якщо явно не запитано
    "https://kubernetes.default.svc"
  ],
  "exp": 1731613413,
  "iat": 1700077413,
  "iss": "https://kubernetes.default.svc",  # відповідає першому значенню, переданому прапорцю --service-account-issuer
  "jti": "ea28ed49-2e11-4280-9ec5-bc3d1d84661a",
  "kubernetes.io": {
    "namespace": "kube-system",
    "node": {
      "name": "127.0.0.1",
      "uid": "58456cb0-dd00-45ed-b797-5578fdceaced"
    },
    "pod": {
      "name": "coredns-69cbfb9798-jv9gn",
      "uid": "778a530c-b3f4-47c0-9cd5-ab018fb64f33"
    },
    "serviceaccount": {
      "name": "coredns",
      "uid": "a087d5a0-e1dd-43ec-93ac-f13d89cd13af"
    },
    "warnafter": 1700081020
  },
  "nbf": 1700077413,
  "sub": "system:serviceaccount:kube-system:coredns"
}

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

Щоб надати Podʼу токен з аудиторією vault та терміном дії дві години, ви можете визначити маніфест Podʼа, схожий на цей:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /var/run/secrets/tokens
      name: vault-token
  serviceAccountName: build-robot
  volumes:
  - name: vault-token
    projected:
      sources:
      - serviceAccountToken:
          path: vault-token
          expirationSeconds: 7200
          audience: vault

Створіть Pod:

kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml

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

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

Виявлення емітента службового облікового запису

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

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

Якщо увімкнено, Kubernetes API-сервер публікує документ конфігурації постачальника OpenID через HTTP. Документ конфігурації публікується за адресою /.well-known/openid-configuration. Документ конфігурації OpenID постачальника іноді називається документом виявлення. Kubernetes API-сервер також публікує повʼязаний набір ключів JSON Web (JWKS), також через HTTP, за адресою /openid/v1/jwks.

Кластери, які використовують RBAC, включають типову роль кластера з назвою system:service-account-issuer-discovery. Типовий ClusterRoleBinding надає цю роль групі system:serviceaccounts, до якої неявно належать всі ServiceAccounts. Це дозволяє Podʼам, які працюють у кластері, отримувати доступ до документа виявлення службового облікового запису через їх змонтований токен службового облікового запису. Адміністратори також можуть вибрати привʼязку ролі до system:authenticated або system:unauthenticated залежно від їх вимог до безпеки та зовнішніх систем, з якими вони мають намір обʼєднуватись.

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

У багатьох випадках API-сервери Kubernetes не доступні через глобальну мережу, але публічні точки доступу, які обслуговують кешовані відповіді від API-сервера, можуть бути доступні для користувачів або постачальників послуг. У таких випадках можливо перевизначити jwks_uri в конфігурації постачальника OpenID, щоб вона вказувала на глобальну точку доступу, а не на адресу API-сервера, передаючи прапорець --service-account-jwks-uri до API-сервера. Як і URL емітента, URI JWKS повинен використовувати схему https.

Що далі

Дивіться також:

15 - Отримання образів з приватного реєстру

Ця сторінка показує, як створити Pod, що використовує Secret для отримання образу з приватного реєстру або сховища контейнерних образів. Існує багато приватних реєстрів, які використовуються. У цьому завданні використовується Docker Hub як приклад реєстру.

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

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

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

  • Якщо ви використовуєте інший приватний контейнерний реєстр, вам потрібен інструмент командного рядка для цього реєстру та будь-яка інформація для входу в реєстр.

Увійдіть до Docker Hub

На вашому компʼютері вам необхідно автентифікуватися в реєстрі, щоб отримати приватний образ.

Використовуйте інструмент docker, щоб увійти до Docker Hub. Докладніше про це дивіться у розділі log in на сторінці Docker ID accounts.

docker login

Коли буде запитано, введіть свій ідентифікатор Docker, а потім обрані вами облікові дані (токен доступу чи пароль до вашого Docker ID).

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

Перегляньте файл config.json:

cat ~/.docker/config.json

Вивід містить секцію, подібну до цієї:

{
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "c3R...zE2"
        }
    }
}

Створення Secret на основі наявних облікових даних

Кластер Kubernetes використовує Secret типу kubernetes.io/dockerconfigjson для автентифікації в контейнерному реєстрі для отримання приватного образу.

Якщо ви вже виконали команду docker login, ви можете скопіювати ці облікові дані в Kubernetes:

kubectl create secret generic regcred \
    --from-file=.dockerconfigjson=<шлях/до/.docker/config.json> \
    --type=kubernetes.io/dockerconfigjson

Якщо вам потрібно більше контролю (наприклад, встановити простір імен чи мітку для нового Secret), то ви можете налаштувати Secret перед збереженням його. Переконайтеся, що:

  • встановлено назву елемента даних як .dockerconfigjson
  • файл конфігурації Docker закодовано у base64, а потім вставлено цей рядок без розривів як значення для поля data[".dockerconfigjson"]
  • встановлено type як kubernetes.io/dockerconfigjson

Приклад:

apiVersion: v1
kind: Secret
metadata:
  name: myregistrykey
  namespace: awesomeapps
data:
  .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg==
type: kubernetes.io/dockerconfigjson

Якщо ви отримали повідомлення про помилку error: no objects passed to create, це може означати, що закодований у base64 рядок є недійсним. Якщо ви отримали повідомлення про помилку, подібне до Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ..., це означає, що закодований у base64 рядок у даних успішно декодувався, але не може бути розпізнаний як файл .docker/config.json.

Створення Secret, за допомогою вводу облікових даних в командному рядку

Створіть цей Secret, назвавши його regcred:

kubectl create secret docker-registry regcred \
    --docker-server=<your-registry-server> \
    --docker-username=<your-name> \
    --docker-password=<your-pword> \
    --docker-email=<your-email>

де:

  • <your-registry-server> — це повна доменна назва вашого приватного реєстру Docker. Використовуйте https://index.docker.io/v1/ для DockerHub.
  • <your-name> — це ваше імʼя користувача Docker.
  • <your-pword> — це ваш пароль Docker.
  • <your-email> — це ваша електронна адреса Docker.

Ви успішно встановили ваші облікові дані Docker у кластері як Secret під назвою regcred.

Перегляд Secret regcred

Щоб зрозуміти вміст Secret regcred, який ви створили, спочатку перегляньте Secret у форматі YAML:

kubectl get secret regcred --output=yaml

Вивід подібний до такого:

apiVersion: v1
kind: Secret
metadata:
  ...
  name: regcred
  ...
data:
  .dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
type: kubernetes.io/dockerconfigjson

Значення поля .dockerconfigjson — це представлення в base64 ваших облікових даних Docker.

Щоб зрозуміти, що знаходиться у полі .dockerconfigjson, конвертуйте дані Secret в читабельний формат:

kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode

Вивід подібний до такого:

{"auths":{"your.private.registry.example.com":{"username":"janedoe","password":"xxxxxxxxxxx","email":"jdoe@example.com","auth":"c3R...zE2"}}}

Щоб зрозуміти, що знаходиться у полі auth, конвертуйте дані, закодовані в base64, у читабельний формат:

echo "c3R...zE2" | base64 --decode

Вивід, імʼя користувача та пароль, зʼєднані через :, подібний до такого:

janedoe:xxxxxxxxxxx

Зверніть увагу, що дані Secret містять токен авторизації, аналогічний вашому локальному файлу ~/.docker/config.json.

Ви успішно встановили ваші облікові дані Docker як Secret з назвою regcred у кластері.

Створення Pod, який використовує ваш Secret

Нижче подано опис для прикладу Pod, який потребує доступу до ваших облікових даних Docker у regcred:

apiVersion: v1
kind: Pod
metadata:
  name: private-reg
spec:
  containers:
  - name: private-reg-container
    image: <your-private-image>
  imagePullSecrets:
  - name: regcred

Завантажте вищезазначений файл на свій компʼютер:

curl -L -o my-private-reg-pod.yaml https://k8s.io/examples/pods/private-reg-pod.yaml

У файлі my-private-reg-pod.yaml замініть <your-private-image> на шлях до образу у приватному реєстрі, наприклад:

your.private.registry.example.com/janedoe/jdoe-private:v1

Для отримання образу з приватного реєстру Kubernetes потрібні облікові дані. Поле imagePullSecrets у файлі конфігурації вказує, що Kubernetes повинен отримати облікові дані з Secret з назвою regcred.

Створіть Pod, який використовує ваш Secret, і перевірте, що Pod працює:

kubectl apply -f my-private-reg-pod.yaml
kubectl get pod private-reg

Також, якщо запуск Podʼа не вдається і ви отримуєте статус ImagePullBackOff, перегляньте події Pod:

kubectl describe pod private-reg

Якщо ви побачите подію з причиною, встановленою на FailedToRetrieveImagePullSecret, Kubernetes не може знайти Secret із назвою (regcred, у цьому прикладі).

Переконайтеся, що вказаний вами Secret існує і що його назва вірно вказана.

Events:
  ...  Reason                           ...  Message
       ------                                -------
  ...  FailedToRetrieveImagePullSecret  ...  Unable to retrieve some image pull secrets (<regcred>); attempting to pull the image may not succeed.

Використання образів з кількох реєстрів

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

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

Що далі

16 - Налаштування проб життєздатності, готовності та запуску

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

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

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

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

Kubelet використовує проби готовності для визначення моменту, коли контейнер готовий приймати трафік. Одним з використань цього сигналу є контроль за тим, які Podʼи використовуються як бекенди для Service. Pod вважається готовим, коли його стан Ready є true. Коли Pod не готовий, його видаляють з балансувальників навантаження Serviceʼів. Стан Ready у Pod є false, коли стан Ready у його Node не є true, коли один з readinessGates Pod є хибним, або коли принаймні один з його контейнерів не готовий.

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

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

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

Визначте команду життєздатності

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

У цьому завданні ви створите Pod, який запускає контейнер на основі образу registry.k8s.io/busybox. Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

У файлі конфігурації можна побачити, що у Podʼа є один Container. Поле periodSeconds вказує, що kubelet повинен виконувати пробу життєздатності кожні 5 секунд. Поле initialDelaySeconds повідомляє kubelet, що він повинен зачекати 5 секунд перед виконанням першої проби. Для виконання проби kubelet виконує команду cat /tmp/healthy у цільовому контейнері. Якщо команда успішно виконується, вона повертає 0, і kubelet вважає контейнер живим і справним. Якщо команда повертає ненульове значення, kubelet примусово зупиняє контейнер і перезапускає його.

Під час запуску контейнера виконується ця команда:

/bin/sh -c "touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600"

Протягом перших 30 секунд життя контейнера існує файл /tmp/healthy. Таким чином, протягом перших 30 секунд команда cat /tmp/healthy повертає код успіху. Після 30 секунд cat /tmp/healthy повертає код невдачі.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml

Протягом 30 секунд перегляньте події Podʼа:

kubectl describe pod liveness-exec

Виведений текст показує, що жодна проба життєздатності ще не зазнав невдачі:

Type    Reason     Age   From               Message
----    ------     ----  ----               -------
Normal  Scheduled  11s   default-scheduler  Successfully assigned default/liveness-exec to node01
Normal  Pulling    9s    kubelet, node01    Pulling image "registry.k8s.io/busybox"
Normal  Pulled     7s    kubelet, node01    Successfully pulled image "registry.k8s.io/busybox"
Normal  Created    7s    kubelet, node01    Created container liveness
Normal  Started    7s    kubelet, node01    Started container liveness

Після 35 секунд знову перегляньте події Podʼа:

kubectl describe pod liveness-exec

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

Type     Reason     Age                From               Message
----     ------     ----               ----               -------
Normal   Scheduled  57s                default-scheduler  Successfully assigned default/liveness-exec to node01
Normal   Pulling    55s                kubelet, node01    Pulling image "registry.k8s.io/busybox"
Normal   Pulled     53s                kubelet, node01    Successfully pulled image "registry.k8s.io/busybox"
Normal   Created    53s                kubelet, node01    Created container liveness
Normal   Started    53s                kubelet, node01    Started container liveness
Warning  Unhealthy  10s (x3 over 20s)  kubelet, node01    Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal   Killing    10s                kubelet, node01    Container liveness failed liveness probe, will be restarted

Почекайте ще 30 секунд та перевірте, що контейнер був перезапущений:

kubectl get pod liveness-exec

Виведений текст показує, що RESTARTS було збільшено. Зауважте, що лічильник RESTARTS збільшується, як тільки непрацездатний контейнер знову переходить у стан виконання:

NAME            READY     STATUS    RESTARTS   AGE
liveness-exec   1/1       Running   1          1m

Визначення HTTP-запиту життєздатності

Ще один вид проб життєздатності використовує HTTP GET-запит. Ось файл конфігурації для Podʼа, який запускає контейнер на основі образу registry.k8s.io/e2e-test-images/agnhost.

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: registry.k8s.io/e2e-test-images/agnhost:2.40
    args:
    - liveness
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

У файлі конфігурації можна побачити, що у Podʼа є один контейнер. Поле periodSeconds вказує, що kubelet повинен виконувати пробу життєздатності кожні 3 секунди. Поле initialDelaySeconds повідомляє kubelet, що він повинен зачекати 3 секунди перед виконанням першої проби. Для виконання проби kubelet надсилає HTTP GET-запит на сервер, який працює в контейнері та слухає порт 8080. Якщо обробник для шляху /healthz сервера повертає код успіху, kubelet вважає контейнер живим і справним. Якщо обробник повертає код невдачі, ubelet примусово зупиняє контейнер і перезапускає його.

Будь-який код, більший або рівний 200 і менший за 400, вказує на успіх. Будь-який інший код вказує на невдачу.

Ви можете переглянути вихідний код сервера в server.go.

Протягом перших 10 секунд, коли контейнер живий, обробник /healthz повертає статус 200. Після цього обробник повертає статус 500.

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    duration := time.Now().Sub(started)
    if duration.Seconds() > 10 {
        w.WriteHeader(500)
        w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
    } else {
        w.WriteHeader(200)
        w.Write([]byte("ok"))
    }
})

Kubelet починає виконувати перевірку стану справності через 3 секунди після запуску контейнера. Таким чином, перші кілька перевірок стану справності будуть успішними. Але після 10 секунд перевірки стану справності будуть невдалими, і kubelet зупинить та перезапустить контейнер.

Щоб спробувати перевірку стану справності через HTTP, створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/http-liveness.yaml

Через 10 секунд перегляньте події Podʼа, щоб перевірити, що проби життєздатності зазнали невдачі, і контейнер був перезапущений:

kubectl describe pod liveness-http

У випусках після v1.13 налаштування локального HTTP-проксі не впливають на пробу життєздатності через HTTP.

Визначення проби життєздатності через TCP-сокет

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

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: registry.k8s.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 10

Як можна побачити, конфігурація для перевірки TCP досить схожа на перевірку через HTTP. У цьому прикладі використовуються як проби готовності, так і життєздатності. Kubelet надішле першу пробу життєздатності через 15 секунд після запуску контейнера. Ця проба спробує підʼєднатися до контейнера goproxy на порту 8080. Якщо проба на життєздатність не спрацює, контейнер буде перезапущено. Kubelet продовжить виконувати цю перевірку кожні 10 секунд.

Крім проби життєздатності, ця конфігурація включає пробу готовності. Kubelet запустить першу пробу готовності через 15 секунд після запуску контейнера. Аналогічно проби життєздатності, це спроба підʼєднатися до контейнера goproxy на порту 8080. Якщо проба пройде успішно, Pod буде позначений як готовий і отримає трафік від сервісів. Якщо перевірка готовності не вдасться, то Pod буде позначений як не готовий і не отримає трафік від жодного з сервісів.

Щоб спробувати перевірку життєздатності через TCP, створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/probe/tcp-liveness-readiness.yaml

Через 15 секунд перегляньте події Podʼа, щоб перевірити, що проби життєздатності:

kubectl describe pod goproxy

Визначення проби життєздатності через gRPC

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

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

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

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

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

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

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

kubectl apply -f https://k8s.io/examples/pods/probe/grpc-liveness.yaml

Через 15 секунд перегляньте події Podʼа, щоб перевірити, що перевірка життєздатності не зазнала невдачі:

kubectl describe pod etcd-with-grpc

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

  • Проби запускаються для IP-адреси Podʼа або його імені хосту. Обовʼязково налаштуйте вашу кінцеву точку gRPC для прослуховування IP-адреси Podʼа.
  • Проби не підтримують жодних параметрів автентифікації (наприклад, -tls).
  • Немає кодів помилок для вбудованих проб. Усі помилки вважаються невдачами проби.
  • Якщо ExecProbeTimeout feature gate встановлено у false, grpc-health-probe не дотримується налаштування timeoutSeconds (яке стандартно становить 1 с), тоді як вбудована проба зазнає невдачі через тайм-аут.

Використання іменованого порту

Ви можете використовувати іменований port для проб HTTP та TCP. Проби gRPC не підтримують іменовані порти.

Наприклад:

ports:
- name: liveness-port
  containerPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port

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

Іноді вам доводиться мати справу з застосунками, які вимагають додаткового часу запуску при їх першій ініціалізації. У таких випадках може бути складно налаштувати параметри проби життєздатності без компромісів щодо швидкої відповіді на затримки, які мотивували використання такої проби. Рішення полягає в тому, щоб налаштувати пробу запуску з тою самою командою, перевіркою через HTTP або TCP, з failureThreshold * periodSeconds, достатньо довгим, щоб покрити найгірший випадок щодо часу запуску.

Отже, попередній приклад стане:

ports:
- name: liveness-port
  containerPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 1
  periodSeconds: 10

startupProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 30
  periodSeconds: 10

Завдяки пробі запуску застосунок матиме максимум 5 хвилин (30 * 10 = 300 с), щоб завершити свій запуск. Як тільки проба запуску вдалася один раз, проба життєздатності бере роль на себе, щоб забезпечити швидку відповідь на затримки роботи контейнера. Якщо проба запуску ніколи не вдається, контейнер буде зупинений після 300 с і підпадатиме під restartPolicy Podʼа.

Визначення проб готовності

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

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

readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5

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

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

Налаштування проб

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

  • initialDelaySeconds: Кількість секунд після запуску контейнера, перед тим як будуть запущені перевірки запуску, життєздатності або готовності. Якщо визначено пробу запуску, проби життєздатності та готовності не починаються, поки проба запуску не вдалася. Якщо значення periodSeconds більше, ніж initialDelaySeconds, то значення initialDelaySeconds буде проігнороване. Стандартно — 0 секунд. Мінімальне значення — 0.
  • periodSeconds: Як часто (у секундах) виконувати пробу. Стандартно — 10 секунд. Мінімальне значення — 1. Поки контейнер не має статусу Ready, ReadinessProbe може бути виконаний у час, відмінний від налаштованого інтервалу periodSeconds. Це робиться для того, щоб пришвидшити готовність Podʼа.
  • timeoutSeconds: Кількість секунд, після яких проба завершиться по тайм-ауту. Стандартно — 1 секунда. Мінімальне значення — 1.
  • successThreshold: Мінімальна послідовна кількість успіхів для того, щоб проба вважалася успішною після невдачі. Стандартно — 1. Має бути 1 для проб життєздатності та запуску. Мінімальне значення — 1.
  • failureThreshold: Після того, як проба не вдається failureThreshold разів поспіль, Kubernetes вважає, що загальна перевірка невдала: контейнер не готовий/справний. У випадку проби запуску або життєздатності, якщо принаймні failureThreshold проб зазнали невдачі, Kubernetes розглядає контейнер як несправний та виконує перезапуск для цього конкретного контейнера. Kubelet дотримується налаштування terminationGracePeriodSeconds для цього контейнера. Для невдалих проб готовності kubelet продовжує запускати контейнер, який не пройшов перевірку, і також продовжує запускати додаткові проби; через те, що перевірка не пройшла, kubelet встановлює умову Ready для Podʼа у значення false.
  • terminationGracePeriodSeconds: налаштуйте період-допуск для kubelet, щоб чекати між тригером вимкнення невдалих контейнерів та примусовим зупиненням контейнера середовищем виконання. Стандартно — значення успадковується від рівня Podʼа для terminationGracePeriodSeconds (якщо не вказано, то 30 секунд), а мінімальне значення — 1. Див. terminationGracePeriodSeconds на рівні проби для більш детальної інформації.

HTTP проби

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

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

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

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

  • User-Agent: Стандартне значення — kube-probe/1.32, де 1.32 — версія kubelet.
  • Accept: Стандартне значення — */*.

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

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

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

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

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

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

TCP проби

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

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

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

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

При встановленні terminationGracePeriodSeconds слід звернути увагу на наступне:

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

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

Наприклад:

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

    ports:
    - name: liveness-port
      containerPort: 8080

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

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

Що далі

Також ви можете прочитати API-посилання на:

17 - Призначення Podʼів на вузли

Ця сторінка показує, як призначити Pod Kubernetes на певний вузол в кластері Kubernetes.

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

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

Для перевірки версії введіть kubectl version.

Додайте мітку до вузла

  1. Виведіть список вузлів у вашому кластері разом з їхніми мітками:

    kubectl get nodes --show-labels
    

    Вивід буде схожий на такий:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    
  2. Виберіть один з ваших вузлів і додайте до нього мітку:

    kubectl label nodes <your-node-name> disktype=ssd
    

    де <your-node-name> — це імʼя вашого обраного вузла.

  3. Перевірте, що ваш обраний вузол має мітку disktype=ssd:

    kubectl get nodes --show-labels
    

    Вивід буде схожий на такий:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,disktype=ssd,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    

    У попередньому виводі можна побачити, що вузол worker0 має мітку disktype=ssd.

Створіть Pod, який буде призначений на ваш обраний вузол

Цей файл конфігурації Podʼа описує Pod, який має селектор вузла disktype: ssd. Це означає, що Pod буде призначений на вузол, який має мітку disktype=ssd.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
  1. Використайте файл конфігурації, щоб створити Pod, який буде призначений на ваш обраний вузол:

    kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml
    
  2. Перевірте, що Pod працює на вашому обраному вузлі:

    kubectl get pods --output=wide
    

    Вивід буде схожий на такий:

    NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
    nginx    1/1       Running   0          13s    10.200.0.4   worker0
    

Створіть Pod, який буде призначений на конкретний вузол

Ви також можете призначити Pod на один конкретний вузол, встановивши nodeName.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: foo-node # призначення Podʼу конкретному вузлу
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent

Використовуйте файл конфігурації, щоб створити Pod, який буде призначений тільки на foo-node.

Що далі

18 - Призначення Podʼів на вузли за допомогою спорідненості вузла

На цій сторінці показано, як призначити Pod Kubernetes на певний вузол за допомогою спорідненості вузла в кластері Kubernetes.

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

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

Версія вашого Kubernetes сервера має бути не старішою ніж v1.10. Для перевірки версії введіть kubectl version.

Додайте мітку до вузла

  1. Виведіть список вузлів у вашому кластері разом з їхніми мітками:

    kubectl get nodes --show-labels
    

    Вивід буде схожий на такий:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    
  2. Виберіть один з ваших вузлів і додайте до нього мітку:

    kubectl label nodes <your-node-name> disktype=ssd
    

    де <your-node-name> — це імʼя вашого обраного вузла.

  3. Перевірте, що ваш обраний вузол має мітку disktype=ssd:

    kubectl get nodes --show-labels
    

    Вивід буде схожий на такий:

    NAME      STATUS    ROLES    AGE     VERSION        LABELS
    worker0   Ready     <none>   1d      v1.13.0        ...,disktype=ssd,kubernetes.io/hostname=worker0
    worker1   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker1
    worker2   Ready     <none>   1d      v1.13.0        ...,kubernetes.io/hostname=worker2
    

    У попередньому виводі можна побачити, що вузол worker0 має мітку disktype=ssd.

Розмістіть Pod, використовуючи потрібну спорідненість вузла

Цей маніфест описує Pod, який має спорідненість вузла requiredDuringSchedulingIgnoredDuringExecution, disktype: ssd. Це означає, що Pod буде розміщений лише на вузлі, який має мітку disktype=ssd.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd            
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  1. Застосуйте маніфест, щоб створити Pod, який буде розміщений на вашому обраному вузлі:

    kubectl apply -f https://k8s.io/examples/pods/pod-nginx-required-affinity.yaml
    
  2. Перевірте, що Pod працює на вашому обраному вузлі:

    kubectl get pods --output=wide
    

    Вивід буде схожий на такий:

    NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
    nginx    1/1       Running   0          13s    10.200.0.4   worker0
    

Розмістіть Pod, використовуючи бажану спорідненість вузла

Цей маніфест описує Pod, який має бажану спорідненість вузла preferredDuringSchedulingIgnoredDuringExecution, disktype: ssd. Це означає, що Pod надасть перевагу вузлу, який має мітку disktype=ssd.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd          
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  1. Застосуйте маніфест, щоб створити Pod, який буде розміщений на вашому обраному вузлі:

    kubectl apply -f https://k8s.io/examples/pods/pod-nginx-preferred-affinity.yaml
    
  2. Перевірте, що Pod працює на вашому обраному вузлі:

    kubectl get pods --output=wide
    

    Вивід буде схожий на такий:

    NAME     READY     STATUS    RESTARTS   AGE    IP           NODE
    nginx    1/1       Running   0          13s    10.200.0.4   worker0
    

Що далі

Дізнайтеся більше про Спорідненість вузла.

19 - Налаштування ініціалізації Podʼа

На цій сторінці показано, як використовувати Init Container для ініціалізації Podʼа перед запуском контейнера застосунку.

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

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

Для перевірки версії введіть kubectl version.

Створіть Pod, який має Init Container

У цьому завданні ви створите Pod, який має один контейнер застосунку та один Init Container. Контейнер ініціалізації виконується до завершення перед тим, як розпочне виконання контейнер застосунку.

Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  # Цей контейр виконуєть під час ініціалізації podʼу
  initContainers:
  - name: install
    image: busybox:1.28
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - http://info.cern.ch
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  dnsPolicy: Default
  volumes:
  - name: workdir
    emptyDir: {}

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

Контейнер ініціалізації монтує спільний Том у /work-dir, а контейнер застосунку монтує спільний Том у /usr/share/nginx/html. Контейнер ініціалізації виконує наступну команду, а потім завершується:

wget -O /work-dir/index.html http://info.cern.ch

Зверніть увагу, що контейнер ініціалізації записує файл index.html в кореневу теку сервера nginx.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/init-containers.yaml

Перевірте, що контейнер nginx працює:

kubectl get pod init-demo

Вивід показує, що контейнер nginx працює:

NAME        READY     STATUS    RESTARTS   AGE
init-demo   1/1       Running   0          1m

Отримайте доступ до оболонки в контейнері nginx, що працює в Podʼі init-demo:

kubectl exec -it init-demo -- /bin/bash

У своїй оболонці надішліть запит GET на сервер nginx:

root@nginx:~# apt-get update
root@nginx:~# apt-get install curl
root@nginx:~# curl localhost

Вивід показує, що nginx обслуговує вебсторінку, яку записав контейнер ініціалізації:

<html><head></head><body><header>
<title>http://info.cern.ch</title>
</header>

<h1>http://info.cern.ch - home of the first website</h1>
  ...
  <li><a href="http://info.cern.ch/hypertext/WWW/TheProject.html">Browse the first website</a></li>
  ...

Що далі

20 - Обробники подій життєвого циклу контейнера

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

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

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

Для перевірки версії введіть kubectl version.

Визначте обробники postStart та preStop

У цьому завдані ви створите Pod, який має один контейнер. У контейнері встановлені обробники для подій postStart та preStop.

Ось файл конфігурації для Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]

У файлі конфігурації ви бачите, що команда postStart записує файл message в теку /usr/share контейнера. Команда preStop відповідним чином вимикає nginx. Це корисно, якщо контейнер перериває роботу через помилку.

Створіть Pod:

kubectl apply -f https://k8s.io/examples/pods/lifecycle-events.yaml

Перевірте, що контейнер у Podʼі працює:

kubectl get pod lifecycle-demo

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

kubectl exec -it lifecycle-demo -- /bin/bash

У своїй оболонці перевірте, що обробник postStart створив файл message:

root@lifecycle-demo:/# cat /usr/share/message

Вивід показує текст, записаний обробником postStart:

Hello from the postStart handler

Обговорення

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

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

Що далі

Довідка

21 - Налаштування Podʼів для використання ConfigMap

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

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

Ця сторінка надає ряд прикладів, які демонструють як створювати ConfigMap та налаштувати Podʼи для використання даних, що містяться в ConfigMap.

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

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

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

Створення ConfigMap

Ви можете скористатись або kubectl create configmap або генератором ConfigMap в kustomization.yaml для створення ConfigMap.

Створення ConfigMap за допомогою kubectl create configmap

Скористайтесь командою kubectl create configmap, щоб створити ConfigMap з тек, файлів, або літералів:

kubectl create configmap <map-name> <data-source>

де, <map-name> — це імʼя ConfigMap, а <data-source> — це тека, файл чи літерал з даними, які ви хочете включити в ConfigMap. Імʼя обʼєкта ConfigMap повинно бути вірним імʼям субдомену DNS.

Коли ви створюєте ConfigMap на основі файлу, ключ в <data-source> визначається імʼям файлу, а значення — вмістом файлу.

Ви можете використовувати kubectl describe або kubectl get для отримання інформації про ConfigMap.

Створення ConfigMap з тек

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

Створіть локальну теку:

mkdir -p configure-pod-container/configmap/

Тепер завантажте приклад конфігурації та створіть ConfigMap:

# Завантажте файли у теку `configure-pod-container/configmap/`
wget https://kubernetes.io/examples/configmap/game.properties -O configure-pod-container/configmap/game.properties
wget https://kubernetes.io/examples/configmap/ui.properties -O configure-pod-container/configmap/ui.properties

# Створіть ConfigMap
kubectl create configmap game-config --from-file=configure-pod-container/configmap/

Вказана вище команда упаковує кожен файл, у цьому випадку game.properties та ui.properties у теці configure-pod-container/configmap/ у ConfigMap game-config. Ви можете показати деталі ConfigMap за допомогою наступної команди:

kubectl describe configmaps game-config

Вивід буде приблизно таким:

Name:         game-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

Файли game.properties та ui.properties у теці configure-pod-container/configmap/ представлені у секції data ConfigMap.

kubectl get configmaps game-config -o yaml

Вивід буде приблизно таким:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2022-02-18T18:52:05Z
  name: game-config
  namespace: default
  resourceVersion: "516"
  uid: b4952dc3-d670-11e5-8cd0-68f728db1985
data:
  game.properties: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30    
  ui.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice    

Створення ConfigMaps з файлів

Ви можете використовувати kubectl create configmap для створення ConfigMap з окремого файлу або з декількох файлів.

Наприклад,

kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties

створить наступний ConfigMap:

kubectl describe configmaps game-config-2

де вивід буде схожий на це:

Name:         game-config-2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30

Ви можете вказати аргумент --from-file кілька разів, щоб створити ConfigMap із кількох джерел даних.

kubectl create configmap game-config-2 --from-file=configure-pod-container/configmap/game.properties --from-file=configure-pod-container/configmap/ui.properties

Можете переглянути деталі ConfigMap game-config-2 за допомогою наступної команди:

kubectl describe configmaps game-config-2

Вивід буде схожий на це:

Name:         game-config-2
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
ui.properties:
----
color.good=purple
color.bad=yellow
allow.textmode=true
how.nice.to.look=fairlyNice

Використовуйте опцію --from-env-file для створення ConfigMap з env-файлу, наприклад:

# Env-файли містять список змінних оточення.
# На ці синтаксичні правила слід звертати увагу:
#   Кожен рядок у env-файлі повинен бути у форматі VAR=VAL.
#   Рядки, які починаються з # (тобто коментарі), ігноруються.
#   Порожні рядки ігноруються.
#   Особливого врахування лапок немає (тобто вони будуть частиною значення у ConfigMap).

# Завантажте приклад файлів у теку `configure-pod-container/configmap/`
wget https://kubernetes.io/examples/configmap/game-env-file.properties -O configure-pod-container/configmap/game-env-file.properties
wget https://kubernetes.io/examples/configmap/ui-env-file.properties -O configure-pod-container/configmap/ui-env-file.properties

# Env-файл `game-env-file.properties` виглядає так
cat configure-pod-container/configmap/game-env-file.properties
enemies=aliens
lives=3
allowed="true"

# Цей коментар та порожній рядок вище ігноруються
kubectl create configmap game-config-env-file \
       --from-env-file=configure-pod-container/configmap/game-env-file.properties

створить ConfigMap. Перегляньте ConfigMap:

kubectl get configmap game-config-env-file -o yaml

вивід буде схожий на:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2019-12-27T18:36:28Z
  name: game-config-env-file
  namespace: default
  resourceVersion: "809965"
  uid: d9d1ca5b-eb34-11e7-887b-42010a8002b8
data:
  allowed: '"true"'
  enemies: aliens
  lives: "3"

Починаючи з Kubernetes v1.23, kubectl підтримує аргумент --from-env-file, який може бути вказаний кілька разів для створення ConfigMap із кількох джерел даних.

kubectl create configmap config-multi-env-files \
        --from-env-file=configure-pod-container/configmap/game-env-file.properties \
        --from-env-file=configure-pod-container/configmap/ui-env-file.properties

створить наступний ConfigMap:

kubectl get configmap config-multi-env-files -o yaml

де вивід буде схожий на це:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2019-12-27T18:38:34Z
  name: config-multi-env-files
  namespace: default
  resourceVersion: "810136"
  uid: 252c4572-eb35-11e7-887b-42010a8002b8
data:
  allowed: '"true"'
  color: purple
  enemies: aliens
  how: fairlyNice
  lives: "3"
  textmode: "true"

Визначення ключа для створення ConfigMap з файлу

Ви можете визначити ключ, відмінний від імені файлу, який буде використаний у розділі data вашого ConfigMap під час використання аргументу --from-file:

kubectl create configmap game-config-3 --from-file=<my-key-name>=<path-to-file>

де <my-key-name> — це ключ, який ви хочете використовувати в ConfigMap, а <path-to-file> — це місцезнаходження файлу джерела даних, яке ключ має представляти.

Наприклад:

kubectl create configmap game-config-3 --from-file=game-special-key=configure-pod-container/configmap/game.properties

створить наступний ConfigMap:

kubectl get configmaps game-config-3 -o yaml

де вивід буде схожий на це:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2022-02-18T18:54:22Z
  name: game-config-3
  namespace: default
  resourceVersion: "530"
  uid: 05f8da22-d671-11e5-8cd0-68f728db1985
data:
  game-special-key: |
    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30    

Створення ConfigMaps з літеральних значень

Ви можете використовувати kubectl create configmap з аргументом --from-literal, щоб визначити літеральне значення з командного рядка:

kubectl create configmap special-config --from-literal=special.how=very --from-literal=special.type=charm

Ви можете передати декілька пар ключ-значення. Кожна пара, надана у командному рядку, представлена як окремий запис у розділі data ConfigMap.

kubectl get configmaps special-config -o yaml

Вивід буде схожий на це:

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2022-02-18T19:14:38Z
  name: special-config
  namespace: default
  resourceVersion: "651"
  uid: dadce046-d673-11e5-8cd0-68f728db1985
data:
  special.how: very
  special.type: charm

Створення ConfigMap за допомогою генератора

Ви також можете створити ConfigMap за допомогою генераторів, а потім застосувати його для створення обʼєкта на API сервері кластера. Ви повинні вказати генератори у файлі kustomization.yaml в межах теки.

Генерація ConfigMaps з файлів

Наприклад, для створення ConfigMap з файлів configure-pod-container/configmap/game.properties:

# Створіть файл kustomization.yaml з ConfigMapGenerator
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-4
  options:
    labels:
      game-config: config-4
  files:
  - configure-pod-container/configmap/game.properties
EOF

Застосуйте теку kustomization для створення обʼєкта ConfigMap:

kubectl apply -k .
configmap/game-config-4-m9dm2f92bt created

Ви можете перевірити, що ConfigMap був створений так:

kubectl get configmap
NAME                       DATA   AGE
game-config-4-m9dm2f92bt   1      37s

а також:

kubectl describe configmaps game-config-4-m9dm2f92bt
Name:         game-config-4-m9dm2f92bt
Namespace:    default
Labels:       game-config=config-4
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"v1","data":{"game.properties":"enemies=aliens\nlives=3\nenemies.cheat=true\nenemies.cheat.level=noGoodRotten\nsecret.code.p...

Data
====
game.properties:
----
enemies=aliens
lives=3
enemies.cheat=true
enemies.cheat.level=noGoodRotten
secret.code.passphrase=UUDDLRLRBABAS
secret.code.allowed=true
secret.code.lives=30
Events:  <none>

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

Визначення ключа для використання при генерації ConfigMap з файлу

Ви можете визначити ключ, відмінний від імені файлу, для використання у генераторі ConfigMap. Наприклад, для генерації ConfigMap з файлів configure-pod-container/configmap/game.properties з ключем game-special-key:

# Створіть файл kustomization.yaml з ConfigMapGenerator
cat <<EOF >./kustomization.yaml
configMapGenerator:
- name: game-config-5
  options:
    labels:
      game-config: config-5
  files:
  - game-special-key=configure-pod-container/configmap/game.properties
EOF

Застосуйте теки kustomization для створення обʼєкта ConfigMap.

kubectl apply -k .
configmap/game-config-5-m67dt67794 created

Генерація ConfigMap з літералів

У цьому прикладі показано, як створити ConfigMap з двох пар ключ/значення: special.type=charm та special.how=very, використовуючи Kustomize та kubectl. Для досягнення цього, ви можете вказати генератор ConfigMap. Створіть (або замініть) kustomization.yaml, щоб мати наступний вміст:

---
# Вміст kustomization.yaml для створення ConfigMap з літералів
configMapGenerator:
- name: special-config-2
  literals:
  - special.how=very
  - special.type=charm

Застосуйте теку kustomization для створення обʼєкта ConfigMap:

kubectl apply -k .
configmap/special-config-2-c92b5mmcf2 created

Проміжна очистка

Перед продовженням, очистіть деякі з ConfigMaps, які ви створили:

kubectl delete configmap special-config
kubectl delete configmap env-config
kubectl delete configmap -l 'game-config in (config-4,config-5)'

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


Визначення змінних середовища контейнера за допомогою даних з ConfigMap

Визначення змінної середовища контейнера за допомогою даних з одного ConfigMap

  1. Визначте змінну середовища як пару ключ-значення в ConfigMap:

    kubectl create configmap special-config --from-literal=special.how=very
    
  2. Присвойте значення special.how, визначене в ConfigMap, змінній середовища SPECIAL_LEVEL_KEY у специфікації Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: registry.k8s.io/busybox
          command: [ "/bin/sh", "-c", "env" ]
          env:
            # Визначення змінної середовища
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  # ConfigMap, що містить значення, яке потрібно присвоїти SPECIAL_LEVEL_KEY
                  name: special-config
                  # Вказує ключ, повʼязаний зі значенням
                  key: special.how
      restartPolicy: Never
    

    Створіть Pod:

    kubectl create -f https://kubernetes.io/examples/pods/pod-single-configmap-env-variable.yaml
    

    Тепер вивід Podʼа містить змінну середовища SPECIAL_LEVEL_KEY=very.

Визначення змінних середовища контейнера з даних з кількох ConfigMaps

Так само як у попередньому прикладі, спочатку створіть ConfigMaps. Ось маніфест, який ви будете використовувати:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config
  namespace: default
data:
  log_level: INFO
  • Створіть ConfigMap:

    kubectl create -f https://kubernetes.io/examples/configmap/configmaps.yaml
    
  • Визначте змінні середовища у специфікації Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: registry.k8s.io/busybox
          command: [ "/bin/sh", "-c", "env" ]
          env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  name: special-config
                  key: special.how
            - name: LOG_LEVEL
              valueFrom:
                configMapKeyRef:
                  name: env-config
                  key: log_level
      restartPolicy: Never
    

    Створіть Pod:

    kubectl create -f https://kubernetes.io/examples/pods/pod-multiple-configmap-env-variable.yaml
    

    Тепер виведення Pod містить змінні середовища SPECIAL_LEVEL_KEY=very та LOG_LEVEL=INFO.

    Як тільки ви готові перейти далі, видаліть цей Pod та ConfigMaps:

    kubectl delete pod dapi-test-pod --now
    kubectl delete configmap special-config
    kubectl delete configmap env-config
    

Налаштування всіх пар ключ-значення в ConfigMap як змінних середовища контейнера

  • Створіть ConfigMap, який містить кілька пар ключ-значення.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: special-config
      namespace: default
    data:
      SPECIAL_LEVEL: very
      SPECIAL_TYPE: charm
    

    Створіть ConfigMap:

    kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml
    
  • Використовуйте envFrom, щоб визначити всі дані ConfigMap як змінні середовища контейнера. Ключ з ConfigMap стає іменем змінної середовища в Pod.

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: registry.k8s.io/busybox
          command: [ "/bin/sh", "-c", "env" ]
          envFrom:
          - configMapRef:
              name: special-config
      restartPolicy: Never
    

    Створіть Pod:

    kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-envFrom.yaml
    

    Тепер виведення Pod містить змінні середовища SPECIAL_LEVEL=very та SPECIAL_TYPE=charm.

    Як тільки ви готові перейти далі, видаліть цей Pod:

    kubectl delete pod dapi-test-pod --now
    

Використання змінних середовища, визначених у ConfigMap, у командах Pod

Ви можете використовувати змінні середовища, визначені у ConfigMap, у розділі command та args контейнера за допомогою синтаксису підстановки Kubernetes $(VAR_NAME).

Наприклад, у наступному маніфесті Pod:

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/echo", "$(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: SPECIAL_LEVEL
        - name: SPECIAL_TYPE_KEY
          valueFrom:
            configMapKeyRef:
              name: special-config
              key: SPECIAL_TYPE
  restartPolicy: Never

Створіть цей Pod, запустивши:

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-env-var-valueFrom.yaml

Цей Pod видає наступний вивід від контейнера test-container:

kubectl logs dapi-test-pod
very charm

Як тільки ви готові перейти далі, видаліть цей Pod:

kubectl delete pod dapi-test-pod --now

Додавання даних ConfigMap до тому

Як пояснено у розділі Створення ConfigMap з файлів, коли ви створюєте ConfigMap, використовуючи --from-file, імʼя файлу стає ключем, збереженим у розділі data ConfigMap. Вміст файлу стає значенням ключа.

Приклади в цьому розділі відносяться до ConfigMap з іменем special-config:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  SPECIAL_LEVEL: very
  SPECIAL_TYPE: charm

Створіть ConfigMap:

kubectl create -f https://kubernetes.io/examples/configmap/configmap-multikeys.yaml

Заповнення тому даними, збереженими в ConfigMap

Додайте імʼя ConfigMap у розділ volumes специфікації Pod. Це додасть дані ConfigMap до теки, вказаної як volumeMounts.mountPath (у цьому випадку, /etc/config). Розділ command перераховує файли теки з іменами, що відповідають ключам у ConfigMap.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh", "-c", "ls /etc/config/" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        # Надає назву ConfigMap, що містить файли, які ви бажаєте
        # додати до контейнера
        name: special-config
  restartPolicy: Never

Створіть Pod:

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume.yaml

Коли Pod працює, команда ls /etc/config/ виводить наступне:

SPECIAL_LEVEL
SPECIAL_TYPE

Текстові дані показуються у вигляді файлів з використанням кодування символів UTF-8. Щоб використовувати інше кодування символів, скористайтеся binaryData (див. обʼєкт ConfigMap для докладніших відомостей).

Якщо ви готові перейти до наступного кроку, видаліть цей Pod:

kubectl delete pod dapi-test-pod --now

Додавання конфігурації ConfigMap до певного шляху у томі

Використовуйте поле path, щоб вказати бажаний шлях до файлів для конкретних елементів ConfigMap. У цьому випадку елемент SPECIAL_LEVEL буде змонтовано у томі config-volume за адресою /etc/config/keys.

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: registry.k8s.io/busybox
      command: [ "/bin/sh","-c","cat /etc/config/keys" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: special-config
        items:
        - key: SPECIAL_LEVEL
          path: keys
  restartPolicy: Never

Створіть pod:

kubectl create -f https://kubernetes.io/examples/pods/pod-configmap-volume-specific-key.yaml

Коли pod запущено, команда cat /etc/config/keys видасть наведений нижче вивід:

very

Видаліть цей Pod:

kubectl delete pod dapi-test-pod --now

Спроєцюйте ключі на конкретні шляхи та встановлюйте права доступу до файлів

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

Необовʼязкові посилання

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

Змонтовані ConfigMap оновлюються автоматично

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

Kubelet перевіряє, чи змонтований ConfigMap є актуальним під час кожної періодичної синхронізації. Однак він використовує свій локальний кеш на основі TTL для отримання поточного значення ConfigMap. В результаті загальна затримка від моменту оновлення ConfigMap до моменту, коли нові ключі проєцюються у Pod може бути таким, як період синхронізації kubelet (стандартно — 1 хвилина) + TTL кешу ConfigMaps (стандартно — 1 хвилина) в kubelet. Ви можете викликати негайне оновлення, оновивши одну з анотацій Podʼа.

Розуміння ConfigMap та Podʼів

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

Поле data у ConfigMap містить дані конфігурації. Як показано у прикладі нижче, це може бути простим (наприклад, окремі властивості, визначені за допомогою --from-literal) або складним (наприклад, файли конфігурації або JSON-фрагменти, визначені за допомогою --from-file).

apiVersion: v1
kind: ConfigMap
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: example-config
  namespace: default
data:
  # приклад простої властивості, визначеної за допомогою --from-literal
  example.property.1: hello
  example.property.2: world
  # приклад складної властивості, визначеної за допомогою --from-file
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3    

Коли kubectl створює ConfigMap з вхідних даних, які не є ASCII або UTF-8, цей інструмент поміщає їх у поле binaryData ConfigMap, а не в data. Як текстові, так і бінарні дані можуть бути поєднані в одному ConfigMap.

Якщо ви хочете переглянути ключі binaryData (і їх значення) в ConfigMap, ви можете виконати kubectl get configmap -o jsonpath='{.binaryData}' <імʼя>.

Podʼи можуть завантажувати дані з ConfigMap, що використовують як data, так і binaryData.

Опціональні ConfigMaps

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

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

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: ["/bin/sh", "-c", "env"]
      env:
        - name: SPECIAL_LEVEL_KEY
          valueFrom:
            configMapKeyRef:
              name: a-config
              key: akey
              optional: true # позначає змінну як опціональну
  restartPolicy: Never

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

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

apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
    - name: test-container
      image: gcr.io/google_containers/busybox
      command: ["/bin/sh", "-c", "ls /etc/config"]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: no-config
        optional: true # позначає ConfigMap як опціональний
  restartPolicy: Never

Обмеження

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

  • Якщо ви використовуєте envFrom для визначення змінних середовища з ConfigMaps, ключі, які вважаються недійсними, будуть пропущені. Podʼу буде дозволено запускатися, але недійсні імена будуть записані в лог подій (InvalidVariableNames). Повідомлення логу містить кожен пропущений ключ. Наприклад:

    kubectl get events
    

    Вивід буде схожий на цей:

    LASTSEEN FIRSTSEEN COUNT NAME          KIND  SUBOBJECT  TYPE      REASON                            SOURCE                MESSAGE
    0s       0s        1     dapi-test-pod Pod              Warning   InvalidEnvironmentVariableNames   {kubelet, 127.0.0.1}  Keys [1badkey, 2alsobad] from the EnvFrom configMap default/myconfig were skipped since they are considered invalid environment variable names.
    
  • ConfigMaps знаходяться в конкретному Namespace. Podʼи можуть посилатися лише на ConfigMaps, які знаходяться в тому ж контексті, що і сам Pod.

  • Ви не можете використовувати ConfigMaps для статичних Podʼів, оскільки kubelet їх не підтримує.

Очищення

Вилучить ConfigMaps та Pod, які ви створили, використовуючи наступні команди:

kubectl delete configmaps/game-config configmaps/game-config-2 configmaps/game-config-3 \
               configmaps/game-config-env-file
kubectl delete pod dapi-test-pod --now

# Можливо, ви вже видалили наступний набір
kubectl delete configmaps/special-config configmaps/env-config
kubectl delete configmap -l 'game-config in (config-4,config-5)'

Видаліть файл kustomization.yaml, який ви створили для генерації ConfigMap:

rm kustomization.yaml

Якщо ви створили ntre configure-pod-container і вже не потребуєте її, вам слід також її видалити або перемістити в кошик або місце для видалених файлів.

rm -rf configure-pod-container

Що далі

22 - Поділ простору імен процесів між контейнерами у Podʼі

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

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

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

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

Налаштування Podʼа

Поділ простору імен процесів увімкнено за допомогою поля shareProcessNamespace в розділі .spec Podʼа. Наприклад:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox:1.28
    command: ["sleep", "3600"]
    securityContext:
      capabilities:
        add:
        - SYS_PTRACE
    stdin: true
    tty: true
  1. Створіть Pod nginx у вашому кластері:

    kubectl apply -f https://k8s.io/examples/pods/share-process-namespace.yaml
    
  2. Приєднайтеся до контейнера shell та запустіть команду ps:

    kubectl exec -it nginx -c shell -- /bin/sh
    

    Якщо ви не бачите символу командного рядка, спробуйте натиснути клавішу Enter. У оболонці контейнера:

    # виконайте це всередині контейнера "shell"
    ps ax
    

    Вивід схожий на такий:

    PID   USER     TIME  COMMAND
        1 root      0:00 /pause
        8 root      0:00 nginx: master process nginx -g daemon off;
       14 101       0:00 nginx: worker process
       15 root      0:00 sh
       21 root      0:00 ps ax
    

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

# виконайте це всередині контейнера "shell"
kill -HUP 8   # змініть "8" на відповідний PID лідера процесу nginx, якщо потрібно
ps ax

Вивід схожий на такий:

PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 nginx: master process nginx -g daemon off;
   15 root      0:00 sh
   22 101       0:00 nginx: worker process
   23 root      0:00 ps ax

Навіть можливо отримати доступ до файлової системи іншого контейнера, використовуючи посилання /proc/$pid/root.

# виконайте це всередині контейнера "shell"
# змініть "8" на PID процесу Nginx, якщо потрібно
head /proc/8/root/etc/nginx/nginx.conf

Вивід схожий на такий:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;

Розуміння поділу простору імен процесів

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

  1. Процес контейнера вже не має PID 1. Деякі контейнери відмовляються запускатися без PID 1 (наприклад, контейнери, що використовують systemd) або виконують команди типу kill -HUP 1 для відправлення сигналу процесу контейнера. У Podʼах зі спільним простором імен процесів kill -HUP 1 відправить сигнал пісочниці Podʼа (/pause у вищезазначеному прикладі).

  2. Процеси видимі іншим контейнерам у Podʼі. Це включає всю інформацію, доступну у /proc, таку як паролі, що були передані як аргументи або змінні середовища. Ці дані захищені лише звичайними правами Unix.

  3. Файлові системи контейнерів видимі іншим контейнерам у Podʼі через посилання /proc/$pid/root. Це полегшує налагодження, але також означає, що секрети файлової системи захищені лише правами файлової системи.

23 - Використання простору імен користувача з Podʼом

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

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

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

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

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

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

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

Версія вашого Kubernetes сервера має бути не старішою ніж v1.25. Для перевірки версії введіть kubectl version.

  • ОС вузла повинна бути Linux
  • Ви повинні мати можливість виконувати команди на хості
  • Ви повинні мати можливість виконувати команди у Podʼах
  • Вам потрібно увімкнути функціональну можливість UserNamespacesSupport

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

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

Запуск Podʼа, що використовує простір імен користувача

Простір імен користувача для Podʼа вимкається, встановленням поля hostUsers в .spec на false. Наприклад:

apiVersion: v1
kind: Pod
metadata:
  name: userns
spec:
  hostUsers: false
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian
  1. Створіть Pod у вашому кластері:

    kubectl apply -f https://k8s.io/examples/pods/user-namespaces-stateless.yaml
    
  2. Приєднайтеся до контейнера і виконайте readlink /proc/self/ns/user:

    kubectl attach -it userns bash
    

Виконайте цю команду:

read

link /proc/self/ns/user

Вивід схожий на:

user:[4026531837]

Також виконайте:

cat /proc/self/uid_map

Вивід схожий на:

0  833617920      65536

Потім відкрийте оболонку на хості та виконайте ті ж самі команди.

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

Останнє число у файлі uid_map всередині контейнера повинно бути 65536, на хості це число повинно бути більшим.

Якщо ви запускаєте kubelet всередині простору імен користувача, вам потрібно порівняти вивід команди в Pod з виводом, отриманим на хості:

readlink /proc/$pid/ns/user

замінивши $pid на PID kubelet.

24 - Використання тому Image в Pod

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

Ця сторінка демонструє, як налаштувати Pod для використання томів image. Це дозволяє монтувати вміст з OCI реєстрів всередині контейнерів.

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

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

Версія вашого Kubernetes сервера має бути не старішою ніж v1.31. Для перевірки версії введіть kubectl version.

  • Середовище виконання контейнерів має підтримувати функцію томів image.
  • Вам потрібно мати можливість виконувати команди на хості.
  • Вам потрібно мати можливість підключатися до pod.
  • Вам потрібно увімкнути функціональну можливість ImageVolume.

Запуск Podʼа, що використовує том image

Том image для Podʼа активується шляхом налаштування поля volumes.[*].image у .spec на дійсне посилання та використання його в volumeMounts контейнера. Наприклад:

apiVersion: v1
kind: Pod
metadata:
  name: image-volume
spec:
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian
    volumeMounts:
    - name: volume
      mountPath: /volume
  volumes:
  - name: volume
    image:
      reference: quay.io/crio/artifact:v1
      pullPolicy: IfNotPresent
  1. Створіть Pod у вашому кластері:

    kubectl apply -f https://k8s.io/examples/pods/image-volumes.yaml
    
  2. Приєднайтесь до контейнера:

    kubectl attach -it image-volume bash
    
  3. Перевірте вміст файлу в томі:

    cat /volume/dir/file
    

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

    1
    

    Ви також можете перевірити інший файл з іншим шляхом:

    cat /volume/file
    

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

    2
    

Додатково

25 - Створення статичних Podʼів

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

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

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

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

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

Для перевірки версії введіть kubectl version.

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

Створення статичного Podʼа

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

Статичний Pod з файлової системи

Маніфести — це стандартні визначення Podʼів у форматі JSON або YAML в певній теці. Використовуйте поле staticPodPath: <тека> у конфігураційному файлі kubelet, який періодично сканує теку і створює/видаляє статичні Podʼи, коли у цій теці зʼявляються/зникають файли YAML/JSON. Зверніть увагу, що kubelet ігнорує файли, що починаються з крапки при скануванні вказаної теки.

Наприклад, так можна запустити простий вебсервер як статичний Pod:

  1. Виберіть вузол, на якому ви хочете запустити статичний Pod. У цьому прикладі це my-node1.

    ssh my-node1
    
  2. Виберіть теку, наприклад /etc/kubernetes/manifests, і помістіть туди визначення Podʼа вебсервера, наприклад, /etc/kubernetes/manifests/static-web.yaml:

    # Виконайте цю команду на вузлі, де працює kubelet
    mkdir -p /etc/kubernetes/manifests/
    cat <<EOF >/etc/kubernetes/manifests/static-web.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: static-web
      labels:
        role: myrole
    spec:
      containers:
        - name: web
          image: nginx
          ports:
            - name: web
              containerPort: 80
              protocol: TCP
    EOF
    
  3. Налаштуйте kubelet на тому вузлі, щоб встановити значення staticPodPath в конфігураційному файлі kubelet. Див. Встановлення параметрів kubelet через конфігураційний файл для отримання додаткової інформації.

    Альтернативний і застарілий метод полягає в налаштуванні kubelet на тому вузлі, щоб він шукав маніфести статичного Podʼа локально, використовуючи аргумент командного рядка. Щоб використовувати застарілий підхід, запустіть kubelet з аргументом --pod-manifest-path=/etc/kubernetes/manifests/.

  4. Перезапустіть kubelet. У Fedora ви виконаєте:

    # Виконайте цю команду на вузлі, де працює kubelet
    systemctl restart kubelet
    

Маніфест Podʼа, розміщений на вебсервері

Kubelet періодично завантажує файл, вказаний аргументом --manifest-url=<URL>, і розглядає його як файл JSON/YAML, який містить визначення Podʼів. Подібно до того, як працюють маніфести, розміщені в файловій системі, kubelet перевіряє маніфест за розкладом. Якщо відбулися зміни в списку статичних Podʼів, kubelet застосовує їх.

Щоб скористатися цим підходом:

  1. Створіть YAML-файл і збережіть його на веб-сервері, щоб ви могли передати URL цього файлу kubelet.

    apiVersion: v1
    kind: Pod
    metadata:
      name: static-web
      labels:
        role: myrole
    spec:
      containers:
        - name: web
          image: nginx
          ports:
            - name: web
              containerPort: 80
              protocol: TCP
    
  2. Налаштуйте kubelet на обраному вузлі для використання цього веб-маніфесту, запустивши його з аргументом --manifest-url=<URL-маніфесту>. У Fedora відредагуйте /etc/kubernetes/kubelet, щоб додати цей рядок:

    KUBELET_ARGS="--cluster-dns=10.254.0.10 --cluster-domain=kube.local --manifest-url=<URL-маніфесту>"
    
  3. Перезапустіть kubelet. У Fedora ви виконаєте:

    # Виконайте цю команду на вузлі, де працює kubelet
    systemctl restart kubelet
    

Спостереження за поведінкою статичного Podʼа

Після запуску kubelet автоматично запускає всі визначені статичні Podʼи. Оскільки ви визначили статичний Pod і перезапустили kubelet, новий статичний Pod вже має бути запущений.

Ви можете переглянути запущені контейнери (включно зі статичними Podʼами), виконавши (на вузлі):

# Виконайте цю команду на вузлі, де працює kubelet
crictl ps

Вивід може бути наступним:

CONTAINER       IMAGE                                 CREATED           STATE      NAME    ATTEMPT    POD ID
129fd7d382018   docker.io/library/nginx@sha256:...    11 minutes ago    Running    web     0          34533c6729106

Ви можете побачити дзеркальний Pod на сервері API:

kubectl get pods
NAME                  READY   STATUS    RESTARTS        AGE
static-web-my-node1   1/1     Running   0               2m

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

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

kubectl delete pod static-web-my-node1
pod "static-web-my-node1" deleted

Ви побачите, що Pod все ще працює:

kubectl get pods
NAME                  READY   STATUS    RESTARTS   AGE
static-web-my-node1   1/1     Running   0          4s

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

# Виконайте ці команди на вузлі, де працює kubelet
crictl stop 129fd7d382018 # замініть на ID вашого контейнера
sleep 20
crictl ps
CONTAINER       IMAGE                                 CREATED           STATE      NAME    ATTEMPT    POD ID
89db4553e1eeb   docker.io/library/nginx@sha256:...    19 seconds ago    Running    web     1          34533c6729106

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

# Виконайте ці команди на вузлі, де працює контейнер
crictl logs <container_id>
10.240.0.48 - - [16/Nov/2022:12:45:49 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.48 - - [16/Nov/2022:12:45:50 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"
10.240.0.48 - - [16/Nove/2022:12:45:51 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.47.0" "-"

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

Динамічне додавання та видалення статичних Podʼів

Запущений kubelet періодично сканує налаштовану теку (/etc/kubernetes/manifests у нашому прикладі) на предмет змін та додає/видаляє Podʼи при появі/зникненні файлів в цій теці.

# Це передбачає, що ви використовуєте файлову конфігурацію статичних Podʼів
# Виконайте ці команди на вузлі, де працює контейнер
#
mv /etc/kubernetes/manifests/static-web.yaml /tmp
sleep 20
crictl ps
# Ви бачите, що ніякий контейнер nginx не працює
mv /tmp/static-web.yaml  /etc/kubernetes/manifests/
sleep 20
crictl ps
CONTAINER       IMAGE                                 CREATED           STATE      NAME    ATTEMPT    POD ID
f427638871c35   docker.io/library/nginx@sha256:...    19 seconds ago    Running    web     1          34533c6729106

Що далі

26 - Конвертація файлу Docker Compose в ресурси Kubernetes

Що таке Kompose? Це інструмент конвертації для всього, що стосується композиції (зокрема Docker Compose) в ресурси систем оркестрування (Kubernetes або OpenShift).

Додаткову інформацію можна знайти на вебсайті Kompose за адресою http://kompose.io.

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

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

Для перевірки версії введіть kubectl version.

Встановлення Kompose

Є кілька способів встановлення Kompose. Наш спосіб - завантаження бінарного файлу з останнього релізу GitHub.

Kompose випускається через GitHub кожні три тижні, ви можете переглянути всі поточні релізи на сторінці релізів GitHub.

# Linux
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-linux-amd64 -o kompose

# macOS
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-darwin-amd64 -o kompose

# Windows
curl -L https://github.com/kubernetes/kompose/releases/download/v1.34.0/kompose-windows-amd64.exe -o kompose.exe

chmod +x kompose
sudo mv ./kompose /usr/local/bin/kompose

Також ви можете завантажити архів.

Встановлення за допомогою go get витягує дані з гілки master з останніми змінами розробки.

go get -u github.com/kubernetes/kompose

Kompose є в репозиторії EPEL для CentOS. Якщо у вас ще немає встановленого та увімкненого репозиторію EPEL, ви можете зробити це, виконавши sudo yum install epel-release.

Якщо у вас увімкнений репозиторій EPEL у вашій системі, ви можете встановити Kompose як будь-який інший пакунок.

sudo yum -y install kompose

Kompose є в репозиторіях Fedora 24, 25 та 26. Ви можете встановити його, як і будь-який інший пакунок.

sudo dnf -y install kompose

У macOS ви можете встановити останній реліз за допомогою Homebrew:

brew install kompose

Використання Kompose

За кілька кроків ми переведемо вас з Docker Compose до Kubernetes. Вам потрібен лише наявний файл docker-compose.yml.

  1. Перейдіть до теки, що містить ваш файл docker-compose.yml. Якщо у вас його немає, ви можете випробувати використовуючи цей.

    
    services:
    
      redis-leader:
        container_name: redis-leader
        image: redis
        ports:
          - "6379"
    
      redis-replica:
        container_name: redis-replica
        image: redis
        ports:
          - "6379"
        command: redis-server --replicaof redis-leader 6379 --dir /tmp
    
      web:
        container_name: web
        image: quay.io/kompose/web
        ports:
          - "8080:8080"
        environment:
          - GET_HOSTS_FROM=dns
        labels:
          kompose.service.type: LoadBalancer
    
  2. Щоб конвертувати файл docker-compose.yml у файли, які можна використовувати з kubectl, запустіть kompose convert, а потім kubectl apply -f <output file>.

    kompose convert
    

    Вивід подібний до:

    INFO Kubernetes file "redis-leader-service.yaml" created
    INFO Kubernetes file "redis-replica-service.yaml" created
    INFO Kubernetes file "web-tcp-service.yaml" created
    INFO Kubernetes file "redis-leader-deployment.yaml" created
    INFO Kubernetes file "redis-replica-deployment.yaml" created
    INFO Kubernetes file "web-deployment.yaml" created
    
     kubectl apply -f web-tcp-service.yaml,redis-leader-service.yaml,redis-replica-service.yaml,web-deployment.yaml,redis-leader-deployment.yaml,redis-replica-deployment.yaml
    

    Вивід подібний до:

    deployment.apps/redis-leader created
    deployment.apps/redis-replica created
    deployment.apps/web created
    service/redis-leader created
    service/redis-replica created
    service/web-tcp created
    

    Ваші розгортання, що працюють в Kubernetes.

  3. Доступ до вашого застосунку.

    Якщо ви вже використовуєте minikube для вашого процесу розробки:

    minikube service web-tcp
    

    В іншому випадку, подивімось, яку IP використовує ваш Service!

    kubectl describe svc web-tcp
    
    Name:                     web-tcp
    Namespace:                default
    Labels:                   io.kompose.service=web-tcp
    Annotations:              kompose.cmd: kompose convert
                            kompose.service.type: LoadBalancer
                            kompose.version: 1.33.0 (3ce457399)
    Selector:                 io.kompose.service=web
    Type:                     LoadBalancer
    IP Family Policy:         SingleStack
    IP Families:              IPv4
    IP:                       10.102.30.3
    IPs:                      10.102.30.3
    Port:                     8080  8080/TCP
    TargetPort:               8080/TCP
    NodePort:                 8080  31624/TCP
    Endpoints:                10.244.0.5:8080
    Session Affinity:         None
    External Traffic Policy:  Cluster
    Events:                   <none>
    

    Якщо ви використовуєте хмарного постачальника, ваша IP буде вказана поруч з LoadBalancer Ingress.

    curl http://192.0.2.89
    
  4. Прибирання.

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

    kubectl delete -f web-tcp-service.yaml,redis-leader-service.yaml,redis-replica-service.yaml,web-deployment.yaml,redis-leader-deployment.yaml,redis-replica-deployment.yaml
    

Посібник користувача

Kompose підтримує двох провайдерів: OpenShift і Kubernetes. Ви можете вибрати відповідного постачальника, використовуючи глобальну опцію --provider. Якщо постачальник не вказаний, буде встановлено Kubernetes.

kompose convert

Kompose підтримує конвертацію файлів Docker Compose версій V1, V2 і V3 в обʼєкти Kubernetes та OpenShift.

Приклад kompose convert для Kubernetes

kompose --file docker-voting.yml convert
WARN Unsupported key networks - ignoring
WARN Unsupported key build - ignoring
INFO Kubernetes file "worker-svc.yaml" created
INFO Kubernetes file "db-svc.yaml" created
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "result-svc.yaml" created
INFO Kubernetes file "vote-svc.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
INFO Kubernetes file "result-deployment.yaml" created
INFO Kubernetes file "vote-deployment.yaml" created
INFO Kubernetes file "worker-deployment.yaml" created
INFO Kubernetes file "db-deployment.yaml" created
ls
db-deployment.yaml  docker-compose.yml         docker-gitlab.yml  redis-deployment.yaml  result-deployment.yaml  vote-deployment.yaml  worker-deployment.yaml
db-svc.yaml         docker-voting.yml          redis-svc.yaml     result-svc.yaml        vote-svc.yaml           worker-svc.yaml

Ви також можете надати кілька файлів docker-compose одночасно:

kompose -f docker-compose.yml -f docker-guestbook.yml convert
INFO Kubernetes file "frontend-service.yaml" created         
INFO Kubernetes file "mlbparks-service.yaml" created         
INFO Kubernetes file "mongodb-service.yaml" created          
INFO Kubernetes file "redis-master-service.yaml" created     
INFO Kubernetes file "redis-slave-service.yaml" created      
INFO Kubernetes file "frontend-deployment.yaml" created      
INFO Kubernetes file "mlbparks-deployment.yaml" created      
INFO Kubernetes file "mongodb-deployment.yaml" created       
INFO Kubernetes file "mongodb-claim0-persistentvolumeclaim.yaml" created
INFO Kubernetes file "redis-master-deployment.yaml" created  
INFO Kubernetes file "redis-slave-deployment.yaml" created   
ls
mlbparks-deployment.yaml  mongodb-service.yaml                       redis-slave-service.jsonmlbparks-service.yaml  
frontend-deployment.yaml  mongodb-claim0-persistentvolumeclaim.yaml  redis-master-service.yaml
frontend-service.yaml     mongodb-deployment.yaml                    redis-slave-deployment.yaml
redis-master-deployment.yaml

Коли надається кілька файлів docker-compose, конфігурація обʼєднується. Будь-яка конфігурація, яка є спільною, буде перевизначена наступним файлом.

Приклад kompose convert для OpenShift

kompose --provider openshift --file docker-voting.yml convert
WARN [worker] Service cannot be created because of missing port.
INFO OpenShift file "vote-service.yaml" created             
INFO OpenShift file "db-service.yaml" created               
INFO OpenShift file "redis-service.yaml" created            
INFO OpenShift file "result-service.yaml" created           
INFO OpenShift file "vote-deploymentconfig.yaml" created    
INFO OpenShift file "vote-imagestream.yaml" created         
INFO OpenShift file "worker-deploymentconfig.yaml" created  
INFO OpenShift file "worker-imagestream.yaml" created       
INFO OpenShift file "db-deploymentconfig.yaml" created      
INFO OpenShift file "db-imagestream.yaml" created           
INFO OpenShift file "redis-deploymentconfig.yaml" created   
INFO OpenShift file "redis-imagestream.yaml" created        
INFO OpenShift file "result-deploymentconfig.yaml" created  
INFO OpenShift file "result-imagestream.yaml" created  

Також підтримує створення buildconfig для директиви build в сервісі. Стандартно використовується віддалений репозиторій для поточної гілки git як джерело репозиторію, та поточну гілку як гілку джерела для збірки. Ви можете вказати інше джерело репозиторію та гілку джерела, використовуючи опції --build-repo та --build-branch відповідно.

kompose --provider openshift --file buildconfig/docker-compose.yml convert
WARN [foo] Service cannot be created because of missing port.
INFO OpenShift Buildconfig using git@github.com:rtnpro/kompose.git::master as source.
INFO OpenShift file "foo-deploymentconfig.yaml" created     
INFO OpenShift file "foo-imagestream.yaml" created          
INFO OpenShift file "foo-buildconfig.yaml" created

Альтернативні конвертації

Типово kompose перетворює файли у форматі yaml на обʼєкти Kubernetes Deployments та Services. У вас є альтернативна опція для генерації json за допомогою -j. Також, ви можете альтернативно згенерувати обʼєкти Replication Controllers, Daemon Sets, або Helm чарти.

kompose convert -j
INFO Kubernetes file "redis-svc.json" created
INFO Kubernetes file "web-svc.json" created
INFO Kubernetes file "redis-deployment.json" created
INFO Kubernetes file "web-deployment.json" created

Файли *-deployment.json містять обʼєкти Deployment.

kompose convert --replication-controller
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-replicationcontroller.yaml" created
INFO Kubernetes file "web-replicationcontroller.yaml" created

Файли *-replicationcontroller.yaml містять обʼєкти Replication Controller. Якщо ви хочете вказати кількість реплік (стандартно 1), використовуйте прапорець --replicas: kompose convert --replication-controller --replicas 3.

kompose convert --daemon-set
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-daemonset.yaml" created
INFO Kubernetes file "web-daemonset.yaml" created

Файли *-daemonset.yaml містять обʼєкти DaemonSet.

Якщо ви хочете згенерувати чарт для використання з Helm, виконайте:

kompose convert -c
INFO Kubernetes file "web-svc.yaml" created
INFO Kubernetes file "redis-svc.yaml" created
INFO Kubernetes file "web-deployment.yaml" created
INFO Kubernetes file "redis-deployment.yaml" created
chart created in "./docker-compose/"
tree docker-compose/
docker-compose
├── Chart.yaml
├── README.md
└── templates
    ├── redis-deployment.yaml
    ├── redis-svc.yaml
    ├── web-deployment.yaml
    └── web-svc.yaml

Структура чарту спрямована на надання каркаса для створення ваших чартів Helm.

Мітки

kompose підтримує специфічні для Kompose мітки в файлі docker-compose.yml, щоб явно визначити поведінку сервісу при конвертації.

  • kompose.service.type визначає тип сервісу, який потрібно створити.

    Наприклад:

    version: "2"
    services:
      nginx:
        image: nginx
        dockerfile: foobar
        build: ./foobar
        cap_add:
          - ALL
        container_name: foobar
        labels:
          kompose.service.type: nodeport
    
  • kompose.service.expose визначає, чи потрібно сервісу бути доступним ззовні кластера чи ні. Якщо значення встановлено на "true", постачальник автоматично встановлює точку доступу, і для будь-якого іншого значення, значення встановлюється як імʼя хосту. Якщо в сервісі визначено кілька портів, вибирається перший.

    • Для постачальника Kubernetes створюється ресурс Ingress, припускається, що контролер Ingress вже налаштований.
    • Для постачальника OpenShift створюється маршрут.

    Наприклад:

    version: "2"
    services:
      web:
        image: tuna/docker-counter23
        ports:
        - "5000:5000"
        links:
        - redis
        labels:
          kompose.service.expose: "counter.example.com"
      redis:
        image: redis:3.0
        ports:
        - "6379"
    

Наразі підтримуються наступні варіанти:

КлючЗначення
kompose.service.typenodeport / clusterip / loadbalancer
kompose.service.exposetrue / hostname

Перезапуск

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

docker-compose restartстворений обʼєктrestartPolicy Podʼа
""обʼєкт контролераAlways
alwaysобʼєкт контролераAlways
on-failureКапсулаOnFailure
noКапсулаNever

Наприклад, сервіс pival стане Podʼом нижче. Цей контейнер обчислює значення pi.

version: '2'

services:
  pival:
    image: perl
    command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
    restart: "on-failure"

Попередження про конфігурації Deployment

Якщо в Docker Compose файлі вказано том для сервісу, стратегія Deployment (Kubernetes) або DeploymentConfig (OpenShift) змінюється на "Recreate" замість "RollingUpdate" (типово). Це робиться для того, щоб уникнути одночасного доступу кількох екземплярів сервісу до тому.

Якщо в Docker Compose файлі імʼя сервісу містить _ (наприклад, web_service), то воно буде замінено на -, і імʼя сервісу буде перейменовано відповідно (наприклад, web-service). Kompose робить це, оскільки "Kubernetes" не дозволяє _ в імені обʼєкта.

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

Версії Docker Compose

Kompose підтримує версії Docker Compose: 1, 2 та 3. Ми маємо обмежену підтримку версій 2.1 та 3.2 через їх експериментальний характер.

Повний список сумісності між усіма трьома версіями перераховано у нашому документі з конвертації, включаючи список всіх несумісних ключів Docker Compose.

27 - Забезпечення стандартів безпеки Podʼів шляхом конфігурування вбудованого контролера допуску

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

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

Після альфа-релізу в Kubernetes v1.22, Pod Security Admission став стандартно доступним в Kubernetes v1.23, у вигляді бета. Починаючи з версії 1.25, Pod Security Admissio доступний загалом.

Для перевірки версії введіть kubectl version.

Якщо у вас не запущено Kubernetes 1.32, ви можете перемикнутися на перегляд цієї сторінки в документації для версії Kubernetes, яку ви використовуєте.

Налаштування контролера допуску

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
  configuration:
    apiVersion: pod-security.admission.config.k8s.io/v1 # див. примітку про сумісність
    kind: PodSecurityConfiguration
    # Стандартні значення, які застосовуються, коли мітка режиму не встановлена.
    #
    # Значення мітки рівня повинні бути одним з:
    # - "privileged" (станадртно)
    # - "baseline"
    # - "restricted"
    #
    # Значення мітки версії повинні бути одним з:
    # - "latest" (станадртно) 
    # - конкретна версія, наприклад "v1.32"
    defaults:
      enforce: "privileged"
      enforce-version: "latest"
      audit: "privileged"
      audit-version: "latest"
      warn: "privileged"
      warn-version: "latest"
    exemptions:
      # Масив імен користувачів для виключення.
      usernames: []
      # Масив імен класів виконання для виключення.
      runtimeClasses: []
      # Масив просторів імен для виключення.
      namespaces: []

28 - Забезпечення стандартів безпеки Podʼів за допомогою міток простору імен

Простори імен можуть бути позначені, щоб забезпечити стандарти безпеки Podʼів. Три політики privileged, baseline та restricted широко охоплюють спектр безпеки та реалізуються за допомогою контролера допуску безпеки Podʼа.

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

Pod Security Admission був доступний в Kubernetes v1.23, у вигляді бета. Починаючи з версії 1.25, Pod Security Admission доступний загалом.

Для перевірки версії введіть kubectl version.

Вимога стандарту безпеки Pod baseline за допомогою міток простору імен

Цей маніфест визначає Простір імен my-baseline-namespace, який:

  • Блокує будь-які Podʼи, які не відповідають вимогам політики baseline.
  • Генерує попередження для користувача та додає анотацію аудиту до будь-якого створеного Podʼа, який не відповідає вимогам політики restricted.
  • Фіксує версії політик baseline та restricted на v1.32.
apiVersion: v1
kind: Namespace
metadata:
  name: my-baseline-namespace
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.32

    # Ми встановлюємо ці рівні за нашим _бажаним_ `enforce` рівнем.
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: v1.32
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: v1.32

Додавання міток до наявних просторів імен за допомогою kubectl label

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

kubectl label --dry-run=server --overwrite ns --all \
    pod-security.kubernetes.io/enforce=baseline

Застосування до всіх просторів імен

Якщо ви тільки починаєте зі Pod Security Standards, відповідний перший крок — налаштувати всі простори імен з анотаціями аудиту для строгого рівня, такого як baseline:

kubectl label --overwrite ns --all \
  pod-security.kubernetes.io/audit=baseline \
  pod-security.kubernetes.io/warn=baseline

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

kubectl get namespaces --selector='!pod-security.kubernetes.io/enforce'

Застосування до конкретного простору імен

Ви також можете оновити конкретний простір імен. Ця команда додає політику enforce=restricted до простору імен my-existing-namespace, закріплюючи версію обмеженої політики на v1.32.

kubectl label --overwrite ns my-existing-namespace \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=v1.32

29 - Міграція з PodSecurityPolicy до вбудованого контролера допуску PodSecurity

Ця сторінка описує процес міграції з PodSecurityPolicy до вбудованого контролера допуску PodSecurity. Це можна зробити ефективно за допомогою комбінації запуску dry-run та режимів audit та warn, хоча це стає складнішим, якщо використовуються мутуючі PSP.

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

Версія вашого Kubernetes сервера має бути не старішою ніж v1.22. Для перевірки версії введіть kubectl version.

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

Ця сторінка передбачає, що ви вже знайомі з основними концепціями Pod Security Admission.

Загальний підхід

Існує кілька стратегій для міграції з PodSecurityPolicy до Pod Security Admission. Наведені нижче кроки — це один з можливих шляхів міграції, з метою мінімізації ризиків виробничої перерви та пробілів у безпеці.

  1. Вирішіть, чи Pod Security Admission відповідає вашому випадку використання.
  2. Перегляньте дозволи простору імен.
  3. Спростіть та стандартизуйте PodSecurityPolicies.
  4. Оновіть простори імен
    1. Визначте відповідний рівень безпеки Podʼа.
    2. Перевірте рівень безпеки Podʼів.
    3. Застосуйте рівень безпеки Podʼів.
    4. Оминіть PodSecurityPolicy.
  5. Перегляньте процеси створення просторів імен.
  6. Вимкніть PodSecurityPolicy.

0. Вирішіть, чи Pod Security Admission підходить для вас

Pod Security Admission був розроблений для задоволення найбільш поширених потреб у безпеці з коробки, а також для забезпечення стандартного набору рівнів безпеки у всіх кластерах. Однак він менш гнучкий, ніж PodSecurityPolicy. Зокрема, наступні функції підтримуються за допомогою PodSecurityPolicy, але не за допомогою Pod Security Admission:

  • Встановлення типових обмежень безпеки — Pod Security Admission є немутуючим контролером допуску, що означає, що він не буде змінювати Podʼи перед їх перевіркою. Якщо ви покладалися на цей аспект PodSecurityPolicy, вам доведеться або модифікувати ваші робочі навантаження, щоб вони відповідали обмеженням безпеки Podʼів, або використовувати Мутуючий вебхук допуску для внесення цих змін. Дивіться Спрощення та стандартизація PodSecurityPolicies нижче для детальнішої інформації.
  • Докладний контроль над визначенням політики — Pod Security Admission підтримує тільки 3 стандартні рівні. Якщо вам потрібно більше контролю над конкретними обмеженнями, вам доведеться використовувати Вебхук допуску з перевіркою для виконання цих політик.
  • Деталізація політики на рівні підпросторів імен — PodSecurityPolicy дозволяє вам призначати різні політики різним обліковим записам служб або користувачам, навіть в межах одного простору імен. Цей підхід має багато підводних каменів і не рекомендується, але якщо вам все одно потрібна ця функція, вам потрібно буде використовувати сторонній вебхук. Виняток становить випадок, коли вам потрібно повністю виключити певних користувачів або RuntimeClasses, у цьому випадку Pod Security Admission все ж надає деякі статичні конфігурації для виключень.

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

1. Перегляньте дозволи простору імен

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

2. Спрощення та стандартизація PodSecurityPolicies

На цьому етапі зменште кількість мутуючих PodSecurityPolicies і видаліть параметри, що виходять за межі Pod Security Standards. Зміни, рекомендовані тут, слід внести в офлайн-копію оригіналу PodSecurityPolicy, який ви змінюєте. Клонована PSP повинна мати іншу назву, яка в алфавітному порядку стоїть перед оригінальною (наприклад, додайте 0 до її назви). Не створюйте нові політики в Kubernetes зараз — це буде розглянуто в розділі Впровадження оновлених політик нижче.

2.а. Видалення явно мутуючих полів

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

Ви можете почати з видалення полів, які є явно мутуючими та не мають жодного впливу на політику валлідації. Ці поля (також перераховані в довіднику Перенесення PodSecurityPolicies у Pod Security Standards) включають:

  • .spec.defaultAllowPrivilegeEscalation
  • .spec.runtimeClass.defaultRuntimeClassName
  • .metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName']
  • .metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName']
  • .spec.defaultAddCapabilities — хоча це технічно мутуюче і валідуюче поле, його слід обʼєднати з .spec.allowedCapabilities, яке виконує ту саму валідацію без мутації.

2.б. Вилучення параметрів, що не підпадають під Pod Security Standards

Існують кілька полів в PodSecurityPolicy, які не входять до складу Pod Security Standards. Якщо вам потрібно забезпечити ці опції, вам доведеться доповнити Pod Security Admission за допомогою вебхуків допуску, що не входить в рамки цього посібника.

Спочатку ви можете видалити явно валідуючі поля, які не охоплюються Pod Security Standards. Ці поля (також перераховані в довіднику Перенесення PodSecurityPolicies у Pod Security Standards з поміткою "no opinion") включають:

  • .spec.allowedHostPaths
  • .spec.allowedFlexVolumes
  • .spec.allowedCSIDrivers
  • .spec.forbiddenSysctls
  • .spec.runtimeClass

Ви також можете видалити наступні поля, які стосуються управління групами POSIX / UNIX.

  • .spec.runAsGroup
  • .spec.supplementalGroups
  • .spec.fsGroup

Залишені мутуючі поля потрібні для належної підтримки Pod Security Standards і будуть оброблені в окремому порядку:

  • .spec.requiredDropCapabilities — Потрібно видалити ALL щоб зробити профіль Restricted.
  • .spec.seLinux — (Тільки мутуюче з правилом MustRunAs) потрібно для забезпечення вимог SELinux для профілів Baseline & Restricted.
  • .spec.runAsUser — (Не мутує з правилом RunAsAny) потрібно для забезпечення RunAsNonRoot для профілю Restricted.
  • .spec.allowPrivilegeEscalation — (Тільки мутується, якщо встановлено false) потрібно для профілю Restricted.

2.в. Впровадження оновлених PSP

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

Для кожної оновленої PodSecurityPolicy:

  1. Визначте, які Podʼи працюють під оригінальною PSP. Це можна зробити за допомогою анотації kubernetes.io/psp. Наприклад, використовуючи kubectl:

    PSP_NAME="original" # Встановіть назву PSP, яку ви перевіряєте
    kubectl get pods --all-namespaces -o jsonpath="{range .items[?(@.metadata.annotations.kubernetes\.io\/psp=='$PSP_NAME')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}"
    
  2. Порівняйте ці робочі навантаження з оригінальною специфікацією Podаʼа, щоб визначити, чи змінила PodSecurityPolicy Pod. Для Podʼів, створених за ресурсами робочого навантаження, ви можете порівняти Pod з PodTemplate в ресурсі контролера. Якщо будь-які зміни виявлені, оригінальний Pod або PodTemplate слід оновити з необхідною конфігурацією. Поля для перегляду:

    • .metadata.annotations['container.apparmor.security.beta.kubernetes.io/*'] (замініть * на назву кожного контейнера)
    • .spec.runtimeClassName
    • .spec.securityContext.fsGroup
    • .spec.securityContext.seccompProfile
    • .spec.securityContext.seLinuxOptions
    • .spec.securityContext.supplementalGroups
    • У контейнерів, під .spec.containers[*] та .spec.initContainers[*]:
      • .securityContext.allowPrivilegeEscalation
      • .securityContext.capabilities.add
      • .securityContext.capabilities.drop
      • .securityContext.readOnlyRootFilesystem
      • .securityContext.runAsGroup
      • .securityContext.runAsNonRoot
      • .securityContext.runAsUser
      • .securityContext.seccompProfile
      • .securityContext.seLinuxOptions
  3. Створіть нові PodSecurityPolicies. Якщо будь-які Roles або ClusterRoles надають use на всі PSP, це може призвести до використання нових PSP замість їх мутуючих аналогів.

  4. Оновіть вашу авторизацію, щоб дозволити доступ до нових PSP. У RBAC це означає оновлення будь-яких Roles або ClusterRoles, які надають дозвіл use на оригінальну PSP, щоб також надати його оновленому PSP.

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

  6. (опціонально) Після того, як ви перевірили, що оригінальні PSP більше не використовуються, ви можете їх видалити.

3. Оновлення просторів імен

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

3.а. Визначення відповідного рівня безпеки Podʼа

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

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

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

  2. За поточними PodSecurityPolicies — Використовуючи довідник Перенесення PodSecurityPolicies у Pod Security Standards, ви можете віднести кожен PSP до рівня стандарту безпеки Podʼа. Якщо ваші PSP не базуються на Pod Security Standards, вам може знадобитися вирішити, обирати рівень, який є принаймні таким же дозвільним, як PSP, або рівень, який є принаймні таким же обмежувальним. Які PSP використовуються для Podʼів у даному просторі імен, ви можете побачити за допомогою цієї команди:

    kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u
    
  3. За поточними Podʼами — Використовуючи стратегії з розділу Перевірка рівня безпеки Podʼа, ви можете перевірити рівні Baseline і Restricted, щоб побачити, чи є вони достатньо дозвільними для наявних робочих навантажень, і вибрати найменш привілейований валідний рівень.

3.б. Перевірка рівня безпеки Podʼа

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

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

# $LEVEL - рівень для пробного запуску, або "baseline", або "restricted".
kubectl label --dry-run=server --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL

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

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

kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL

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

3.в. Впровадження рівня безпеки Podʼа

Коли ви переконаєтеся, що обраний рівень може бути безпечно впроваджений для простору імен, ви можете оновити простір імен, щоб впровадити бажаний рівень:

kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL

3.г. Оминання політики безпеки Pod

Наостанок, ви можете ефективно оминути PodSecurityPolicy на рівні простору імен, привʼязавши повністю привілейовану PSP до всіх облікових записів служб у просторі імен.

# Наступні команди, які виконуються на рівні кластера, потрібні лише один раз.
kubectl apply -f privileged-psp.yaml
kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged

# Вимкнення на рівні простору імен
kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE

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

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

# Скасування вимкнення PodSecurityPolicy.
kubectl delete -n $NAMESPACE rolebinding disable-psp

4. Перегляд процесів створення просторів імен

Тепер, коли поточні простори імен оновлено для забезпечення прийняття рішень щодо Pod Security Admission, вам слід переконатися, що ваші процеси та/або політики для створення нових просторів імен оновлено, щоб гарантувати застосування відповідного профілю безпеки Pod для нових просторів імен.

Ви також можете статично налаштувати контролер Pod Security Admission для встановлення типового рівня впровадження, аудиту та/або попередження для просторів імен без міток. Див. Налаштування контролера допуску для отримання додаткової інформації.

5. Вимкнення PodSecurityPolicy

Нарешті, ви готові вимкнути PodSecurityPolicy. Для цього вам потрібно змінити конфігурацію допуску сервера API: Як я можу вимкнути контролер допуску?.

Щоб перевірити, що контролер допуску PodSecurityPolicy більше не активний, ви можете вручну запустити тест, видаючи себе за користувача без доступу до будь-яких PodSecurityPolicies (див. приклад PodSecurityPolicy), або перевірити логи сервера API. При запуску сервер API виводить рядки логу, що перераховують завантажені втулки контролера допуску:

I0218 00:59:44.903329      13 plugins.go:158] Loaded 16 mutating admission controller(s) successfully in the following order: NamespaceLifecycle,LimitRanger,ServiceAccount,NodeRestriction,TaintNodesByCondition,Priority,DefaultTolerationSeconds,ExtendedResourceToleration,PersistentVolumeLabel,DefaultStorageClass,StorageObjectInUseProtection,RuntimeClass,DefaultIngressClass,MutatingAdmissionWebhook.
I0218 00:59:44.903350      13 plugins.go:161] Loaded 14 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,DenyServiceExternalIPs,ValidatingAdmissionWebhook,ResourceQuota.

Ви маєте побачити PodSecurity (у списку контролерів допуску для перевірки валідності), і жоден зі списків не повинен містити PodSecurityPolicy.

Після того, як ви впевнені, що контролер допуску PSP вимкнуто (і після достатнього часу, щоб бути впевненим, що вам не потрібно буде відкочувати зміни), ви вільні видалити ваші PodSecurityPolicies та будь-які повʼязані Roles, ClusterRoles, RoleBindings та ClusterRoleBindings (просто переконайтеся, що вони не надають будь-яких інших неповʼязаних дозволів).