Квоти ресурсів

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

Квоти ресурсів є інструментом для адміністраторів для розвʼязання цієї проблеми.

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

Квоти ресурсів працюють наступним чином:

  • Різні команди працюють у різних просторах імен. Це може бути забезпечено з використанням RBAC.

  • Адміністратор створює одну квоту ресурсів для кожного простору імен.

  • Користувачі створюють ресурси (Podʼи, Serviceʼи тощо) у просторі імен, і система квот відстежує використання, щоб забезпечити, що воно не перевищує жорсткі обмеження ресурсів, визначені в ResourceQuota.

  • Якщо створення або оновлення ресурсу порушує обмеження квоти, запит буде відхилено з HTTP кодом стану 403 FORBIDDEN з повідомленням, яке пояснює обмеження, що було б порушено.

  • Якщо квота включена в простір імен для обчислювальних ресурсів, таких як cpu та memory, користувачі повинні вказати запити або ліміти для цих значень; інакше, система квот може відхилити створення Podʼа. Підказка: Використовуйте контролер допуску LimitRanger, щоб надати для Podʼів, які не мають вимог до обчислювальних ресурсів, стандартні обсяги ресурсів.

    Дивіться посібник для прикладу того, як уникнути цієї проблеми.

Назва обʼєкта 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>, загальна кількість запитів на постійні томи, які можуть існувати у просторі імен.

Наприклад ви хочете обмежити зберігання з StorageClass gold окремо від StorageClass 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.

Квота на кількість обʼєктів

Ви можете встановити квоту на загальну кількість одного конкретного типу ресурсів у API Kubernetes, використовуючи наступний синтаксис:

  • count/<resource>.<group> для ресурсів з груп non-core
  • count/<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ʼа буде дозволено, якщо:

  1. Параметр priorityClassName Podʼа не вказано.
  2. Параметр priorityClassName Podʼа вказано на значення, відмінне від cluster-services.
  3. Параметр priorityClassName Podʼа встановлено на cluster-services, він має бути створений в просторі імен kube-system і пройти перевірку обмеження ресурсів.

Запит на створення Podʼа буде відхилено, якщо його priorityClassName встановлено на cluster-services і він має бути створений в просторі імен, відмінному від kube-system.

Що далі

Змінено December 17, 2024 at 11:53 AM PST: Sync upstream after v1.32 release (d7b08bbf8e)