Квоти ресурсів
Коли декілька користувачів або команд спільно використовують кластер з фіксованою кількістю вузлів, є можливість, що одна команда може використовувати більше, ніж свою справедливу частку ресурсів.
Квоти ресурсів є інструментом для адміністраторів для розвʼязання цієї проблеми.
Квота ресурсів, визначена обʼєктом ResourceQuota
, надає обмеження, які обмежують загальне споживання ресурсів у просторі імен. Вона може обмежувати кількість обʼєктів, які можуть бути створені в просторі імен за типом, а також загальний обсяг обчислювальних ресурсів, які можуть бути спожиті ресурсами у цьому просторі імен.
Квоти ресурсів працюють наступним чином:
Різні команди працюють у різних просторах імен. Це може бути забезпечено з використанням RBAC.
Адміністратор створює одну квоту ресурсів для кожного простору імен.
Користувачі створюють ресурси (Podʼи, Serviceʼи тощо) у просторі імен, і система квот відстежує використання, щоб забезпечити, що воно не перевищує жорсткі обмеження ресурсів, визначені в ResourceQuota.
Якщо створення або оновлення ресурсу порушує обмеження квоти, запит буде відхилено з HTTP кодом стану
403 FORBIDDEN
з повідомленням, яке пояснює обмеження, що було б порушено.Якщо квота включена в простір імен для обчислювальних ресурсів, таких як
cpu
таmemory
, користувачі повинні вказати запити або ліміти для цих значень; інакше, система квот може відхилити створення Podʼа. Підказка: Використовуйте контролер допускуLimitRanger
, щоб надати для Podʼів, які не мають вимог до обчислювальних ресурсів, стандартні обсяги ресурсів.Дивіться посібник для прикладу того, як уникнути цієї проблеми.
Примітка:
- Для ресурсів
cpu
таmemory
, квоти ресурсів забезпечують, що кожен (новий) Pod у цьому просторі імен встановлює ліміт для цього ресурсу. Якщо ви встановлюєте квоту ресурсів у просторі імен дляcpu
абоmemory
, ви, і інші клієнти, повинні вказати абоrequests
, абоlimits
для цього ресурсу, для кожного нового Podʼа, який ви створюєте. Якщо ви цього не робите, панель управління може відхилити допуск для цього Podʼа. - Для інших ресурсів: ResourceQuota працює та ігнорує Podʼи в просторі імен, які не встановлюють ліміт або запит для цього ресурсу. Це означає, що ви можете створити новий Pod без обмеження/запиту тимчасового сховища, якщо квота ресурсів обмежує тимчасове сховище цього простору імен. Ви можете використовувати LimitRange для автоматичного встановлення стандартних запитів для цих ресурсів.
Назва обʼєкта ResourceQuota повинна бути дійсним піддоменом DNS.
Приклади політик, які можна створити за допомогою просторів імен та квот, такі:
- У кластері з місткістю 32 ГБ ОЗП та 16 ядрами, дозвольте команді A використовувати 20 ГБ та 10 ядер, дозвольте команді B використовувати 10 ГБ та 4 ядра, і залиште 2 ГБ та 2 ядра у резерві на майбутнє.
- Обмежте простір імен "testing" використанням 1 ядра та 1 ГБ ОЗП. Дозвольте простору імен "production" використовувати будь-який обсяг.
У випадку, коли загальна місткість кластера менше суми квот просторів імен, може виникнути конфлікт за ресурси. Це обробляється за принципом "хто перший прийшов, той і молотить" (FIFO).
Ні конфлікт, ні зміни квоти не впливають на вже створені ресурси.
Увімкнення квоти ресурсів
Підтримка квоти ресурсів є типово увімкненою для багатьох дистрибутивів Kubernetes. Вона увімкнена, коли прапорець --enable-admission-plugins=
API serverʼа має ResourceQuota
серед своїх аргументів.
Квота ресурсів застосовується в певному просторі імен, коли у цьому просторі імен є ResourceQuota.
Квота обчислювальних ресурсів
Ви можете обмежити загальну суму обчислювальних ресурсів, які можуть бути запитані в певному просторі імен.
Підтримуються наступні типи ресурсів:
Назва ресурсу | Опис |
---|---|
limits.cpu | У всіх Podʼах у незавершеному стані сума лімітів CPU не може перевищувати це значення. |
limits.memory | У всіх Podʼах у незавершеному стані сума лімітів памʼяті не може перевищувати це значення. |
requests.cpu | У всіх Podʼах у незавершеному стані сума запитів CPU не може перевищувати це значення. |
requests.memory | У всіх Podʼах у незавершеному стані сума запитів памʼяті не може перевищувати це значення. |
hugepages-<size> | У всіх Podʼах у незавершеному стані кількість запитів великих сторінок зазначеного розміру не може перевищувати це значення. |
cpu | Те саме, що і requests.cpu |
memory | Те саме, що і requests.memory |
Квота для розширених ресурсів
Крім ресурсів, згаданих вище, в релізі 1.10 було додано підтримку квоти для розширених ресурсів.
Оскільки перевищення не дозволяється для розширених ресурсів, немає сенсу вказувати як requests
, так і limits
для одного й того ж розширеного ресурсу у квоті. Таким чином, для розширених ресурсів дозволяються лише елементи квоти з префіксом requests.
наразі.
Візьмімо ресурс GPU як приклад. Якщо імʼя ресурсу — nvidia.com/gpu
, і ви хочете обмежити загальну кількість запитаних GPU в просторі імен до 4, ви можете визначити квоту так:
requests.nvidia.com/gpu: 4
Дивіться Перегляд та встановлення квот для більш детальної інформації.
Квота ресурсів зберігання
Ви можете обмежити загальну суму ресурсів зберігання, які можуть бути запитані в певному просторі імен.
Крім того, ви можете обмежити споживання ресурсів зберігання на основі повʼязаного класу зберігання.
Назва ресурсу | Опис |
---|---|
requests.storage | У всіх запитах на постійний том, сума запитів зберігання не може перевищувати це значення. |
persistentvolumeclaims | Загальна кількість PersistentVolumeClaims, які можуть існувати у просторі імен. |
<storage-class-name>.storageclass.storage.k8s.io/requests.storage | У всіх запитах на постійний том, повʼязаних з <storage-class-name> , сума запитів зберігання не може перевищувати це значення. |
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims | У всіх запитах на постійний том, повʼязаних з <storage-class-name> , загальна кількість запитів на постійні томи, які можуть існувати у просторі імен. |
Наприклад, якщо оператор хоче обмежити зберігання з класом зберігання gold
окремо від класу зберігання bronze
, оператор може визначити квоту так:
gold.storageclass.storage.k8s.io/requests.storage: 500Gi
bronze.storageclass.storage.k8s.io/requests.storage: 100Gi
У релізі 1.8, підтримка квоти для локального тимчасового сховища додана як альфа-функція:
Назва ресурсу | Опис |
---|---|
requests.ephemeral-storage | У всіх Podʼах у просторі імен, сума запитів на локальне тимчасове сховище не може перевищувати це значення. |
limits.ephemeral-storage | У всіх Podʼах у просторі імен, сума лімітів на локальне тимчасове сховище не може перевищувати це значення. |
ephemeral-storage | Те саме, що і requests.ephemeral-storage . |
Примітка:
При використанні середовища виконання контейнерів CRI, логи контейнера будуть зараховуватися до квоти тимчасового сховища. Це може призвести до неочікуваного видалення Podʼів, які вичерпали свої квоти на сховище. Дивіться Архітектура логів для деталей.Квота на кількість обʼєктів
Ви можете встановити квоту на загальну кількість одного конкретного типу ресурсів у API Kubernetes, використовуючи наступний синтаксис:
count/<resource>.<group>
для ресурсів з груп non-corecount/<resource>
для ресурсів з групи core
Нижче наведено приклад набору ресурсів, які користувачі можуть хотіти обмежити квотою на кількість обʼєктів:
count/persistentvolumeclaims
count/services
count/secrets
count/configmaps
count/replicationcontrollers
count/deployments.apps
count/replicasets.apps
count/statefulsets.apps
count/jobs.batch
count/cronjobs.batch
Якщо ви визначаєте квоту таким чином, вона застосовується до API Kubernetes, які є частиною сервера API, а також до будь-яких власних ресурсів, підтримуваних CustomResourceDefinition. Якщо ви використовуєте агрегацію API, щоб додати додаткові, власні API, які не визначені як CustomResourceDefinitions, основна панель управління Kubernetes не застосовує квоту для агрегованого API. Очікується, що розширений сервер API забезпечить виконання квот, якщо це відповідає потребам власного API. Наприклад, щоб створити квоту на власний ресурс widgets
у групі API example.com
, використовуйте count/widgets.example.com
.
При використанні такої квоти ресурсів (практично для всіх видів обʼєктів), обʼєкт враховується у квоті, якщо вид обʼєкта існує (визначений) у панелі управління. Ці типи квот корисні для захисту від вичерпання ресурсів зберігання. Наприклад, ви можете хотіти обмежити кількість Secretʼів на сервері, враховуючи їх великий розмір. Занадто багато Secretʼів у кластері може фактично завадити запуску серверів і контролерів. Ви можете встановити квоту для Job, щоб захиститися від погано налаштованого CronJob. CronJobs, які створюють занадто багато Job у просторі імен, можуть призвести до заподіяння відмови в обслуговуванні.
Існує інший синтаксис, який дозволяє встановити такий же тип квоти для певних ресурсів. Підтримуються наступні типи:
Назва ресурсу | Опис |
---|---|
configmaps | Загальна кількість ConfigMaps, які можуть існувати в просторі імен. |
persistentvolumeclaims | Загальна кількість PersistentVolumeClaims, які можуть існувати в просторі імен. |
pods | Загальна кількість Podʼів у просторі імен, що не перебувають в стані завершення роботи. Pod вважається таким, якщо .status.phase in (Failed, Succeeded) є true. |
replicationcontrollers | Загальна кількість ReplicationControllers, які можуть існувати в просторі імен. |
resourcequotas | Загальна кількість ResourceQuotas, які можуть існувати в просторі імен. |
services | Загальна кількість Services, які можуть існувати в просторі імен. |
services.loadbalancers | Загальна кількість Services типу LoadBalancer , які можуть існувати в просторі імен. |
services.nodeports | Загальна кількість NodePorts , виділених Services типу NodePort чи LoadBalancer , які можуть існувати в просторі імен. |
secrets | Загальна кількість Secrets, які можуть існувати в просторі імен. |
Наприклад, квота pods
рахує та обмежує максимальну кількість Pod
ʼів, створених у одному просторі імен, що не перебувають в стані завершення роботи. Ви можете встановити квоту pods
у просторі імен, щоб уникнути випадку, коли користувач створює багато невеликих Podʼів і вичерпує запаси IP-адрес Podʼів кластері.
Ви можете знайти більше прикладів у розділі Перегляд і налаштування квот.
Області дії квоти
Кожна квота може мати повʼязаний набір scopes
. Квота вимірюватиме використання ресурсу лише в тому випадку, якщо вона відповідає перетину перерахованих областей.
Коли до квоти додається область, вона обмежує кількість ресурсів, які вона підтримує, тими, які стосуються цієї області. Ресурси, вказані у квоті поза дозволеним набором, призводять до помилки перевірки.
Область | Опис |
---|---|
Terminating | Відповідає Podʼам, де .spec.activeDeadlineSeconds >= 0 |
NotTerminating | Відповідає Podʼам, де .spec.activeDeadlineSeconds is nil |
BestEffort | Відповідає Podʼам, які мають найкращий рівень якості обслуговування. |
NotBestEffort | Відповідає Podʼам, які не мають найкращого рівня якості обслуговування. |
PriorityClass | Відповідає Podʼам, які посилаються на вказаний клас пріоритету. |
CrossNamespacePodAffinity | Відповідає Podʼам, які мають міжпросторові (anti)affinity. |
Область BestEffort
обмежує квоту відстеження наступним ресурсом:
pods
Області Terminating
, NotTerminating
, NotBestEffort
та PriorityClass
обмежують квоту відстеження наступними ресурсами:
pods
cpu
memory
requests.cpu
requests.memory
limits.cpu
limits.memory
Зверніть увагу, що ви не можете вказати як Terminating
, так і NotTerminating
області в одній й тій же квоті, і ви також не можете вказати як BestEffort
, так і NotBestEffort
області в одній й тій же квоті.
Селектор області підтримує наступні значення у полі operator
:
In
NotIn
Exists
DoesNotExist
При використанні одного з наступних значень як scopeName
при визначенні scopeSelector
, оператор повинен бути Exists
.
Terminating
NotTerminating
BestEffort
NotBestEffort
Якщо оператором є In
або NotIn
, поле values
повинно мати щонайменше одне значення. Наприклад:
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
Якщо оператором є Exists
або DoesNotExist
, поле values
НЕ повинно бути
вказане.
Квота ресурсів за PriorityClass
Kubernetes v1.17 [stable]
Podʼи можуть бути створені з певним пріоритетом. Ви можете контролювати використання ресурсів системи для Podʼів з урахуванням їх пріоритету, використовуючи поле scopeSelector
у специфікації квоти.
Квота має збіг та використовується лише якщо scopeSelector
у специфікації квоти вибирає Pod.
Коли квота обмежена класом пріоритету за допомогою поля scopeSelector
, обʼєкт квоти обмежується відстеженням лише наступних ресурсів:
pods
cpu
memory
ephemeral-storage
limits.cpu
limits.memory
limits.ephemeral-storage
requests.cpu
requests.memory
requests.ephemeral-storage
У цьому прикладі створюється обʼєкт квоти та відповідною до нього підходить до Podʼів з певними пріоритетами. Приклад працює наступним чином:
- Podʼи в кластері мають один з трьох класів пріоритету: "низький", "середній", "високий".
- Для кожного пріоритету створюється один обʼєкт квоти.
Збережіть наступний YAML у файл quota.yml
.
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
Застосуйте YAML за допомогою kubectl create
.
kubectl create -f ./quota.yml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
Перевірте, що значення Used
квоти дорівнює 0
за допомогою kubectl describe quota
.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 1k
memory 0 200Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
Створіть Pod із пріоритетом "high". Збережіть наступний YAML у файл high-priority-pod.yml
.
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
Застосуйте його за допомогою kubectl create
.
kubectl create -f ./high-priority-pod.yml
Перевірте, що статистика "Used" для квоти пріоритету "high", pods-high
, змінилася і що для інших двох квот стан не змінився.
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 1k
memory 10Gi 200Gi
pods 1 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
Квота Pod Affinity між просторами імен
Kubernetes v1.24 [stable]
Оператори можуть використовувати область квоти CrossNamespacePodAffinity
, щоб обмежити, які простори імен можуть мати Podʼи з термінами спорідненості, які перетинають простори імен. Зокрема, вона контролює, яким Podʼам дозволено встановлювати поля namespaces
або namespaceSelector
у термінах спорідненості (Pod Affinity).
Бажано уникати використання термінів спорідненості, які перетинають простори імен, оскільки Pod з обмеженнями анти-спорідненості може заблокувати Podʼи з усіх інших просторів імен від планування в області відмов.
За допомогою цієї області оператори можуть запобігти певним просторам імен (наприклад, foo-ns
у наведеному нижче прикладі) використання Podʼів, які використовують спорідненість між просторами імен, створивши обʼєкт квоти ресурсів в цьому просторі імен з областю CrossNamespacePodAffinity
та жорстким обмеженням 0:
apiVersion: v1
kind: ResourceQuota
metadata:
name: disable-cross-namespace-affinity
namespace: foo-ns
spec:
hard:
pods: "0"
scopeSelector:
matchExpressions:
- scopeName: CrossNamespacePodAffinity
operator: Exists
Якщо оператори хочуть заборонити стандартне використання namespaces
та namespaceSelector
, і дозволити це лише для певних просторів імен, вони можуть налаштувати CrossNamespacePodAffinity
як обмежений ресурс, встановивши прапорець kube-apiserver --admission-control-config-file на шлях до наступного конфігураційного файлу:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: CrossNamespacePodAffinity
operator: Exists
За такої конфігурації Podʼи можуть використовувати namespaces
та namespaceSelector
у термінах спорідненості тільки якщо простір імен, в якому вони створені, має обʼєкт квоти ресурсів з областю CrossNamespacePodAffinity
та жорстким обмеженням, більшим або рівним кількості Podʼів, що використовують ці поля.
Запити порівняно з лімітами
При розподілі обчислювальних ресурсів кожен контейнер може вказати значення запиту та ліміту для CPU або памʼяті. Квоту можна налаштувати для обмеження будь-якого значення.
Якщо для квоти вказано значення для requests.cpu
або requests.memory
, то це вимагає, щоб кожен вхідний контейнер явно вказував запити для цих ресурсів. Якщо для квоти вказано значення для limits.cpu
або limits.memory
, то це вимагає, щоб кожен вхідний контейнер вказував явний ліміт для цих ресурсів.
Перегляд і налаштування квот
Kubectl підтримує створення, оновлення та перегляд квот:
kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
pods 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
Kubectl також підтримує квоту на кількість обʼєктів для всіх стандартних обʼєктів в просторі імен за допомогою синтаксису count/<resource>.<group>
:
kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
kubectl describe quota --namespace=myspace
Name: test
Namespace: myspace
Resource Used Hard
-------- ---- ----
count/deployments.apps 1 2
count/pods 2 3
count/replicasets.apps 1 4
count/secrets 1 4
Квоти та місткість кластера
ResourceQuotas є незалежними від місткості кластера. Вони виражені в абсолютних одиницях. Таким чином, якщо ви додаєте вузли до свого кластера, це автоматично не надає кожному простору імен можливість використовувати більше ресурсів.
Іноді бажані складніші політики, такі як:
- Пропорційне розподілення спільних ресурсів кластера серед кількох команд.
- Дозвіл кожному орендареві збільшувати використання ресурсів за потреби, але мати щедру квоту, щоб уникнути випадкового вичерпання ресурсів.
- Виявлення попиту з одного простору імен, додавання вузли та збільшення квоти.
Такі політики можна реалізувати, використовуючи ResourceQuotas
як будівельні блоки, написавши "контролер", який спостерігає за використанням квоти та налаштовує межі квоти кожного простору імен згідно з іншими сигналами.
Зверніть увагу, що квота ресурсів розподіляє загальні ресурси кластера, але не створює обмежень щодо вузлів: Podʼи з кількох просторів імен можуть працювати на одному вузлі.
Типове обмеження споживання Priority Class
Може бути бажаним, щоб Podʼи з певного пріоритету, наприклад, "cluster-services", дозволялися в просторі імен, лише якщо існує відповідний обʼєкт квоти.
За допомогою цього механізму оператори можуть обмежувати використання певних високопріоритетних класів до обмеженої кількості просторів імен, і не кожний простір імен зможе стандартно споживати ці класи пріоритету.
Для цього потрібно використовувати прапорець --admission-control-config-file
kube-apiserver
для передачі шляху до наступного конфігураційного файлу:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: PriorityClass
operator: In
values: ["cluster-services"]
Потім створіть обʼєкт квоти ресурсів у просторі імен kube-system
:
apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-cluster-services
spec:
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["cluster-services"]
kubectl apply -f https://k8s.io/examples/policy/priority-class-resourcequota.yaml -n kube-system
resourcequota/pods-cluster-services created
У цьому випадку створення Podʼа буде дозволено, якщо:
- Параметр
priorityClassName
Podʼа не вказано. - Параметр
priorityClassName
Podʼа вказано на значення, відмінне відcluster-services
. - Параметр
priorityClassName
Podʼа встановлено наcluster-services
, він має бути створений в просторі іменkube-system
і пройти перевірку обмеження ресурсів.
Запит на створення Podʼа буде відхилено, якщо його priorityClassName
встановлено на cluster-services
і він має бути створений в просторі імен, відмінному від kube-system
.
Що далі
- Дивіться документ з проєктування ResourceQuota для отримання додаткової інформації.
- Перегляньте детальний приклад використання квоти ресурсів.
- Прочитайте документ з проєктування підтримки квот для класу пріоритету.
- Дивіться LimitedResources