Что происходит с запросами / ограничениями памяти, указанными в задании (контейнере) K8s, когда задание завершено? - PullRequest
0 голосов
/ 06 марта 2020

У меня кластер k8s с несколькими средами ( EKS ), и я пытаюсь установить точные значения для ResourceQuotas.

Одна интересная вещь, которую я заметил, заключается в том, что указанный запрос / лимит для CPU / памяти остается "занят" в кластере k8s, когда задание выполнено успешно и эффективно, модуль pod освобождает ресурсы процессора / памяти что он использует.

Поскольку я ожидаю, что в среде будет выполнено много заданий, это вызвало для меня проблему. Конечно, я добавил поддержку запуска cronjob очистки для успешно выполненных заданий, но это только одна часть решения.

Мне известно о функции TTL на k8s : https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#ttl -механизм-для-выполненных работ , который все еще находится в альфа-состоянии и как таковой недоступен в кластере EKS k8s.

Я бы ожидал, что оба запроса / ограничения указаны в что указанные c pod (контейнер / контейнеры) также «освобождены», но, глядя на показатели k8s в Grafana, я вижу, что это не так.

Это пример (зеленая линия обозначает текущий ресурс) использование, желтые метки для запроса ресурсов, а синие метки для ограничения ресурсов): enter image description here

Мой вопрос:

  • Это ожидаемое поведение?
  • Если да, то по каким техническим причинам запрос / лимиты не освобождаются также после завершения выполнения задания (модуля)?

Ответы [ 2 ]

2 голосов
/ 07 марта 2020

Я выполнил «нагрузочный» тест в своей среде, чтобы проверить, действительно ли запросы / ограничения, оставленные назначенными для завершенного задания (модуля), действительно повлияют на установленную мной ResourceQuota.

Вот так выглядит моя ResourceQuota:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: mem-cpu-quota
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 2Gi
    limits.cpu: "2"
    limits.memory: 3Gi

Это запрос / лимит для процессора / памяти, который существует в каждом задании k8s (если быть точным для контейнера, запущенного в модуле Pod, который ускоряется заданием):

resources:
  limits:
    cpu: 250m
    memory: 250Mi
  requests:
    cpu: 100m
    memory: 100Mi

Результаты тестирования:

  • Количество выполняемых заданий: 66
  • Ожидаемая сумма запросов ЦП (если предположение из вопроса верное) ~ = 6,6 м
  • Ожидаемая сумма запросов памяти (если предположение из вопроса верное) ~ = 6,6 млн.
  • Ожидаемая сумма ограничений ЦП (если предположение из вопроса верное) ~ = 16,5
  • Ожидаемая сумма пределов памяти (если предположение из вопроса верное ) ~ = 16,5

Я создал графики Grafana, которые показывают следующее:

Загрузка ЦП / запросы / ограничения для заданий в одном пространстве имен

sum(rate(container_cpu_usage_seconds_total{namespace="${namespace}", container="myjob"}[5m]))
sum(kube_pod_container_resource_requests_cpu_cores{namespace="${namespace}", container="myjob"})
sum(kube_pod_container_resource_limits_cpu_cores{namespace="${namespace}", container="myjob"})

Использование памяти / запросы / ограничения для заданий в одном пространстве имен

sum(rate(container_memory_usage_bytes{namespace="${namespace}", container="myjob"}[5m]))
sum(kube_pod_container_resource_requests_memory_bytes{namespace="${namespace}", container="myjob"})
sum(kube_pod_container_resource_limits_memory_bytes{namespace="${namespace}", container="myjob"})

Вот как выглядят графики: enter image description here

Согласно этому графику, запросы / лимиты накапливаются и go значительно превышают пороги ResourceQuota. Тем не менее, я все еще могу запускать новые задания без проблем.

В этот момент я начал сомневаться в том, какие метрики отображаются, и решил проверить другую часть метрик. Чтобы указать c, я использовал следующий набор метрик:

ЦП:

sum (rate(container_cpu_usage_seconds_total{namespace="$namespace"}[1m]))
kube_resourcequota{namespace="$namespace", resource="limits.cpu", type="hard"}
kube_resourcequota{namespace="$namespace", resource="requests.cpu", type="hard"}
kube_resourcequota{namespace="$namespace", resource="limits.cpu", type="used"}
kube_resourcequota{namespace="$namespace", resource="requests.cpu", type="used"}

Память:

sum (container_memory_usage_bytes{image!="",name=~"^k8s_.*", namespace="$namespace"})
kube_resourcequota{namespace="$namespace", resource="limits.memory", type="hard"}
kube_resourcequota{namespace="$namespace", resource="requests.memory", type="hard"}
kube_resourcequota{namespace="$namespace", resource="limits.memory", type="used"}
kube_resourcequota{namespace="$namespace", resource="requests.memory", type="used"}

Вот как выглядит график: enter image description here


Вывод:

На этом скриншоте это Ясно, что после завершения нагрузочного теста и задания go в завершенное состояние, хотя количество модулей все еще около (с ГОТОВНОСТЬЮ: 0/1 и СОСТОЯНИЕМ: Завершено) , запрос / ограничения ЦП / памяти освобожден и больше не представляет ограничение, которое необходимо рассчитать в порог ResourceQuota. Это можно увидеть, наблюдая следующие данные на графике:

CPU allocated requests
CPU allocated limits
Memory allocated requests
Memory allocated limits

, все из которых увеличиваются в момент времени, когда происходит нагрузка на систему и создаются новые задания, но сразу же возвращается в предыдущее состояние по мере выполнения заданий (даже если они не удалены из среды)

Другими словами, использование ресурсов / пределы / запросы для процессора / памяти учитываются только в то время, когда задание (и его соответствующий модуль) находится в состоянии РАБОТА

0 голосов
/ 07 марта 2020

Если вы сделаете kubectl get pod, вы увидите, что модуль, созданный заданием, все еще существует в списке, например:

NAME                                                            READY   STATUS      RESTARTS   AGE
cert-generator-11b35c51b71ea3086396a780dbf20b5cd695b25d-wvb7t   0/1     Completed   0          57d

Таким образом, любые запросы / ограничения на ресурсы по-прежнему используются порт назначения Чтобы освободить ресурс, вы можете вручную удалить модуль. Он будет воссоздан при следующем запуске задания.

Вы также можете настроить автоматическое удаление задания (и, следовательно, модуля) из истории при успехе и / или неудаче с помощью .spec.ttlSecondsAfterFinished на работе. Но вы бы потеряли способ узнать, было ли задание успешным или нет.

Или, если ваше задание фактически создано CronJob, вы можете настроить задание (и, следовательно, модуль) на автоматическое удаление. .spec.successfulJobsHistoryLimit и .spec.failedJobsHistoryLimit на CronJob.

...