Kubernetes: Evicted поды и Quality of Service для подов

Автор: | 03/10/2020
 

Имеется Kubernetes кластер, работает на AWS Elastic Kubernetes Service.

В кластере запущено приложение, которое в целом работает без проблем, но система мониторинга периодически сообщает, что:

Проверяем поды:

[simterm]

$ kk -n eks-prod-1-web-projectname-admin-backend-ns get pod
NAME                                                   READY   STATUS    RESTARTS   AGE
bttrm-web-projectname-admin-backend-64648597fc-9j29n   1/1     Running   0          43m
bttrm-web-projectname-admin-backend-64648597fc-kptjj   1/1     Running   0          43m
bttrm-web-projectname-admin-backend-7f4b5bdb4c-wlbjf   0/1     Evicted   0          12d
bttrm-web-projectname-admin-backend-8478d778f9-5mrnc   0/1     Evicted   0          15d

[/simterm]

Два пода оказались в Evicted статусе – начинаем разбираться.

Kubernetes requests и limits

В Kubernetes мы имеем возможность ограничить используемые контейнерами ресурсы двумя способами – requests и limits:

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

Тут:

  • requests: используется Kubernetes Scheduler при выборе рабочей ноды, на которой будет запущен под – тут задаётся минимальное значение памяти и/или ЦПУ, которые должны быть доступны на ноде для запуска пода
  • limits: такой себе “hard-limit” – максимальное значение ресурсов, которые доступны контейнеру для использования

Kubernetes pods QoS classes

Документация – Configure Quality of Service for Pods.

Поды в Kubernetes могут попадать под один из трёх классов Quality of Service (QoS):

  • Guaranteed: поды, для которых указаны реквесты и лимиты для всех контейнеров, и для всех они одинаковы
  • Burstable: не гарантированные поды, для которых задан реквест как минимум на CPU или память для одного из контейнеров
  • Best effort: поды без реквестов и лимитов вообще

Проверить QoS класс пода можно через describe pod -o yaml:

[simterm]

$ kubectl get pod appname-54545944b4-h8gmv -o yaml
...
    resources:
     requests:
       cpu: 100m
...
  qosClass: Burstable
...

[/simterm]

Тут задан requests только на CPU, и под попадает под QoS class Burstable.

А теперь посмотрим – как QoS класс влияет на жизнь подов.

Node tolerations

Когда WorkerNode в кластере исчерпытывает доступные ей ресурсы – память, ЦПУ, диск и т.д. – scheduler кластера во-первых перестаёт добавлять новые поды на эту ноду.

Кроме того, Kubernetes к такой ноде добавляет аннотации, указывающие на проблему с нодой, например – node.kubernetes.io/memory-pressure.

См. полный список в Taint based Evictions.

В таком случае, kubelet на этой ноде начинает убивать запущенные контейнеры, а их поды отмечает как Failed.

Например, при заполнении диска – kubelet будет удалять в первую очередь неиспользуемые поды и их контейнеры, затем – удалять образы с дисков.

Если этого недостаточно – начинает “выселять” (собственно – Evict) пользовательские поды в следующем порядке:

  • Best Effort – поды без реквестов и лимитов вообще
  • Burstable – поды, использующие больше ресурсов, чем задано в их реквестах
  • Burstable – поды, использующие меньше ресурсов, чем задано в их реквестах

Guaranteed поды в целом не должны затрагиваться, но в случае, если системе на ноде потребуется больше ресурсов, чем доступно – то kubelet начнёт вытеснять с этой ноды даже те поды, которые попадают под Guaranteed QoS класс.

Увидеть, почему именно под был вынеснен с ноды можно в событиях этого пода.

Например, последние поды у нас сейчас:

[simterm]

$ kk -n eks-prod-1-web-projectname-admin-backend-ns get pod
NAME                                                   READY   STATUS    RESTARTS   AGE
...
bttrm-web-projectname-admin-backend-7f4b5bdb4c-wlbjf   0/1     Evicted   0          14d
bttrm-web-projectname-admin-backend-8478d778f9-5mrnc   0/1     Evicted   0          17d

[/simterm]

И события пода:

[simterm]

$ kk -n eks-prod-1-web-projectname-admin-backend-ns get pod bttrm-web-projectname-admin-backend-7f4b5bdb4c-wlbjf -o yaml
...
status:
  message: 'The node was low on resource: memory. Container bttrm-web-projectname-admin-backend
    was using 1014836Ki, which exceeds its request of 300Mi. '
  phase: Failed
  reason: Evicted

[/simterm]

Тут Kubernetes нам явно сообщает, что “Container was using 1014836Ki, which exceeds its request of 300Mi“.

Тут Ki == kibibyte (1024 байта, 8192 бита), а Mi – mebibyte, т.е. 1024 kibibytes, или 1048576 байт.

Проверяем – переведём 1014836Ki в мегабайты:

[simterm]

$ echo 1014836/1024 | bc
991

[/simterm]

Почти гиг памяти.

И ещё раз посмотрим на ресурсы, заданные в Deployment этого пода:

[simterm]

$ kk -n eks-prod-1-web-projectname-admin-backend-ns get deploy bttrm-web-projectname-admin-backend -o yaml
...
        resources:
          limits:
            memory: 3Gi
          requests:
            cpu: 100m
            memory: 300Mi
...

[/simterm]

Т.к. в лимитах во-первых не задан лимит на ЦПУ, во-вторых – лимиты и реквесты не одинаковы – то он попадает под Burstable QoS класс, плюс на этой ноде кроме подов этого деплоймента других подов не было – и Kubernetes его прибил.

Посмотрим историю статусов пода (см. Kubernetes: мониторинг кластера с Prometheus Operator):

Жил-был под на рабочей ноде 10.4.44.215 в статусе Running, а потом бац – и в 19:40 убился.

Посмотрим на состояние ноды 10.4.44.215 в это время:

Нода исчерпала доступную память (AWS EC2 t3.medium, 4GB RAM), и kubelet начал вытеснять поды.

И глянем ресурсы, которые под потреблял в этом время:

Собственно, видим, что на под прилетело немного входящего трафика – и он активно начал отжирать память.

Память на ноде закончилась – и kubelet этот под прибил.

Дальше уже вопрос к разработчикам – то ли это expected, и надо переселять этот проект на рабочие ноды, у которых больше доступной памяти, и увеличивать подам реквесты и лимиты – либо у них где-то memory leak, и тогда они уже сами будут это фиксить.

Ссылки по теме