Конфігурація
Механізми конфігурації в Kubernetes.
Kubernetes надає способи відокремлення конфігурації від коду. Це поширена практика, яка узгоджується з принципами DevOps та з архітектурою cloud native.
Якщо у вас є образ контейнера, який підтримує окрему конфігурацію, ви можете розгортати той самий код застосунку в різних контекстах. Наприклад, ви можете запускати тести для зібраного образу, а потім запускати той самий образ у промисловому контексті. Це дає вам більше впевненості у вашому тестуванні порівняно з розгортанням застосунку одним способом для тестів та іншим у промисловій експлуатації.
Щоб дізнатися про налаштування інструмента командного рядка kubectl, прочитайте налаштування доступу до кількох кластерів.
API Kubernetes, повʼязані з конфігурацією
Kubernetes надає два основні види API, які ви можете використовувати для зберігання конфігурації, готової для завантаження та використання Podʼом (або іншим компонентом): ConfigMap та Secret.
Види API спеціального призначення CertificateSigningRequest та ClusterTrustBundle також містять дані конфігурації, що стосуються деяких конкретних випадків, таких як конфігурація TLS.
Усі ці механізми конфігурації, навіть для сертифікатів, розроблені так, щоб конфігурацію можна було повторно та спільно використовувати кількома Podʼами. Зазвичай вам не потрібно записувати конфігурацію окремо для кожного Podʼа, і ви маєте проєктувати застосунки, де це можливо, так, щоб вони могли працювати зі спільною конфігурацією.
Щоб дізнатися про використання конфігурації у ваших застосунках, прочитайте про інʼєкцію даних у застосунки.
ConfigMaps
ConfigMap — це обʼєкт API, призначений для зберігання неконфіденційних даних у вигляді пар ключ-значення. Podʼи можуть використовувати ConfigMap як змінні середовища, аргументи командного рядка чи файли конфігурації у томі.
ConfigMap дозволяє відділити конфігурацію, специфічну для середовища, від образів контейнерів, щоб ваші застосунки були легко переносимими.
Secrets
Secret — це обʼєкт, який містить певний обсяг конфіденційних даних, таких як пароль, токен або ключ.
Secrets схожі на ConfigMaps, але спеціально призначені для зберігання конфіденційних даних. Прочитайте сторінку про Secrets, щоб дізнатися про переваги (та обмеження) щодо інформаційної безпеки та Secrets.
Конфігурація через sidecar-контейнери або init-контейнери
Ви також можете використовувати init-контейнер або sidecar-контейнер, щоб надати конфігурацію вашому робочому навантаженню.
Це корисно, якщо у вас уже є певний спосіб, поза межами Kubernetes, для зберігання конфігурації, ключів безпеки або іншої інформації, яку ваші контейнери мають використовувати і яка не повинна зберігатися в образах контейнерів.
Sidecar-контейнер як помічник
Помічник конфігурації у вигляді sidecar працює в тому самому Podʼі, що й контейнер застосунку, тому кожен Pod має власний sidecar. Типовий sidecar конфігурації отримує дані конфігурації через мережу Podʼа, а потім записує їх у том, який змонтовано в обидва контейнери.
Існує багато варіацій цього базового шаблону, у яких все ще є контейнер-помічник, що записує конфігурацію для використання контейнером застосунку.
Init-контейнер як помічник
Podʼи можуть мати init-контейнери, які запускаються перед головним застосунком. На відміну від sidecar-контейнерів, init-контейнери завершуються до того, як запустяться головні контейнери Podʼа (з основним застосунком), тому конфігурація встановлюється тільки один раз.
У вас є два основні варіанти конфігурації за допомогою init-контейнерів:
Конфігурація через файлову систему
За цього варіанту init-контейнер отримує конфігурацію та записує її у файл або кілька файлів, зазвичай у локальний для Podʼа том.
Конфігурація через змінні середовища
СТАН ФУНКЦІОНАЛУ:
Beta since Kubernetes v1.35; (стандартно увімкнено)
Це робиться за допомогою локального тому, але лише init-контейнер монтує цей том. Потім kubelet читає з цього тому перед запуском контейнера застосунку.
Прочитайте Визначення значень змінних середовища за допомогою init-контейнера, щоб дізнатися більше.
Конфігурація кластера
Цей розділ документації присвячений конфігурації. Однак якщо ви виконуєте конфігурацію на рівні платформи або кластера, прочитайте сторінки адміністрування кластера та перегляньте список завдань з адміністрування кластера.
Що далі
Усі наведені нижче посилання стосуються загальної концепції конфігурації та Kubernetes:
а також ви можете переглянути список форматів конфігураційних файлів у розділі довідки.
У межах цього розділу документації ви можете прочитати про:
1 - ConfigMaps
ConfigMap — це обʼєкт API, призначений для зберігання неконфіденційних даних у вигляді пар ключ-значення. Podʼи можуть використовувати ConfigMap як змінні середовища, аргументи командного рядка чи файли конфігурації у томі.
ConfigMap дозволяє відділити конфігурацію, специфічну для середовища, від образів контейнерів, щоб ваші застосунки були легко переносимими.
Увага:
ConfigMap не забезпечує конфіденційності або шифрування. Якщо дані, які ви хочете зберегти, конфіденційні, використовуйте
Secret замість ConfigMap або використовуйте додаткові (сторонні) інструменти для збереження ваших даних в таємниці.
Мотивація
Використовуйте ConfigMap для визначення конфігураційних даних окремо від коду застосунку.
Наприклад, уявіть, що ви розробляєте застосунок, який ви можете запускати на власному компʼютері (для розробки) і в хмарі (для обробки реального трафіку). Ви пишете код, який читає змінну середовища з назвою DATABASE_HOST. Локально ви встановлюєте цю змінну в значення localhost. У хмарі ви встановлюєте її так, щоб вона посилалася на Service, який надає доступ до компонента бази даних вашому кластеру. Це дозволяє вам отримати образ контейнера, який працює в хмарі, і у разі потреби налагоджувати той самий код локально.
Примітка:
ConfigMap не призначено для зберігання великих обсягів даних. Дані, збережені в ConfigMap, не можуть перевищувати 1 MiB. Якщо потрібно зберегти налаштування, які перевищують це обмеження, варто розглянути можливість монтування тому або використання окремої бази даних або файлового сервісу.Обʼєкт ConfigMap
ConfigMap — це обʼєкт API, який дозволяє зберігати конфігураційні дані для використання іншими обʼєктами. На відміну від більшості обʼєктів Kubernetes, у яких є spec, ConfigMap має поля data та binaryData. Ці поля приймають пари ключ-значення як свої значення. Обидва поля data і binaryData є необовʼязковими. Поле data призначене для зберігання рядків UTF-8, тоді як поле binaryData призначене для зберігання бінарних даних у вигляді рядків, закодованих у base64.
Назва ConfigMap повинна бути дійсним піддоменом DNS.
Кожний ключ у полі data або binaryData повинен складатися з буквено-цифрових символів, -, _ або .. Ключі, збережені в data, не повинні перетинатися з ключами у полі binaryData.
Починаючи з версії v1.19, ви можете додати поле immutable до визначення ConfigMap, щоб створити незмінний ConfigMap.
ConfigMaps та Podʼи
Ви можете написати spec Podʼа, який посилається на ConfigMap і конфігурує контейнер(и) в цьому Podʼі на основі даних з ConfigMap. Pod і ConfigMap повинні бути в тому самому просторі імен.
Примітка:
spec статичного Podʼа не може посилатися на ConfigMap або на інші обʼєкти API.
Ось приклад ConfigMap, який має деякі ключі з окремими значеннями, а також інші ключі, де значення виглядає як фрагмент формату конфігурації.
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# ключі у вигляді властивостей; кожен ключ зіставляється з простим значенням
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# ключі у формі файлів
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
Є чотири різних способи використання ConfigMap для конфігурації контейнера всередині Podʼа:
- В команді та аргументах контейнера
- У змінних середовища для контейнера
- Додайте файл до тому тільки для читання, щоб застосунок міг його читати
- Напишіть код для виконання всередині Podʼа, який використовує API Kubernetes для читання ConfigMap
Ці різні методи підходять для різних способів моделювання даних, які використовуються. Для перших трьох методів kubelet використовує дані з ConfigMap під час запуску контейнера(ів) для Podʼа.
Четвертий метод означає, що вам потрібно написати код для читання ConfigMap та його даних. Однак, оскільки ви використовуєте прямий доступ до API Kubernetes, ваш застосунок може підписатися на отримання оновлень, коли змінюється ConfigMap, і реагувати на це. Завдяки прямому доступу до API Kubernetes цей підхід також дозволяє вам отримувати доступ до ConfigMap в іншому просторі імен.
Ось приклад Podʼа, який використовує значення з game-demo для конфігурації Podʼа:
ConfigMap не розрізняє однорядкові значення властивостей та багаторядкові файлоподібні значення. Важливо, як Podʼи та інші обʼєкти використовують ці значення.
У цьому прикладі визначення тому та монтування його всередину контейнера demo як /config створює два файли, /config/game.properties та /config/user-interface.properties, хоча в ConfigMap є чотири ключі. Це тому, що визначення Podʼа містить масив items в розділі volumes. Якщо ви взагалі опустите масив items, кожен ключ у ConfigMap стане файлом із такою самою назвою, що й ключ, і ви отримаєте 4 файли.
Використання ConfigMap
ConfigMap можуть бути змонтовані як томи даних. ConfigMap також можуть бути використані іншими частинами системи без безпосереднього надання Podʼу. Наприклад, ConfigMap можуть містити дані, які повинні використовуватися іншими частинами системи для конфігурації.
Найпоширеніший спосіб використання ConfigMap — це налаштування контейнерів, які працюють у Podʼі в тому самому просторі імен. Ви також можете використовувати ConfigMap окремо.
Наприклад, ви можете зустріти надбудови або оператори, які налаштовують свою поведінку на основі ConfigMap.
Використання ConfigMaps як файлів у Podʼі
Щоб використовувати ConfigMap в томі в Podʼі:
- Створіть ConfigMap або використовуйте наявний. Декілька Podʼів можуть посилатися на один ConfigMap.
- Змініть ваше визначення Podʼа, щоб додати том в
.spec.volumes[]. Дайте тому будь-яку назву та встановіть поле .spec.volumes[].configMap.name для посилання на ваш обʼєкт ConfigMap. - Додайте
.spec.containers[].volumeMounts[] до кожного контейнера, який потребує ConfigMap. Вкажіть .spec.containers[].volumeMounts[].readOnly = true та задайте в .spec.containers[].volumeMounts[].mountPath назву невикористаної теки, де ви хочете, щоб зʼявився ConfigMap. - Змініть ваш образ або командний рядок так, щоб програма шукала файли у цій теці. Кожен ключ у мапі
data ConfigMap стає імʼям файлу в mountPath.
Ось приклад Podʼа, який монтує ConfigMap в том:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
configMap:
name: myconfigmap
Кожен ConfigMap, який ви хочете використовувати, слід зазначити в .spec.volumes.
Якщо в Podʼі є кілька контейнерів, то кожен контейнер потребує свого власного блоку volumeMounts, але потрібно лише одне поле .spec.volumes на ConfigMap.
Змонтовані ConfigMaps оновлюються автоматично
Коли ConfigMap, що наразі використовується в томі, оновлюється, спроєцьовані ключі згодом також оновлюються. Kubelet перевіряє, чи змонтований ConfigMap є актуальним під час кожної періодичної синхронізації. Однак kubelet використовує свій локальний кеш для отримання поточного значення ConfigMap. Тип кешу налаштовується за допомогою поля configMapAndSecretChangeDetectionStrategy в структурі KubeletConfiguration. ConfigMap можна поширити за допомогою watch (типово), на основі ttl або шляхом перенаправлення всіх запитів безпосередньо до API-сервера. Отже, загальна затримка від моменту оновлення ConfigMap до моменту, коли нові ключі буде спроєцьовано в Pod, може дорівнювати періоду синхронізації kubelet + затримці поширення кешу, де затримка поширення кешу залежить від обраного типу кешу (вона дорівнює затримці поширення watch, ttl кешу або нулю відповідно).
ConfigMap, що використовуються як змінні середовища, не оновлюються автоматично і потребують перезапуску Podʼа.
Примітка:
Контейнер, який використовує ConfigMap як том з монтуванням
subPath, не отримує оновлення ConfigMap.
Використання ConfigMaps як змінних середовища
Щоб використовувати ConfigMap у змінних середовища в Podʼі:
- Для кожного контейнера у вашій специфікації Podʼа додайте змінну середовища для кожного ключа ConfigMap, який ви хочете використовувати, до поля
env[].valueFrom.configMapKeyRef. - Змініть ваш образ та/або командний рядок так, щоб програма шукала значення у вказаних змінних середовища.
Ось приклад визначення ConfigMap як змінної середовища Podʼа:
Цей ConfigMap (myconfigmap.yaml) містить дві властивості: username та access_level:
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfigmap
data:
username: k8s-admin
access_level: "1"
Ця команда створить обʼєкт ConfigMap:
kubectl apply -f myconfigmap.yaml
Цей Pod використовує вміст ConfigMap як змінні середовища:
apiVersion: v1
kind: Pod
metadata:
name: env-configmap
spec:
containers:
- name: app
command: ["/bin/sh", "-c", "printenv"]
image: busybox:latest
envFrom:
- configMapRef:
name: myconfigmap
Поле envFrom вказує Kubernetes створити змінні середовища з джерел, вкладених у нього. Внутрішній configMapRef посилається на ConfigMap за його назвою і вибирає всі його пари ключ-значення. Додайте Pod до свого кластера, а потім перегляньте його логи, щоб побачити виведення команди printenv. Це має підтвердити, що дві пари ключ-значення з ConfigMap були встановлені як змінні середовища:
kubectl apply -f env-configmap.yaml
kubectl logs pod/env-configmap
Вивід буде подібний до цього:
...
username: "k8s-admin"
access_level: "1"
...
Іноді Pod не потребуватиме доступу до всіх значень у ConfigMap. Наприклад, можна мати інший Pod, який використовує тільки значення username з ConfigMap. Для цього випадку можна використовувати синтаксис env.valueFrom, який дозволяє вибирати окремі ключі в ConfigMap. Імʼя змінної середовища також може відрізнятися від ключа в ConfigMap. Наприклад:
apiVersion: v1
kind: Pod
metadata:
name: env-configmap
spec:
containers:
- name: envars-test-container
image: nginx
env:
- name: CONFIGMAP_USERNAME
valueFrom:
configMapKeyRef:
name: myconfigmap
key: username
У Podʼі, створеному з цього маніфесту, ви побачите, що змінна середовища CONFIGMAP_USERNAME встановлена на значення username з ConfigMap. Інші ключі з даних ConfigMap не будуть скопійовані у середовище.
Важливо зауважити, що набір символів, дозволених для назв змінних середовища в Podʼах, обмежений. Якщо будь-які ключі не відповідають правилам, ці ключі не будуть доступні вашому контейнеру, хоча Pod може бути запущений.
Незмінні ConfigMap
СТАН ФУНКЦІОНАЛУ:
GA since Kubernetes v1.21
Функція Kubernetes Immutable Secrets та ConfigMaps надає можливість зробити окремі Secrets та ConfigMaps незмінними. Для кластерів, що інтенсивно використовують ConfigMap (принаймні десятки тисяч унікальних монтувань ConfigMap до Podʼів), запобігання змінам їх даних має такі переваги:
- захищає від випадкових (або небажаних) оновлень, які можуть призвести до відмов застосунків
- покращує продуктивність кластера шляхом значного зниження навантаження на kube-apiserver, завдяки закриттю спостережень за ConfigMap, позначеними як незмінні.
Ви можете створити незмінний ConfigMap, встановивши поле immutable в true. Наприклад:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
Після того, як ConfigMap позначено як незмінний, відмінити цю зміну або змінити вміст поля data або binaryData неможливо. Ви можете лише видалити та створити ConfigMap знову. Оскільки поточні Podʼи підтримують точку монтування для видаленого ConfigMap, рекомендується створити заново ці Podʼи.
Що далі
2 - Secrets
Secret — це обʼєкт, який містить невелику кількість конфіденційних даних, таких як пароль, токен або ключ. Інакше така інформація могла б потрапити до специфікації Pod або до образу контейнера. Використання Secret означає, що вам не потрібно включати конфіденційні дані в код застосунку.
Оскільки Secrets можна створювати незалежно від Podʼів, які їх використовують, існує менше ризику того, що Secret (і його дані) буде розкрито під час створення, перегляду та редагування Podʼів. Kubernetes та застосунки, які працюють у вашому кластері, також можуть вживати додаткових заходів безпеки щодо Secrets, наприклад, уникати запису конфіденційних даних в енергонезалежне сховище.
Secrets схожі на ConfigMaps, але спеціально призначені для зберігання конфіденційних даних.
Увага:
Kubernetes Secrets стандартно зберігаються незашифрованими в базовому сховищі даних API-сервера (etcd). Будь-хто з доступом до API може отримати або змінити Secret, так само як будь-хто з доступом до etcd. Крім того, будь-хто, хто має дозвіл на створення Podʼа у просторі імен, може використовувати цей доступ для читання будь-якого Secret у цьому просторі імен; це включає і непрямий доступ, такий як можливість створення Deployment.
Щоб безпечно використовувати Secrets, виконайте принаймні такі кроки:
- Увімкніть шифрування у стані спокою для Secrets.
- Увімкніть або налаштуйте правила RBAC з доступом до Secrets за принципом найменших привілеїв.
- Обмежте доступ до Secrets конкретними контейнерами.
- Розгляньте використання зовнішніх постачальників сховища для Secrets.
Для отримання додаткових рекомендацій щодо керування та покращення безпеки ваших Secrets ознайомтесь із Належними практиками для Kubernetes Secrets.
Докладніше див. у розділі Інформаційна безпека для Secrets.
Застосування Secrets
Ви можете використовувати Secrets для таких цілей:
Панель управління Kubernetes також використовує Secrets; наприклад, Secrets bootstrap-токенів — це механізм, що допомагає автоматизувати реєстрацію вузлів.
Сценарій використання: dotfiles у томі Secret
Ви можете зробити ваші дані "прихованими", визначивши ключ, який починається з крапки. Цей ключ являє собою dotfile або "прихований" файл. Наприклад, коли цей Secret монтується в том secret-volume, том міститиме один файл із назвою .secret-file, а контейнер dotfile-test-container матиме цей файл за шляхом /etc/secret-volume/.secret-file.
Примітка:
Файли, які починаються з крапок, приховані від виводу ls -l; щоб побачити їх під час перегляду вмісту теки, використовуйте ls -la.apiVersion: v1
kind: Secret
metadata:
name: dotfile-secret
data:
.secret-file: dmFsdWUtMg0KDQo=
---
apiVersion: v1
kind: Pod
metadata:
name: secret-dotfiles-pod
spec:
volumes:
- name: secret-volume
secret:
secretName: dotfile-secret
containers:
- name: dotfile-test-container
image: registry.k8s.io/busybox
command:
- ls
- "-l"
- "/etc/secret-volume"
volumeMounts:
- name: secret-volume
readOnly: true
mountPath: "/etc/secret-volume"
Сценарій використання: Secret, видимий для одного контейнера в Podʼі
Припустимо, що у вас є програма, яка потребує обробки HTTP-запитів, виконання складної бізнес-логіки та підписування деяких повідомлень за допомогою HMAC. Оскільки у неї складна логіка застосунку, на сервері може бути непомічена вразливість віддаленого читання файлів, яка може розкрити приватний ключ зловмиснику.
Це можна розділити на два процеси у двох контейнерах: фронтенд-контейнер, який обробляє взаємодію з користувачем та бізнес-логіку, але не може бачити приватний ключ; і контейнер-підписувач, який може бачити приватний ключ та відповідає на прості запити на підпис від фронтенду (наприклад, через мережу localhost).
З цим розділеним підходом зловмиснику тепер потрібно змусити сервер застосунку зробити щось досить довільне, що може бути складніше, ніж змусити його прочитати файл.
Альтернативи Secrets
Замість використання Secret для захисту конфіденційних даних ви можете скористатися альтернативами.
Ось деякі з варіантів:
- Якщо ваш компонент cloud native має автентифікуватися в іншому застосунку, який, як ви знаєте, працює в тому самому кластері Kubernetes, ви можете використовувати ServiceAccount та його токени, щоб ідентифікувати вашого клієнта.
- Існують сторонні інструменти, які ви можете запускати, як в межах, так і поза вашим кластером, які керують чутливими даними. Наприклад, сервіс, до якого Podʼи звертаються через HTTPS і який розкриває Secret, якщо клієнт правильно автентифікується (наприклад, з токеном ServiceAccount).
- Для автентифікації ви можете реалізувати власний підписувач для сертифікатів X.509 і використовувати CertificateSigningRequests, щоб дозволити цьому власному підписувачу видавати сертифікати Podʼам, які їх потребують.
- Ви можете використовувати втулок пристрою, щоб надати певному Podʼу доступ до локального для вузла апаратного забезпечення шифрування. Наприклад, ви можете планувати довірені Podʼи на вузли, які надають Trusted Platform Module, налаштований окремо (out-of-band).
Ви також можете комбінувати два або більше з цих варіантів, включаючи використання самих обʼєктів Secret.
Наприклад: реалізуйте (або розгорніть) оператор, що отримує короткострокові токени сеансів від зовнішнього сервісу, а потім створює Secrets на основі цих короткострокових токенів. Podʼи, що працюють у вашому кластері, можуть використовувати токени сеансів, а оператор забезпечує їхню дійсність. Такий розподіл означає, що ви можете запускати Podʼи, які не знають точних механізмів видачі та оновлення цих токенів сеансів.
Типи Secret
Під час створення Secret ви можете вказати його тип, використовуючи поле type ресурсу Secret, або певні еквівалентні прапорці командного рядка kubectl (якщо вони доступні). Тип Secret використовується для полегшення програмної обробки даних Secret.
Kubernetes надає кілька вбудованих типів для деяких типових сценаріїв використання. Ці типи відрізняються за умовами перевірки та обмеженнями, які Kubernetes накладає на них.
| Вбудований тип | Використання |
|---|
Opaque | довільні користувацькі дані |
kubernetes.io/service-account-token | токен ServiceAccount |
kubernetes.io/dockercfg | серіалізований файл ~/.dockercfg |
kubernetes.io/dockerconfigjson | серіалізований файл ~/.docker/config.json |
kubernetes.io/basic-auth | облікові дані для базової автентифікації |
kubernetes.io/ssh-auth | облікові дані для SSH-автентифікації |
kubernetes.io/tls | дані для клієнта або сервера TLS |
bootstrap.kubernetes.io/token | дані bootstrap-токена |
Ви можете визначити та використовувати власний тип Secret, присвоївши непорожній рядок як значення type обʼєкта Secret (порожній рядок розглядається як тип Opaque).
Kubernetes не накладає жодних обмежень на назву типу. Однак якщо ви використовуєте один з вбудованих типів, ви повинні задовольнити всі вимоги, визначені для цього типу.
Якщо ви визначаєте тип Secret, призначений для загального використання, дотримуйтесь домовленостей та структуруйте тип Secret так, щоб він мав назву вашого домену перед назвою типу, відокремлену символом /. Наприклад: cloud-hosting.example.net/cloud-api-credentials.
Opaque Secrets
Opaque — це стандартний тип Secret, якщо ви не вказуєте явно тип у маніфесті Secret. Під час створення Secret за допомогою kubectl вам потрібно використовувати підкоманду generic, щоб вказати тип Secret Opaque. Наприклад, ця команда створює порожній Secret типу Opaque:
kubectl create secret generic empty-secret
kubectl get secret empty-secret
Вивід виглядає так:
NAME TYPE DATA AGE
empty-secret Opaque 0 2m6s
У стовпчику DATA показується кількість елементів даних, збережених у Secret. У цьому випадку 0 означає, що ви створили порожній Secret.
Secrets токенів ServiceAccount
Тип Secret kubernetes.io/service-account-token використовується для зберігання токена, який ідентифікує ServiceAccount. Це застарілий механізм, який забезпечує довгострокові облікові дані ServiceAccount для Podʼів.
У Kubernetes v1.22 та пізніших рекомендований підхід полягає в тому, щоб натомість отримувати короткостроковий токен ServiceAccount з автоматичною ротацією за допомогою API TokenRequest. Ви можете отримати ці короткострокові токени такими методами:
- Викликайте API
TokenRequest безпосередньо або через клієнт API, такий як kubectl. Наприклад, ви можете використовувати команду kubectl create token. - Запитуйте змонтований токен у спроєцьованому томі у вашому маніфесті Podʼа. Kubernetes створює токен і монтує його в Pod. Токен автоматично анулюється, коли Pod, в якому він монтується, видаляється. Докладні відомості див. в розділі Запуск Podʼа з проєкцією токена ServiceAccount.
Примітка:
Ви повинні створювати Secret токена ServiceAccount лише в тому випадку, якщо ви не можете використовувати API
TokenRequest для отримання токена, і вам прийнятно з погляду безпеки зберігання безстрокового токена доступу в доступному для читання обʼєкті API. Для інструкцій див.
Створення довгострокового API-токена для ServiceAccount вручну.
Під час використання цього типу Secret вам потрібно переконатися, що анотація kubernetes.io/service-account.name містить назву наявного ServiceAccount. Якщо ви створюєте як Secret, так і обʼєкти ServiceAccount, ви повинні спочатку створити обʼєкт ServiceAccount.
Після створення Secret контролер Kubernetes заповнює деякі інші поля, такі як анотація kubernetes.io/service-account.uid, та ключ token в полі data, який заповнюється токеном автентифікації.
У цьому прикладі конфігурації оголошується Secret токена ServiceAccount:
apiVersion: v1
kind: Secret
metadata:
name: secret-sa-sample
annotations:
kubernetes.io/service-account.name: "sa-name"
type: kubernetes.io/service-account-token
data:
extra: YmFyCg==
Після створення Secret дочекайтеся, коли Kubernetes заповнить ключ token в полі data.
Для отримання додаткової інформації про роботу ServiceAccounts перегляньте документацію про ServiceAccount. Ви також можете перевірити поле automountServiceAccountToken та поле serviceAccountName у Pod для отримання інформації про посилання на облікові дані ServiceAccount з Podʼів.
Secrets конфігурації Docker
Якщо ви створюєте Secret для зберігання облікових даних для доступу до реєстру образів контейнерів, ви повинні використовувати одне з таких значень type для цього Secret:
kubernetes.io/dockercfg: зберігає серіалізований ~/.dockercfg, який є застарілим форматом налаштування командного рядка Docker. У полі data Secret міститься ключ .dockercfg, значення якого — це вміст файлу ~/.dockercfg, закодованого у форматі base64.kubernetes.io/dockerconfigjson: зберігає серіалізований JSON, який відповідає тим самим правилам формату, що й файл ~/.docker/config.json, який є новим форматом для ~/.dockercfg. У полі data Secret має міститися ключ .dockerconfigjson, значення якого — це вміст файлу ~/.docker/config.json, закодованого у форматі base64.
Нижче наведено приклад для Secret типу kubernetes.io/dockercfg:
apiVersion: v1
kind: Secret
metadata:
name: secret-dockercfg
type: kubernetes.io/dockercfg
data:
.dockercfg: |
eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUvdjEvIjp7ImF1dGgiOiJvcGVuc2VzYW1lIn19fQo=
Примітка:
Якщо ви не хочете виконувати кодування у формат base64, ви можете натомість використати поле stringData.Під час створення Secrets конфігурації Docker за допомогою маніфесту API-сервер перевіряє, чи існує очікуваний ключ у полі data, і чи надане значення можна розібрати як дійсний JSON. API-сервер не перевіряє, чи є цей JSON фактично файлом конфігурації Docker.
Ви також можете використовувати kubectl для створення Secret для доступу до реєстру контейнерів, наприклад, коли у вас немає файлу конфігурації Docker:
kubectl create secret docker-registry secret-tiger-docker \
--docker-email=tiger@acme.example \
--docker-username=tiger \
--docker-password=pass1234 \
--docker-server=my-registry.example:5000
Ця команда створює Secret типу kubernetes.io/dockerconfigjson.
Отримайте поле .data.dockerconfigjson з цього нового Secret та розкодуйте дані:
kubectl get secret secret-tiger-docker -o jsonpath='{.data.*}' | base64 -d
Вивід еквівалентний такому JSON-документу (який також є дійсним файлом конфігурації Docker):
{
"auths": {
"my-registry.example:5000": {
"username": "tiger",
"password": "pass1234",
"email": "tiger@acme.example",
"auth": "dGlnZXI6cGFzczEyMzQ="
}
}
}
Увага:
Значення auth закодовано у формат base64; воно приховане, але не є секретним. Будь-хто, хто може прочитати цей Secret, може дізнатися токен доступу (bearer) до реєстру.
Рекомендується використовувати постачальників облікових даних для динамічного й безпечного надання Secrets для завантаження образів на запит.
Secret базової автентифікації
Тип kubernetes.io/basic-auth наданий для зберігання облікових даних, необхідних для базової автентифікації. Під час використання цього типу Secret поле data Secret повинно містити один із двох таких ключів:
username: імʼя користувача для автентифікаціїpassword: пароль або токен для автентифікації
Обидва значення для цих ключів є рядками, закодованими в base64. Ви також можете надати відкритий текст, використовуючи поле stringData у маніфесті Secret.
Цей маніфест є прикладом Secret для базової автентифікації:
apiVersion: v1
kind: Secret
metadata:
name: secret-basic-auth
type: kubernetes.io/basic-auth
stringData:
username: admin # required field for kubernetes.io/basic-auth
password: t0p-Secret # required field for kubernetes.io/basic-auth
Примітка:
Поле stringData для Secret погано працює із застосуванням на боці сервера (server-side apply).Тип Secret для базової автентифікації наданий лише для зручності. Ви можете створити тип Opaque для облікових даних, які використовуються для базової автентифікації. Однак використання визначеного та публічного типу Secret (kubernetes.io/basic-auth) допомагає іншим людям зрозуміти призначення вашого Secret та встановлює домовленості для очікуваних назв ключів.
Secret для автентифікації SSH
Вбудований тип kubernetes.io/ssh-auth наданий для зберігання даних, що використовуються в автентифікації SSH. Під час використання цього типу Secret вам потрібно вказати пару ключ-значення ssh-privatekey в полі data (або stringData) як SSH-автентифікаційні дані для використання.
Цей маніфест є прикладом Secret, який використовується для автентифікації SSH з використанням пари публічного/приватного ключів:
apiVersion: v1
kind: Secret
metadata:
name: secret-ssh-auth
type: kubernetes.io/ssh-auth
data:
# the data is abbreviated in this example
ssh-privatekey: |
UG91cmluZzYlRW1vdGljb24lU2N1YmE=
Тип Secret для автентифікації SSH наданий лише для зручності. Ви можете створити тип Opaque для облікових даних, які використовуються для автентифікації SSH. Однак використання визначеного та публічного типу Secret (kubernetes.io/ssh-auth) допомагає іншим людям зрозуміти призначення вашого Secret та встановлює домовленості для очікуваних назв ключів. API Kubernetes перевіряє, чи встановлені необхідні ключі для Secret цього типу.
Увага:
Приватні ключі SSH не встановлюють довіру між клієнтом SSH та хост-сервером самі по собі. Для зменшення ризику атак "man-in-the-middle" потрібен додатковий спосіб встановлення довіри, наприклад, файл known_hosts, доданий до ConfigMap.TLS Secrets
Тип Secret kubernetes.io/tls призначений для зберігання сертифіката та повʼязаного з ним ключа, які зазвичай використовуються для TLS.
Одним з поширених використань TLS Secret є налаштування шифрування під час передачі для Ingress, але ви також можете використовувати його з іншими ресурсами або безпосередньо у вашому навантаженні. Під час використання цього типу Secret ключі tls.key та tls.crt повинні бути надані в полі data (або stringData) конфігурації Secret, хоча API-сервер фактично не перевіряє значення кожного ключа.
Як альтернативу використанню stringData, ви можете використовувати поле data для надання сертифіката та приватного ключа у вигляді base64-кодованого тексту. Докладніше див. Обмеження щодо назв і даних Secret.
Цей YAML містить приклад конфігурації TLS Secret:
apiVersion: v1
kind: Secret
metadata:
name: secret-tls
type: kubernetes.io/tls
data:
# values are base64 encoded, which obscures them but does NOT provide
# any useful level of confidentiality
# Replace the following values with your own base64-encoded certificate and key.
tls.crt: "REPLACE_WITH_BASE64_CERT"
tls.key: "REPLACE_WITH_BASE64_KEY"
Тип TLS Secret наданий лише для зручності. Ви можете створити тип Opaque для облікових даних, які використовуються для TLS-автентифікації. Однак використання визначеного та публічного типу Secret (kubernetes.io/tls) допомагає забезпечити однорідність формату Secret у вашому проєкті. API-сервер перевіряє, чи встановлені необхідні ключі для Secret цього типу.
Для створення TLS Secret за допомогою kubectl використовуйте підкоманду tls:
kubectl create secret tls my-tls-secret \
--cert=path/to/cert/file \
--key=path/to/key/file
Пара публічного та приватного ключів повинна існувати заздалегідь. Сертифікат публічного ключа для --cert повинен бути закодований у форматі .PEM і повинен відповідати наданому приватному ключу для --key.
Secrets bootstrap-токенів
Тип Secret bootstrap.kubernetes.io/token призначений для токенів, що використовуються під час процесу ініціалізації вузла. Він зберігає токени, які використовуються для підпису відомих ConfigMaps.
Secret bootstrap-токена зазвичай створюється в просторі імен kube-system і називається у формі bootstrap-token-<token-id>, де <token-id> — це 6-символьний рядок ідентифікатора токена.
Як маніфест Kubernetes, Secret bootstrap-токена може виглядати так:
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-5emitj
namespace: kube-system
type: bootstrap.kubernetes.io/token
data:
auth-extra-groups: c3lzdGVtOmJvb3RzdHJhcHBlcnM6a3ViZWFkbTpkZWZhdWx0LW5vZGUtdG9rZW4=
expiration: MjAyMC0wOS0xM1QwNDozOToxMFo=
token-id: NWVtaXRq
token-secret: a3E0Z2lodnN6emduMXAwcg==
usage-bootstrap-authentication: dHJ1ZQ==
usage-bootstrap-signing: dHJ1ZQ==
У Secret bootstrap-токена вказані такі ключі в data:
token-id: Випадковий рядок з 6 символів як ідентифікатор токена. Обовʼязковий.token-secret: Випадковий рядок з 16 символів як власне секрет токена. Обовʼязковий.description: Зрозумілий людині рядок, що описує, для чого використовується токен. Необовʼязковий.expiration: Абсолютний час UTC, відповідно до RFC3339, що вказує, коли має закінчитися дія токена. Необовʼязковий.usage-bootstrap-<usage>: Логічний прапорець, який вказує додаткове використання bootstrap-токена.auth-extra-groups: Розділений комами список назв груп, від імені яких відбуватиметься автентифікація на додачу до групи system:bootstrappers.
Ви також можете надати значення в полі stringData Secret без кодування в base64:
apiVersion: v1
kind: Secret
metadata:
# Note how the Secret is named
name: bootstrap-token-5emitj
# A bootstrap token Secret usually resides in the kube-system namespace
namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
auth-extra-groups: "system:bootstrappers:kubeadm:default-node-token"
expiration: "2020-09-13T04:39:10Z"
# This token ID is used in the name
token-id: "5emitj"
token-secret: "kq4gihvszzgn1p0r"
# This token can be used for authentication
usage-bootstrap-authentication: "true"
# and it can be used for signing
usage-bootstrap-signing: "true"
Примітка:
Поле stringData для Secret погано працює із застосуванням на боці сервера (server-side apply).Робота з Secrets
Створення Secret
Є кілька способів створення Secret:
Обмеження щодо назв і даних Secret
Назва обʼєкта Secret повинна бути дійсним імʼям DNS-піддомену.
Ви можете вказати поля data і/або stringData під час створення файлу конфігурації для Secret. Поля data і stringData є необовʼязковими. Значення для всіх ключів у полі data повинні бути base64-кодованими рядками. Якщо перетворення у рядок base64 не є бажаним, ви можете вибрати поле stringData, яке приймає довільні рядки як значення.
Ключі data і stringData повинні складатися з буквено-цифрових символів, -, _ або .. Усі пари ключ-значення в полі stringData внутрішньо обʼєднуються в поле data. Якщо ключ зустрічається як у полі data, так і у полі stringData, значення, вказане у полі stringData, має пріоритет.
Обмеження розміру
Розмір окремих Secrets обмежено 1MiB. Це зроблено для того, щоб уникнути створення дуже великих Secrets, які можуть вичерпати памʼять API-сервера та kubelet. Однак створення багатьох менших Secrets також може вичерпати памʼять. Ви можете використовувати квоту ресурсів для обмеження кількості Secrets (або інших ресурсів) у просторі імен.
Редагування Secret
Ви можете редагувати наявний Secret, якщо він не є незмінним. Для редагування Secret скористайтеся одним із таких методів:
Ви також можете редагувати дані у Secret за допомогою інструменту Kustomize. Проте цей метод створює новий обʼєкт Secret з відредагованими даними.
Залежно від того, як ви створили Secret, а також від того, як Secret використовується у ваших Podʼах, оновлення наявних обʼєктів Secret автоматично поширюються на Podʼи, які використовують ці дані. Для отримання додаткової інформації звертайтеся до розділу Використання Secrets як файлів у Podʼі.
Використання Secret
Secrets можна монтувати як томи даних або надавати як змінні середовища для використання контейнером у Podʼі. Secrets також можуть використовуватися іншими частинами системи без безпосереднього надання Podʼу. Наприклад, Secrets можуть містити автентифікаційні дані, які інші частини системи повинні використовувати для взаємодії із зовнішніми системами від вашого імені.
Джерела томів Secret перевіряються, щоб переконатися, що вказане посилання на обʼєкт дійсно вказує на обʼєкт типу Secret. Тому Secret повинен бути створений перед будь-якими Podʼами, які залежать від нього.
Якщо Secret не може бути отриманий (можливо, через те, що він не існує, або через тимчасову відсутність зʼєднання з API-сервером), kubelet періодично повторює спробу запуску цього Podʼа. Kubelet також повідомляє про подію (Event) для цього Podʼа, включаючи деталі проблеми отримання Secret.
Необовʼязкові Secrets
Коли ви посилаєтеся на Secret у Podʼі, ви можете позначити Secret як необовʼязковий, як у цьому прикладі. Якщо необовʼязковий Secret не існує, Kubernetes ігнорує його.
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
optional: true
Типово Secrets є обовʼязковими. Жоден з контейнерів Podʼа не розпочне роботу, доки всі обовʼязкові Secrets не будуть доступні.
Якщо Pod посилається на певний ключ у обовʼязковому Secret і цей Secret існує, але в ньому немає зазначеного ключа, Pod завершується невдачею під час запуску.
Використання Secrets як файлів у Podʼі
Якщо ви хочете отримати доступ до даних з Secret у Podʼі, один зі способів це зробити — щоб Kubernetes зробив значення цього Secret доступним як файл у файловій системі одного або декількох контейнерів Podʼа.
Щоб це зробити, дивіться Створення Podʼа, який має доступ до секретних даних через том.
Коли том містить дані з Secret, а цей Secret оновлюється, Kubernetes відстежує це і оновлює дані в томі, використовуючи підхід кінцевої узгодженості (eventually consistent).
Примітка:
Контейнер, який використовує Secret як том з монтуванням
subPath, не отримує автоматичних оновлень Secret.
Kubelet зберігає кеш поточних ключів та значень для Secrets, які використовуються у томах для Podʼів на цьому вузлі. Ви можете налаштувати спосіб, яким kubelet виявляє зміни від кешованих значень. Поле configMapAndSecretChangeDetectionStrategy в конфігурації kubelet контролює стратегію, яку використовує kubelet. Стандартною стратегією є Watch.
Оновлення Secrets можуть передаватися за допомогою механізму watch API (стандартно), на основі кешу з визначеним часом життя або шляхом опитування API-сервера кластера на кожному циклі синхронізації kubelet.
Як результат, загальна затримка від моменту оновлення Secret до моменту, коли нові ключі буде спроєцьовано в Pod, може дорівнювати періоду синхронізації kubelet + затримці поширення кешу, де затримка поширення кешу залежить від обраного типу кешу (у тому самому порядку, що й у попередньому абзаці: затримка поширення watch, налаштований TTL кешу або нуль для прямого опитування).
Використання Secrets як змінних середовища
Для використання Secret в змінних середовища в Podʼі:
- Для кожного контейнера у вашій специфікації Podʼа додайте змінну середовища для кожного ключа Secret, який ви хочете використовувати, у поле
env[].valueFrom.secretKeyRef. - Змініть свій образ і/або командний рядок так, щоб програма шукала значення у вказаних змінних середовища.
Для отримання інструкцій дивіться Визначення змінних середовища контейнера за допомогою даних Secret.
Важливо зауважити, що діапазон символів, дозволених для назв змінних середовища в Podʼах, обмежений. Якщо будь-які ключі не відповідають правилам, ці ключі не будуть доступні вашому контейнеру, хоча Pod може бути запущений.
Secrets для завантаження образів контейнерів
Якщо ви хочете отримувати образи контейнерів з приватного репозиторію, вам потрібен спосіб автентифікації для kubelet на кожному вузлі для доступу до цього репозиторію. Ви можете налаштувати Secrets для завантаження образів для досягнення цієї мети. Ці Secrets налаштовуються на рівні Podʼа.
Використання imagePullSecrets
Поле imagePullSecrets є списком посилань на Secrets у тому самому просторі імен. Ви можете використовувати imagePullSecrets, щоб передати Secret, який містить пароль Docker (або іншого) репозиторію образів, в kubelet. Kubelet використовує цю інформацію для завантаження приватного образу від імені вашого Podʼа. Для отримання додаткової інформації про поле imagePullSecrets дивіться PodSpec API.
Вказування imagePullSecret вручну
Ви можете дізнатися, як вказати imagePullSecrets, переглянувши документацію про образи контейнерів.
Організація автоматичного приєднання imagePullSecrets
Ви можете вручну створити imagePullSecrets та посилатися на них з ServiceAccount. Будь-які Podʼи, створені з цим ServiceAccount або типово з ним, отримають поле imagePullSecrets, встановлене відповідно до цього ServiceAccount. Дивіться Додавання ImagePullSecrets до ServiceAccount для детального пояснення цього процесу.
Використання Secrets зі статичними Podʼами
Ви не можете використовувати ConfigMaps або Secrets зі статичними Podʼами.
Незмінні Secrets
СТАН ФУНКЦІОНАЛУ:
GA since Kubernetes v1.21
Kubernetes дозволяє вам позначати певні Secrets (і ConfigMaps) як незмінні. Запобігання змінам даних наявного Secret має такі переваги:
- захищає вас від випадкових (або небажаних) оновлень, які можуть призвести до відмов застосунків
- (для кластерів, що широко використовують Secrets, — щонайменше десятки тисяч унікальних монтувань Secret у Podʼи) перехід до незмінних Secrets покращує продуктивність вашого кластера завдяки значному зменшенню навантаження на kube-apiserver. Kubelet не потрібно підтримувати [watch] для будь-яких Secrets, позначених як незмінні.
Позначення Secret як незмінного
Ви можете створити незмінний Secret, встановивши поле immutable в true. Наприклад,
apiVersion: v1
kind: Secret
metadata: ...
data: ...
immutable: true
Ви також можете оновити будь-який наявний змінний Secret, щоб зробити його незмінним.
Примітка:
Як тільки Secret або ConfigMap позначений як незмінний, цю зміну неможливо скасувати чи змінити зміст поля data. Ви можете тільки видалити і знову створити Secret. Наявні Podʼи зберігають точку монтування для видаленого Secret — рекомендується створити ці Podʼи заново.Хоча ConfigMap і Secret працюють схоже, Kubernetes застосовує додаткові заходи захисту для обʼєктів Secret.
Secrets часто містять значення різного ступеня важливості, багато з яких можуть спричинити ескалацію привілеїв у Kubernetes (наприклад, токени ServiceAccount) та у зовнішніх системах. Навіть якщо окремий застосунок може оцінити можливості Secrets, з якими очікує взаємодіяти, інші застосунки в тому самому просторі імен можуть зробити ці припущення недійсними.
Налаштування авторизації впливає на те, як можна отримати доступ до даних Secret у межах простору імен. Наприклад, надання дозволів list або watch для Secrets дозволяє субʼєкту читати всі дані Secret у цьому просторі імен, а не лише ті Secrets, на які явно посилаються його Podʼи. Обмежте доступ до мінімального набору дозволів, необхідних для роботи навантаження, і уникайте надання широких ролей, таких як cluster-admin, якщо це не потрібно для адміністративних цілей.
Також дивіться документацію з авторизації.
Secret буде відправлений на вузол тільки у випадку, якщо на цьому вузлі є Pod, якому він потрібен. Для монтування Secrets у Podʼи kubelet зберігає копію даних у tmpfs, щоб конфіденційні дані не записувалися на постійний носій. Коли Pod, який залежить від Secret, видаляється, kubelet видаляє свою локальну копію конфіденційних даних з Secret.
У Podʼі може бути кілька контейнерів. Типово контейнери, які ви визначаєте, мають доступ тільки до стандартного ServiceAccount та повʼязаного з ним Secret. Вам потрібно явно визначити змінні середовища або відобразити том у контейнері, щоб надати доступ до будь-якого іншого Secret.
На одному вузлі можуть бути Secrets для кількох Podʼів. Проте лише ті Secrets, які запитує Pod, потенційно видимі всередині його контейнерів. Таким чином, один Pod не має доступу до Secrets іншого Podʼа.
Щоб посилити заходи безпеки навколо Secrets, використовуйте окремі простори імен для ізоляції доступу до змонтованих Secrets.
Попередження:
Будь-які контейнери, які працюють з параметром privileged: true на вузлі, можуть отримати доступ до всіх Secrets, що використовуються на цьому вузлі.Що далі
3 - Керування ресурсами Podʼів та контейнерів
Коли ви визначаєте Pod, ви можете додатково вказати, скільки кожного ресурсу потребує контейнер. Найпоширеніші ресурси, які вказують, — це CPU та памʼять (RAM); є й інші.
Коли ви вказуєте запит ресурсів для контейнерів в Podʼі, kube-scheduler використовує цю інформацію для вибору вузла, на який розмістити Pod. Коли ви вказуєте обмеження ресурсів для контейнера, kubelet забезпечує виконання цих обмежень, щоб запущений контейнер не міг використовувати більше цього ресурсу, ніж обмеження, яке ви встановили. Kubelet також резервує принаймні запитану кількість цього системного ресурсу спеціально для використання цим контейнером.
Запити та обмеження
Якщо вузол, на якому запущений Pod, має достатньо вільного ресурсу, то контейнер може (і має право) використовувати більше ресурсу, ніж зазначено в його request для цього ресурсу.
Наприклад, якщо ви встановите запит memory 256 MiB для контейнера, і цей контейнер буде в Podʼі, запланованому на вузол із 8GiB памʼяті та без інших Podʼів, то контейнер може спробувати використати більше оперативної памʼяті.
Обмеження — то вже інша справа. Обидва обмеження cpu та memory застосовуються kubeletʼом (та середовищем виконання контейнерів), і, зрештою, забезпечуються ядром. На вузлах Linux ядро Linux застосовує обмеження за допомогою cgroups. Поведінка застосування обмежень cpu та memory дещо відрізняється.
Обмеження cpu застосовуються через тротлінг CPU (CPU throttling). Коли контейнер наближається до свого обмеження cpu, ядро обмежує доступ до CPU відповідно до обмеження контейнера. Тож обмеження cpu є жорстким обмеженням, що застосовує ядро. Контейнери не можуть використовувати більше CPU, ніж зазначено в їх обмеженні cpu.
Обмеження memory застосовуються ядром через завершення процесів за нестачі памʼяті (OOM kills). Якщо контейнер використовує більше памʼяті, ніж його обмеження memory, ядро може його завершити. Однак завершення відбувається тільки тоді, коли ядро виявляє тиск на памʼять. Тому контейнер, який виділяє забагато памʼяті, може бути завершений не одразу. Це означає, що обмеження memory застосовуються реактивно. Контейнер може використовувати більше памʼяті, ніж його обмеження memory, але в такому разі його може бути завершено.
Примітка:
Існує функція
MemoryQoS, яка додає тротлінг памʼяті та необовʼязкове багаторівневе резервування памʼяті на вузлах Linux за допомогою cgroup v2. Докладніше дивіться
Memory QoS з cgroup v2.
Примітка:
Якщо ви вказали обмеження для ресурсу, але не вказали жодного запиту, і жодний механізм допуску не застосував стандартного значення запиту для цього ресурсу, то Kubernetes скопіює обмеження, яке ви вказали, та використовує його як запитане значення для ресурсу.Типи ресурсів
Тип ресурсу має базову одиницю вимірювання, і його можна запитувати, обмежувати або і те, й інше. Kubernetes має такі вбудовані типи ресурсів:
Кластери також можуть надавати розширені ресурси (ресурси з власною назвою, які зазвичай надають втулки пристроїв).
Великі сторінки
Для робочих навантажень на Linux ви можете вказати ресурси великих сторінок (huge pages). Великі сторінки є функцією, специфічною для Linux, де ядро вузла виділяє блоки памʼяті, значно більші за стандартний розмір сторінки.
Наприклад, у системі, де розмір стандартної сторінки становить 4KiB, ви можете вказати обмеження hugepages-2Mi: 80Mi. Якщо контейнер намагається виділити понад 40 великих сторінок по 2MiB (загалом 80 MiB), це виділення завершиться невдачею.
Примітка:
Ресурси hugepages-* не можна виділяти понад наявні (overcommit). Це відрізняється від ресурсів memory та cpu.CPU та памʼять спільно називаються обчислювальними ресурсами або ресурсами. Обчислювальні ресурси — це вимірювані величини, які можна запитувати, виділяти та використовувати. Вони відрізняються від ресурсів API. Ресурси API, такі як Podʼи та Services, є обʼєктами, які можна читати та змінювати через API-сервер Kubernetes.
Запити та обмеження ресурсів для Podʼа та контейнера
Для кожного контейнера ви можете вказати обмеження та запити ресурсів, зокрема такі:
spec.containers[].resources.limits.cpuspec.containers[].resources.limits.memoryspec.containers[].resources.limits.ephemeral-storagespec.containers[].resources.limits.hugepages-<size>spec.containers[].resources.requests.cpuspec.containers[].resources.requests.memoryspec.containers[].resources.requests.ephemeral-storagespec.containers[].resources.requests.hugepages-<size>
Хоча ви можете вказувати запити та обмеження тільки для окремих контейнерів, також корисно думати про загальні запити та обмеження ресурсів для Podʼа. Для певного ресурсу запит/обмеження ресурсів Podʼа — це сума запитів/обмежень цього типу для кожного контейнера в Podʼі.
Специфікація ресурсів на рівні Podʼів
СТАН ФУНКЦІОНАЛУ:
Beta since Kubernetes v1.34; (стандартно увімкнено)
За умови, що у вашому кластері увімкнено функціональну можливість PodLevelResources, ви можете вказувати запити та обмеження ресурсів на рівні Podʼа. На рівні Podʼа Kubernetes 1.37 підтримує запити або обмеження ресурсів лише для певних типів ресурсів: cpu та/або memory, та/або hugepages. Завдяки цій функції Kubernetes дозволяє вам декларувати загальний бюджет ресурсів для Podʼа, що є особливо корисним під час роботи з великою кількістю контейнерів, де може бути важко точно визначити індивідуальні потреби у ресурсах. Крім того, це дає змогу контейнерам у межах Podʼа ділитися один з одним ресурсами, що простоюють, покращуючи використання ресурсів.
Для Podʼа ви можете вказати обмеження та запити ресурсів для CPU і памʼяті, включивши таке:
spec.resources.limits.cpuspec.resources.limits.memoryspec.resources.limits.hugepages-<size>spec.resources.requests.cpuspec.resources.requests.memoryspec.resources.requests.hugepages-<size>
Одиниці виміру ресурсів в Kubernetes
Одиниці виміру ресурсів CPU
Обмеження та запити ресурсів CPU вимірюються в одиницях cpu. У Kubernetes 1 одиниця CPU еквівалентна 1 фізичному ядру CPU або 1 віртуальному ядру, залежно від того, чи є вузол фізичним хостом або віртуальною машиною, яка працює всередині фізичної машини.
Допускаються дробові запити. Коли ви визначаєте контейнер зі значенням 0.5 у spec.containers[].resources.requests.cpu, ви запитуєте вдвічі менше часу CPU, ніж якби запросили 1.0 CPU. Для одиниць ресурсів CPU вираз кількості 0.1 еквівалентний виразу 100m, що можна прочитати як "сто millicpu". Деякі люди кажуть "сто міліядер", і це розуміється так само.
Ресурс CPU завжди вказується як абсолютна кількість ресурсу, ніколи як відносна кількість. Наприклад, 500m CPU представляє приблизно ту саму обчислювальну потужність незалежно від того, чи працює цей контейнер на одноядерній, двоядерній або 48-ядерній машині.
Примітка:
Kubernetes не дозволяє вказувати ресурси CPU з точністю вище 1m або 0.001 CPU. Щоб уникнути випадкового використання неприпустимої кількості CPU, корисно вказувати одиниці CPU, використовуючи форму milliCPU замість десяткової форми, коли використовується менше ніж 1 одиниця CPU.
Наприклад, у вас є Pod, який використовує 5m або 0.005 CPU, і ви хочете зменшити його ресурси CPU. Використовуючи десяткову форму, важко помітити, що 0.0005 CPU є неприпустимим значенням, тоді як використовуючи форму milliCPU, легше помітити, що 0.5m є неприпустимим значенням.
Одиниці виміру ресурсів памʼяті
Обмеження та запити для memory вимірюються в байтах. Ви можете вказувати памʼять як звичайне ціле число або як число з фіксованою комою, використовуючи один із таких суфіксів кількості: E, P, T, G, M, k. Ви також можете використовувати еквіваленти степенів двійки: Ei, Pi, Ti, Gi, Mi, Ki. API Kubernetes також дозволяє використовувати суфікс m (для мілібайтів: 1/1000 байта), але вказувати його немає сенсу: завжди потрібно призначати цілі числа байтів або іноді більші блоки, такі як кратні 1 гібібайту.
Ось кілька прикладів визначення обсягу памʼяті, які приблизно представляють те саме значення:
128974848, 129e6, 129M, 128974848000m, 123Mi
Звертайте увагу на регістр суфіксів. "M" означає мегабайти, тоді як "m" означає мілібайти. Якщо ви запитуєте 400m памʼяті, це запит на 0,4 байта. Той, хто вводить це, ймовірно, мав на увазі запросити 400 мебібайтів (400Mi) або 400 мегабайтів (400M).
Приклад ресурсів контейнера
У цьому Podʼі є два контейнери. Обидва контейнери визначені із запитом на 0,25 CPU і 64MiB (226 байт) памʼяті. Кожен контейнер має обмеження в 0,5 CPU та 128MiB памʼяті. Можна сказати, що Pod має запит на 0,5 CPU та 128 MiB памʼяті й обмеження в 1 CPU та 256MiB памʼяті.
---
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Приклад ресурсів Podʼа
СТАН ФУНКЦІОНАЛУ:
Beta since Kubernetes v1.34; (стандартно увімкнено)
Цю можливість можна увімкнути за допомогою функціональної можливості PodLevelResources. Цей Pod має явний запит на 1 CPU та 100 MiB памʼяті, а також явне обмеження в 1 CPU та 200 MiB памʼяті. Контейнер pod-resources-demo-ctr-1 має явні запити та обмеження. Однак контейнер pod-resources-demo-ctr-2 просто спільно використовуватиме ресурси, доступні в межах ресурсів 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ʼи із запитами ресурсів
Коли ви створюєте Pod, планувальник Kubernetes вибирає вузол, на якому Pod буде запущено. Кожен вузол має максимальну місткість для кожного з типів ресурсів: кількість CPU та обсяг памʼяті, які він може надати для Podʼів. Планувальник гарантує, що для кожного типу ресурсів сума запитів ресурсів запланованих контейнерів буде менше, ніж місткість вузла. Зверніть увагу, що навіть якщо фактичне використання ресурсів CPU або памʼяті на вузлі дуже низьке, планувальник все одно відмовляється розміщувати Pod на вузлі, якщо перевірка місткості не пройшла успішно. Це захищає від нестачі ресурсів на вузлі, коли пізніше збільшується використання ресурсів, наприклад, під час щоденного піку кількості запитів.
Як Kubernetes застосовує запити на ресурси та обмеження
Коли kubelet запускає контейнер як частину Podʼа, він передає запити та обмеження для памʼяті та CPU цього контейнера до середовища виконання контейнерів.
У Linux середовище виконання контейнерів зазвичай налаштовує cgroups ядра, які застосовують і забезпечують виконання визначених вами обмежень.
- Обмеження CPU встановлює жорстку верхню межу часу CPU, який може використовувати контейнер. Протягом кожного інтервалу планування (часового відрізка) ядро Linux перевіряє, чи перевищується це обмеження; якщо так, ядро чекає, перш ніж дозволити цій cgroup продовжити виконання.
- Запит CPU зазвичай визначає вагу. Якщо кілька різних контейнерів (cgroups) хочуть працювати на системі з конкуренцією за ресурси, робочі навантаження з більшими запитами CPU отримують більше часу CPU, ніж робочі навантаження з малими запитами.
- Запит памʼяті в основному використовується під час планування Podʼа (Kubernetes). На вузлі, що використовує cgroups v2, середовище виконання контейнерів може використовувати запит памʼяті як підказку для встановлення
memory.min та memory.low. - Обмеження памʼяті встановлює обмеження памʼяті для цієї контрольної групи. Якщо контейнер намагається виділити більше памʼяті, ніж це обмеження, підсистема обробки нестачі памʼяті (out-of-memory) ядра Linux активується і, зазвичай, втручається, зупиняючи один з процесів у контейнері, який намагався виділити памʼять. Якщо цей процес є PID 1 контейнера, і контейнер позначений як такий, що може перезапускатися, Kubernetes перезапускає контейнер.
- Обмеження памʼяті для Podʼа або контейнера також може застосовуватися до сторінок у томах, що зберігаються в памʼяті, таких як
emptyDir. Kubelet відстежує томи emptyDir типу tmpfs як використання памʼяті контейнера, а не як локальне тимчасове сховище. Під час використання emptyDir у памʼяті обовʼязково ознайомтеся з примітками нижче.
Якщо контейнер перевищує свій запит на памʼять і вузол, на якому він працює, загалом стикається з нестачею памʼяті, ймовірно, що Pod, якому належить цей контейнер, буде виселено.
Контейнеру може бути дозволено або не дозволено перевищувати своє обмеження CPU протягом тривалого часу. Однак середовища виконання контейнерів не завершують Podʼи або контейнери через надмірне використання CPU.
Щоб визначити, чи контейнер неможливо запланувати або чи його завершують через обмеження ресурсів, див. розділ Усунення несправностей.
Зміна розміру ресурсів контейнера
Після створення Podʼа може знадобитися налаштувати його ресурси CPU або памʼяті відповідно до фактичних моделей використання. Kubernetes пропонує два підходи до зміни розміру ресурсів Podʼа:
Зміна розміру на місці
СТАН ФУНКЦІОНАЛУ:
GA since Kubernetes v1.35
More information about this feature
This is a stable feature in Kubernetes, and has been since version v1.35. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate InPlacePodVerticalScaling, Kubernetes ignores it but does not report any error.
Ви можете змінити requests та limits CPU та памʼяті контейнерів у запущеному Podʼі без його повторного створення. Це називається вертикальним масштабуванням Podʼа на місці або зміною розміру Podʼа на місці. Щоб виконати зміну розміру на місці, оновіть специфікації ресурсів контейнера за допомогою субресурсу Podʼа /resize. Ви можете контролювати, чи потрібно перезапускати контейнер, встановивши поле resizePolicy у специфікації контейнера.
Примітка:
СТАН ФУНКЦІОНАЛУ:
Alpha since Kubernetes v1.37; (стандартно вимкнено)
Коли увімкнено функціональну можливість InPlacePodVerticalScalingSchedulerPreemption, відкладені запити на зміну розміру на місці можуть спонукати kube-scheduler витіснити Podʼи з нижчим пріоритетом на призначеному вузлі, щоб звільнити місце для зміни розміру. Для отримання додаткових відомостей див. Витіснення для зміни розміру Podʼа на місці.
Зміна розміру шляхом запуску Podʼів-замінників
Підхід cloud native до зміни ресурсів Podʼа полягає в оновленні шаблону Podʼа в обʼєкті робочого навантаження (такому як Deployment або StatefulSet) і дозволі контролеру робочого навантаження замінити Podʼи новими, що мають оновлені ресурси. Цей підхід працює з будь-якою версією Kubernetes і дозволяє змінювати будь-які специфікації Podʼів.
Детальніше про зміну розміру Podʼів див. Зміна розміру Podʼа. Детальні інструкції щодо зміни розміру на місці див. у розділі Зміна розміру ресурсів CPU та памʼяті, призначених контейнерам. Ви також можете використовувати Vertical Pod Autoscaler для автоматичного управління рекомендаціями щодо ресурсів Podʼа.
Моніторинг використання обчислювальних ресурсів та ресурсів памʼяті
Kubelet повідомляє про використання ресурсів Podʼа як частину status Podʼа.
Якщо у вашому кластері доступні інструменти для моніторингу, то використання ресурсів Podʼа можна отримати або безпосередньо з Metrics API, або з ваших інструментів моніторингу.
Міркування щодо томів emptyDir, що зберігаються в памʼяті
Примітка:
СТАН ФУНКЦІОНАЛУ:
Alpha since Kubernetes v1.37; (стандартно вимкнено)
Коли увімкнено функціональну можливість InPlacePodVerticalScalingMemoryBackedVolumes, ви можете динамічно змінювати sizeLimit тому emptyDir, що зберігається в памʼяті (medium: Memory), на запущеному Podʼі без повторного створення Podʼа або перезапуску контейнерів. Покрокові інструкції див. у розділі Зміна розміру ресурсів CPU та памʼяті, призначених контейнерам.
Увага:
Якщо ви не вказуєте sizeLimit для тому emptyDir, цей том може використовувати памʼять до обмеження памʼяті цього Podʼа (Pod.spec.containers[].resources.limits.memory). Якщо ви не встановлюєте обмеження памʼяті, Pod не має верхньої межі на споживання памʼяті і може використовувати всю доступну памʼять на вузлі. Kubernetes планує Podʼи на основі запитів на ресурси (Pod.spec.containers[].resources.requests) і не враховує використання памʼяті понад запит під час вирішення, чи може інший Pod розміститися на даному вузлі. Це може призвести до відмови в обслуговуванні та змусити ОС виконати обробку нестачі памʼяті (OOM). Можна створити будь-яку кількість emptyDir, які потенційно можуть використовувати всю доступну памʼять на вузлі, що робить OOM більш ймовірним.З точки зору управління памʼяттю, є деякі подібності між використанням памʼяті як робочої області процесу і використанням памʼяті для emptyDir, що зберігається в памʼяті. Але під час використання памʼяті як тому, як у випадку з emptyDir, що зберігається в памʼяті, є додаткові моменти, на які слід звернути увагу:
- Файли, збережені в томі, що зберігається в памʼяті, майже повністю управляються застосунком користувача. На відміну від використання памʼяті як робочої області процесу, ви не можете покладатися на такі речі, як збір сміття на рівні мови програмування.
- Мета запису файлів в том полягає в збереженні даних або їх передачі між застосунками. Ні Kubernetes, ні ОС не можуть автоматично видаляти файли з тому, тому памʼять, яку займають ці файли, не може бути звільнена, коли система або Pod відчувають тиск на памʼять.
- Томи
emptyDir, що зберігаються в памʼяті, корисні через свою продуктивність, але памʼять зазвичай набагато менша за розміром і набагато дорожча за інші носії, такі як диски або SSD. Використання великої кількості памʼяті для томів emptyDir може вплинути на нормальну роботу вашого Podʼа або всього вузла, тому їх слід використовувати обережно.
Якщо ви адмініструєте кластер або простір імен, ви також можете встановити ResourceQuota, що обмежує використання памʼяті; також може бути корисно визначити LimitRange для додаткового забезпечення обмежень. Якщо ви вказуєте spec.containers[].resources.limits.memory для кожного Podʼа, то максимальний розмір тому emptyDir буде дорівнювати обмеженню памʼяті Podʼа.
Як альтернатива, адміністратор кластера може забезпечити дотримання обмежень на розмір томів emptyDir в нових Podʼах, використовуючи механізм політики, такий як ValidatingAdmissionPolicy.
Локальне тимчасове сховище
Щодо загальних концепцій про локальне тимчасове сховище та порад щодо налаштування запитів і/або обмежень локального тимчасового сховища для контейнера, дивіться сторінку локальне тимчасове сховище.
Моніторинг ресурсів для локального тимчасового сховища
Kubelet може вимірювати, скільки локального тимчасового сховища використовується. Він робить це, якщо ви ввімкнули ізоляцію ємності локального тимчасового сховища.
Kubernetes відстежує обсяг тимчасового сховища, яке використовує Pod, із таких джерел:
- Запис у шар контейнера, доступний для запису (rootfs), в образи контейнерів або і туди, й туди.
- Запис у локальні томи
emptyDir. - Власні логи Podʼа (зазвичай зберігаються в
/var/log/pods). - Системні файли, керовані Kubernetes, які відображаються в Pod, наприклад
/etc/hosts.
Розширені ресурси
Розширені ресурси — це повністю кваліфіковані назви ресурсів поза доменом kubernetes.io. Вони дозволяють операторам кластера оголошувати, а користувачам використовувати ресурси, які не вбудовані в Kubernetes.
Щоб скористатися розширеними ресурсами, потрібно виконати два кроки. По-перше, оператор кластера повинен оголосити розширений ресурс. По-друге, користувачі повинні запитати розширений ресурс у Podʼах.
Керування розширеними ресурсами
Розширені ресурси на рівні вузла
Розширені ресурси на рівні вузла повʼязані з вузлами.
Ресурси, керовані втулками пристроїв
Дивіться Втулок пристроїв щодо того, як оголошувати ресурси, що керуються втулком пристроїв на кожному вузлі.
Інші ресурси
Щоб оголосити новий розширений ресурс на рівні вузла, оператор кластера може надіслати HTTP-запит типу PATCH до API-сервера, щоб вказати доступну кількість в полі status.capacity для вузла у кластері. Після цієї операції поле status.capacity вузла буде містити новий ресурс. Kubelet автоматично й асинхронно оновлює поле status.allocatable, додаючи новий ресурс.
Оскільки планувальник використовує значення status.allocatable вузла під час оцінювання придатності Podʼа, планувальник враховує нове значення лише після цього асинхронного оновлення. Між моментом зміни місткості вузла новим ресурсом і часом, коли перший Pod, який запитує ресурс, може бути запланований на цьому вузлі, може відбуватися коротка затримка.
Приклад:
Нижче наведено приклад використання curl для формування HTTP-запиту, який оголошує пʼять ресурсів "example.com/foo" на вузлі k8s-node-1, master якого — k8s-master.
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
Примітка:
У наведеному вище запиті
~1 — це кодування символу
/ у шляху патча. Значення шляху операції у JSON-Patch інтерпретується як JSON-Pointer. Докладніше дивіться
IETF RFC 6901, розділ 3.
Розширені ресурси на рівні кластера
Розширені ресурси на рівні кластера не повʼязані з вузлами. Зазвичай ними керують розширювачі планувальника, які відповідають за споживання ресурсів і квоту ресурсів.
Ви можете вказати розширені ресурси, які обробляються розширювачами планувальника, в конфігурації планувальника.
Приклад:
Ця конфігурація для політики планувальника вказує на те, що розширений ресурс на рівні кластера "example.com/foo" обробляється розширювачем планувальника.
- Планувальник відправляє Pod до розширювача планувальника тільки у випадку, якщо Pod запитує "example.com/foo".
- Поле
ignoredByScheduler вказує, що планувальник не перевіряє ресурс "example.com/foo" в своєму предикаті PodFitsResources.
{
"kind": "Policy",
"apiVersion": "v1",
"extenders": [
{
"urlPrefix":"<extender-endpoint>",
"bindVerb": "bind",
"managedResources": [
{
"name": "example.com/foo",
"ignoredByScheduler": true
}
]
}
]
}
Розподілення розширених ресурсів за допомогою DRA
Розподілення розширених ресурсів за допомогою DRA дозволяє адміністраторам кластерів вказувати extendedResourceName у DeviceClass, після чого пристрої, що відповідають DeviceClass, можуть бути запитані з розширених запитів ресурсів Podʼа. Читайте більше про Розподілення розширених ресурсів за допомогою DRA.
Використання розширених ресурсів
Користувачі можуть використовувати розширені ресурси у специфікаціях Podʼа, подібно до CPU та памʼяті. Планувальник відповідає за облік ресурсів, щоб одночасно не виділялося більше доступної кількості ресурсів для Podʼів.
API-сервер обмежує кількість розширених ресурсів цілими числами. Приклади дійсних значень: 3, 3000m та 3Ki. Приклади недійсних значень: 0.5 та 1500m (тому що 1500m буде давати в результаті 1.5).
Примітка:
Розширені ресурси замінюють Opaque Integer Resources. Користувачі можуть використовувати будь-який префікс доменного імені, крім kubernetes.io, який зарезервований.Щоб використовувати розширений ресурс у Podʼі, включіть назву ресурсу як ключ у мапу spec.containers[].resources.limits у специфікації контейнера.
Примітка:
Розширені ресурси не можна виділяти понад наявні (overcommit), тому запит і обмеження мають бути рівними, якщо обидва присутні у специфікації контейнера.Pod планується лише тоді, коли задоволено всі запити ресурсів, включаючи CPU, памʼять та будь-які розширені ресурси. Pod залишається у стані PENDING, доки запит ресурсу неможливо задовольнити.
Приклад:
Нижче наведено Pod, який запитує 2 CPU та 1 "example.com/foo" (розширений ресурс).
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: myimage
resources:
requests:
cpu: 2
example.com/foo: 1
limits:
example.com/foo: 1
Обмеження PID
Обмеження ідентифікаторів процесів (PID) дозволяють налаштувати kubelet для обмеження кількості PID, яку може використовувати певний Pod. Див. Обмеження PID для отримання інформації.
Усунення несправностей
Мої Podʼи знаходяться в стані очікування з повідомленням події FailedScheduling
Якщо планувальник не може знайти жодного вузла, де може розміститися Pod, Pod залишається незапланованим, поки не буде знайдено місце. Кожного разу, коли планувальник не може знайти місце для Podʼа, створюється подія. Ви можете використовувати kubectl для перегляду подій Podʼа; наприклад:
kubectl describe pod frontend | grep -A 9999999999 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 23s default-scheduler 0/42 nodes available: insufficient cpu
У наведеному вище прикладі Pod із назвою "frontend" не вдалося запланувати через нестачу ресурсу CPU на будь-якому вузлі. Схожі повідомлення про помилку також можуть вказувати на невдачу через недостатню памʼять (PodExceedsFreeMemory). Загалом, якщо Pod знаходиться в стані очікування з таким типом повідомлення, є кілька речей, які варто спробувати:
- Додайте більше вузлів у кластер.
- Завершіть непотрібні Podʼи, щоб звільнити місце для очікуваних Podʼів.
- Перевірте, що Pod не є більшим, ніж усі вузли. Наприклад, якщо всі вузли мають місткість
cpu: 1, то Pod з запитом cpu: 1.1 ніколи не буде запланованим. - Перевірте наявність taints на вузлах. Якщо більшість ваших вузлів мають taint, і новий Pod не толерує цей taint, планувальник розглядає розміщення лише на решті вузлів, які не мають цього taint.
Ви можете перевірити місткості вузлів та виділені обсяги ресурсів за допомогою команди kubectl describe nodes. Наприклад:
kubectl describe nodes e2e-test-node-pool-4lw4
Name: e2e-test-node-pool-4lw4
[ ... lines removed for clarity ...]
Capacity:
cpu: 2
memory: 7679792Ki
pods: 110
Allocatable:
cpu: 1800m
memory: 7474992Ki
pods: 110
[ ... lines removed for clarity ...]
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
kube-system coredns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
680m (34%) 400m (20%) 920Mi (11%) 1070Mi (13%)
У наведеному вище виводі ви можете побачити, що якщо Pod запитує більше 1,120 CPU або більше 6,23Gi памʼяті, то цей Pod не поміститься на вузлі.
Подивившись на розділ "Pods", ви можете побачити, які Podʼи займають місце на вузлі.
Обсяг ресурсів, доступних для Podʼів, менший за місткість вузла, оскільки системні демони використовують частину доступних ресурсів. В API Kubernetes кожен вузол має поле .status.allocatable (див. NodeStatus для деталей).
Поле .status.allocatable описує обсяг ресурсів, доступних для Podʼів на цьому вузлі (наприклад: 15 віртуальних CPU та 7538 MiB памʼяті). Для отримання додаткової інформації про доступні для розподілу (allocatable) ресурси вузла в Kubernetes дивіться Резервування обчислювальних ресурсів для системних демонів.
Ви можете налаштувати квоти ресурсів для обмеження загального обсягу ресурсів, який може споживати простір імен. Kubernetes забезпечує дотримання квот для обʼєктів в конкретному просторі імен, коли існує ResourceQuota в цьому просторі імен. Наприклад, якщо ви призначаєте конкретні простори імен різним командам, ви можете додавати ResourceQuotas в ці простори імен. Встановлення квот ресурсів допомагає запобігти використанню однією командою так багато будь-якого ресурсу, що це впливає на інші команди.
Вам також варто розглянути, який доступ ви надаєте до цього простору імен: повний дозвіл на запис у простір імен дозволяє тому, хто має такий доступ, видаляти будь-який ресурс, включаючи налаштований ResourceQuota.
Робота мого контейнера завершується примусово
Робота вашого контейнера може бути завершена через нестачу ресурсів. Щоб перевірити, чи контейнер був завершений через досягнення обмеження ресурсів, викличте kubectl describe pod для потрібного Podʼа:
kubectl describe pod simmemleak-hra99
Вивід буде схожий на:
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
Labels: name=simmemleak
Status: Running
Reason:
Message:
IP: 10.244.2.75
Containers:
simmemleak:
Image: saadali/simmemleak:latest
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2019 12:54:41 -0700
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Fri, 07 Jul 2019 12:54:30 -0700
Finished: Fri, 07 Jul 2019 12:54:33 -0700
Ready: False
Restart Count: 5
Conditions:
Type Status
Ready False
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 42s default-scheduler Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
Normal Pulled 41s kubelet Container image "saadali/simmemleak:latest" already present on machine
Normal Created 41s kubelet Created container simmemleak
Normal Started 40s kubelet Started container simmemleak
Normal Killing 32s kubelet Killing container with id ead3fb35-5cf5-44ed-9ae1-488115be66c6: Need to kill Pod
У наведеному вище прикладі Restart Count: 5 вказує на те, що контейнер simmemleak у Podʼі був завершений та перезапущений пʼять разів (до цього моменту). Причина OOMKilled показує, що контейнер намагався використовувати більше памʼяті, ніж встановлене йому обмеження.
Наступним кроком може бути перевірка коду застосунку на витік памʼяті. Якщо ви виявите, що застосунок працює так, як очікувалося, розгляньте встановлення вищого обмеження памʼяті (і, можливо, запиту) для цього контейнера.
Що далі
4 - Організація доступу до кластера за допомогою файлів kubeconfig
Використовуйте файли kubeconfig для організації інформації про кластери, користувачів, простори імен та механізми автентифікації. Інструмент командного рядка kubectl використовує файли kubeconfig, щоб знайти інформацію, необхідну для вибору кластера та звʼязку з API-сервером кластера.
Примітка:
Файл, який використовується для налаштування доступу до кластерів, називається файлом kubeconfig. Це загальний спосіб посилання на файли конфігурації. Це не означає, що існує файл із назвою kubeconfig.Попередження:
Використовуйте файли kubeconfig лише з надійних джерел. Використання спеціально створеного файлу kubeconfig може призвести до виконання зловмисного коду або розкриття файлів. Якщо вам все ж потрібно використовувати ненадійний файл kubeconfig, уважно перевірте його, так само як ви це зробили б з файлом скрипту оболонки.Типово kubectl шукає файл із назвою config у теці $HOME/.kube. Ви можете вказати інші файли kubeconfig, встановивши змінну середовища KUBECONFIG або встановивши прапорець --kubeconfig.
Для покрокових інструкцій щодо створення та вказування файлів kubeconfig див. Налаштування доступу до кількох кластерів.
Підтримка кількох кластерів, користувачів та механізмів автентифікації
Припустимо, у вас є декілька кластерів, і ваші користувачі та компоненти автентифікуються різними способами. Наприклад:
- Запущений kubelet може автентифікуватися за допомогою сертифікатів.
- Користувач може автентифікуватися за допомогою токенів.
- Адміністратори можуть мати набори сертифікатів, які вони надають окремим користувачам.
За допомогою файлів kubeconfig ви можете організувати ваші кластери, користувачів та простори імен. Ви також можете визначити контексти, щоб швидко та легко перемикатися між кластерами та просторами імен.
Контекст
Елемент context у файлі kubeconfig використовується для групування параметрів доступу під зручною назвою. Кожен контекст має три параметри: кластер, простір імен та користувач. Типово інструмент командного рядка kubectl використовує параметри з поточного контексту для звʼязку з кластером.
Щоб обрати поточний контекст:
kubectl config use-context
Змінна середовища KUBECONFIG
Змінна середовища KUBECONFIG містить список файлів kubeconfig. Для Linux та Mac список розділяється двокрапкою. Для Windows список розділяється крапкою з комою. Змінна середовища KUBECONFIG не є обовʼязковою. Якщо змінна середовища KUBECONFIG не існує, kubectl використовує стандартний файл kubeconfig, $HOME/.kube/config.
Якщо змінна середовища KUBECONFIG існує, kubectl використовує підсумкову конфігурацію, яка є результатом обʼєднання файлів, перелічених у змінній середовища KUBECONFIG.
Обʼєднання файлів kubeconfig
Щоб переглянути вашу конфігурацію, введіть цю команду:
Як описано раніше, вивід може бути з одного файлу kubeconfig або бути результатом обʼєднання кількох файлів kubeconfig.
Ось правила, які використовує kubectl під час обʼєднання файлів kubeconfig:
Якщо встановлено прапорець --kubeconfig, використовуйте лише вказаний файл. Обʼєднання не здійснюється. Дозволяється лише один екземпляр цього прапорця.
В іншому випадку, якщо встановлена змінна середовища KUBECONFIG, використовуйте її як список файлів, які потрібно обʼєднати. Обʼєднайте файли, перелічені у змінній середовища KUBECONFIG, за такими правилами:
- Ігноруйте порожні імена файлів.
- Виводьте помилки для файлів з вмістом, який не може бути десеріалізований.
- Перший файл, що встановлює певне значення або ключ мапи, має перевагу.
- Ніколи не змінюйте значення або ключ мапи. Приклад: зберігайте контекст першого файлу, який встановлює
current-context. Приклад: якщо два файли вказують red-user, використовуйте лише значення з red-user першого файлу. Навіть якщо другий файл має неконфліктні записи в red-user, відкиньте їх.
Для прикладу встановлення змінної середовища KUBECONFIG дивіться Встановлення змінної середовища KUBECONFIG.
В іншому випадку використовуйте стандартний файл kubeconfig, $HOME/.kube/config, без обʼєднання.
Визначте контекст, який буде використовуватися, на основі першого збігу в цьому ланцюжку:
- Використовуйте прапорець командного рядка
--context, якщо він існує. - Використовуйте
current-context з обʼєднаних файлів kubeconfig.
Порожній контекст допускається на цьому етапі.
Визначте кластер та користувача. На цьому етапі може бути або не бути контексту. Визначте кластер та користувача на основі першого збігу в цьому ланцюжку, який запускається двічі: один раз для користувача та один раз для кластера:
- Використовуйте прапорці командного рядка, якщо вони існують:
--user або --cluster. - Якщо контекст не порожній, беріть користувача або кластер з контексту.
Користувач та кластер можуть бути порожніми на цьому етапі.
Визначте фактичну інформацію про кластер, яку слід використовувати. На цьому етапі може бути або не бути інформації про кластер. Побудуйте кожен елемент інформації про кластер на основі цього ланцюжка; перший збіг перемагає:
- Використовуйте прапорці командного рядка, якщо вони існують:
--server, --certificate-authority, --insecure-skip-tls-verify. - Якщо існують будь-які атрибути інформації про кластер з обʼєднаних файлів kubeconfig, використовуйте їх.
- Якщо немає розташування сервера, завершіть роботу з помилкою.
Визначте фактичну інформацію про користувача, яку слід використовувати. Побудуйте інформацію про користувача, використовуючи ті самі правила, що і для інформації про кластер, за винятком того, що дозволяється лише одна техніка автентифікації для кожного користувача:
- Використовуйте прапорці командного рядка, якщо вони існують:
--client-certificate, --client-key, --username, --password, --token. - Використовуйте поля
user з обʼєднаних файлів kubeconfig. - Якщо є дві суперечливі техніки, завершіть роботу з помилкою.
Для будь-якої інформації, що все ще відсутня, використовуйте стандартні значення і, можливо, запитайте інформацію для автентифікації.
Посилання на файли
Посилання на файли та шляхи в файлі kubeconfig є відносними до місця розташування файлу kubeconfig. Посилання на файли в командному рядку є відносними до поточної робочої теки. У файлі $HOME/.kube/config відносні шляхи зберігаються як відносні, а абсолютні — як абсолютні.
Проксі
Ви можете налаштувати kubectl на використання проксі для кожного кластера за допомогою proxy-url у вашому файлі kubeconfig, на зразок такого:
apiVersion: v1
kind: Config
clusters:
- cluster:
proxy-url: http://proxy.example.org:3128
server: https://k8s.example.org/k8s/clusters/c-xxyyzz
name: development
users:
- name: developer
contexts:
- context:
name: development
Що далі
5 - Управління ресурсами для вузлів Windows
Ця сторінка описує відмінності у способах управління ресурсами між Linux та Windows.
На Linux-вузлах використовуються cgroups як межа Podʼа для керування ресурсами. Контейнери створюються всередині цієї межі для ізоляції мережі, процесів та файлової системи. API cgroup для Linux може використовуватися для збору статистики використання CPU, введення/виведення та памʼяті.
Натомість у Windows використовується job object на кожен контейнер з фільтром системного простору імен, щоб обмежити всі процеси в контейнері та забезпечити логічну ізоляцію від хоста. (Обʼєкти завдань є механізмом ізоляції процесів Windows і відрізняються від того, що Kubernetes називає Job).
Не існує можливості запуску контейнера Windows без фільтрації простору імен. Це означає, що системні привілеї не можна отримати в контексті хоста, і, отже, привілейовані контейнери недоступні в Windows. Контейнери не можуть набувати ідентичності хоста, оскільки менеджер облікових записів безпеки (Security Account Manager, SAM) є окремим.
Управління памʼяттю
Windows не має OOM-завершувача процесів (out-of-memory process killer), як у Linux. Windows завжди розглядає всі виділення памʼяті в режимі користувача як віртуальні, і файли підкачки є обовʼязковими.
Вузли Windows не виділяють процесам памʼять понад наявну (overcommit). У підсумку Windows не доходить до стану нестачі памʼяті так, як Linux, і процеси вивантажуються на диск замість завершення через нестачу памʼяті (OOM). Якщо памʼять надмірно виділена і всю фізичну памʼять вичерпано, підкачка може знизити продуктивність.
Управління CPU
Windows може обмежувати кількість часу CPU, виділеного для різних процесів, але не може гарантувати мінімальну кількість часу CPU.
У Windows kubelet підтримує прапорець командного рядка для встановлення пріоритету планування процесу kubelet: --windows-priorityclass. Цей прапорець дозволяє процесу kubelet отримувати більше часових квантів CPU порівняно з іншими процесами, які виконуються на хості Windows. Додаткову інформацію про допустимі значення та їхнє тлумачення можна знайти за посиланням Класи пріоритетів Windows. Щоб гарантувати, що запущені Podʼи не позбавлять kubelet циклів CPU, встановіть цей прапорець у значення ABOVE_NORMAL_PRIORITY_CLASS або вище.
Резервування ресурсів
Щоб врахувати памʼять і CPU, які використовуються операційною системою, середовищем виконання контейнерів і процесами хоста Kubernetes, такими як kubelet, ви можете (і повинні) зарезервувати ресурси памʼяті та CPU за допомогою прапорців kubelet --kube-reserved та/або --system-reserved. У Windows ці значення використовуються лише для розрахунку доступних для розподілу (allocatable) ресурсів вузла.
Увага:
Під час розгортання навантажень встановлюйте обмеження ресурсів памʼяті та CPU для контейнерів. Це також зменшує NodeAllocatable та допомагає загальнокластерному планувальнику визначити, які Podʼи розмістити на яких вузлах.
Планування Podʼів без обмежень може надмірно виділити ресурси на вузлах Windows, і в крайніх випадках може призвести до того, що вузли стануть несправними.
У Windows доброю практикою є резервування принаймні 2GiB памʼяті.
Щоб визначити, скільки CPU резервувати, визначте максимальну щільність Podʼів для кожного вузла та відстежуйте використання CPU системними сервісами, що працюють там, а потім виберіть значення, яке відповідає потребам вашого робочого навантаження.