В этом посте хотелось бы поделиться заметками относительно использования Probe в кубернетес. И предоставить понимание того, на чем строиться ресурс менеджмент - реквесты и лимиты, QoS-классы.

Probes

В kubernetes реализован механизм проверки доступности нашего приложения. Существую 3 типа проверок:

  • Liveness Probe - выполняет контроль за состоянием приложения в процессе его жизни. Liveness проверки выполняются постоянно. В случаи, если выполнение liveness пробы завершилось с результатом - failed, то kubernetes перезапустил приложение (под).
  • Readiness Probe - выполняют проверки за состоянием контейнеров, для того что бы понять готов ли под принимать клиентский трафик. В случаи неудачного выполнения readiness проды, приложение убирается из балансировки. Так же как и с liveness, readiness пробы выполняются постоянно, с некой переодичностью.
  • Startup Probe - с помошью startup пробы мы можем проверить, что наше приложение действительно проинициализировалось и готово принимать принимать запросы. Startup проба выполняется только до последнего успешного выполнения, после чего разблокирует выполнение других проб (liveness и readiness). Такой механизм может быть полезен, когда наш контейнер долго запускается, и чтобы избежать преждевременного убийства контейнера другими пробами они блокируются. Теперь напишем деплоймент, и будем разбираться с настройками проб.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-with-probes
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels: 
        app: my-app
    spec:
      containers:
      - image: nginx:1.12
        name: nginx-web
        ports:
        - containerPort: 80
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 80
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 80
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
          initialDelaySeconds: 10
        startupProbe: 
          httpGet:
            path: /
            port: 80
          failureThreshold: 30
          periodSeconds: 10

Пробы указываются в контексте - containers. И могу быть сконфигурированы полями:

  • failureThreshold - в этом поле указывается количество проверок. Например в нашем деплойменте указано значение равное 3-м. Это означает, что если проба 3 раза выполняется с результатом - failed, то контейнер будет перезащен в случаи с livenessProbe пробы и будет помечан как Unready в случаи c readynessProbe.
  • httpGet - это тип нашей проверки, то есть в нашем случаи мы будем отправлять http-запрос контейнеру. По мимо - httpGet, есть возможность выполнять команды внутри контейнера через поле - exec. Также есть проверка - tcpSocket, проверка на доступность tcp-порта. В нашем случаи мы проверяем обычным http-запросом.
    • path - указывается локейшейн, в нашем случае это корневой
    • port - порт, на который будем стучаться.
  • periodSeconds - переодичность проверки, в данном случаи мы хотим проверять наше приложение каждые 10 секунд.
  • successThreshold - это поле задает количество успешно выполненых проб после неуспешной. Например в нашем случаи при заданном количестве failureThreshold: 3, если хоть одна проверка из этих трех завершиться успешно, то счетчик failureThreshold обнуляется.
  • timeoutSeconds - здесь указывается количество секунд для ожидания пробы.
  • initialDelaySeconds - задается колличество секунд для отсрочки начала выполнения пробы. В нашем примере, мы задаем 10 секунд, что означает подождать 10 секунд после запуска прилы, прежде чем начать запускать пробы.

Запустим деплоймент, и посмотрим информацию по деплойменту:

$ kubectl apply -f deployment-probes.yml
$ kubectl describe pod deployment-with-probes-8556d554-2prkw | grep  http-get
----
    Liveness:       http-get http://:80/ delay=10s timeout=1s period=10s #success=1 #failure=3
    Readiness:      http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Startup:        http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=30

Limits & Requests

Когда мы запускаем наше приложение в kubernetes, нам крайне важно понимать, сколько ресурсов оно будет потреблять в процессе своей работы. У нас есть два параметра, которые относятся к resource managment в kubernetes:

  • Limits - это верхняя граница по ресурсам, которые может использовать под. Например, если у нас выставлен лимит на память в 256мб, то приложение не сможет потреблять вышего этого значения. В случаи выхода за отведенный лимит, OOM Killer прибьет прилу.
  • Requests - здесь указывается количество ресурсов, которые необходимы для работы или запуска нашего приложения, эти ресурсы будут зарезервированы за подом.
    Наш деплоймент из прошлой главы дополним новыми полями. Лимиты и Реквесты указывается в контексте поля нашего контейнера.
resources:
  requests:
    cpu: 50m
	  memory: 100Mi
	limits:
	  cpu: 100m
	  memory: 100Mi

В полях requests и limits, мы указываем:

  • cpu: 50m - здесь мы указываем значение в milicpu (milicores). В терминалогии kubernetes - 1 ядро (1 виртуальное ядро) равно 1000 milicpu (milicores).
  • memory: 100Mi - тут все просто, указывается значение в 100 мегабайт. Соотношение milicores к сore.
1000m (milicores) = 1 core = 1 vCPU = 1 AWS vCPU = 1 GCP Core

Применяем обновленный манифест, и смотрим подробную информация по подам.

$ kubectl describe pod
---
Containers:
  nginx-web:
    Container ID:   docker://0dae14de4d43f2717ea7a40a2ca38f8a5f6e77bf3ae329df7e8f85600c840677
    Image:          nginx:1.12
    Image ID:       docker-pullable://nginx@sha256:72daaf46f11cc753c4eab981cbf869919bd1fee3d2170a2adeac12400f494728
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sun, 04 Dec 2022 00:39:19 +0600
    Ready:          True
    Restart Count:  0
    Limits:
      cpu:     100m
      memory:  100Mi
    Requests:
      cpu:        50m
      memory:     100Mi
    Liveness:     http-get http://:80/ delay=10s timeout=1s period=10s #success=1 #failure=3
    Readiness:    http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=3
    Startup:      http-get http://:80/ delay=0s timeout=1s period=10s #success=1 #failure=30
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-c2rxq (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  kube-api-access-c2rxq:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   Burstable

Стоит отметить еще важную штуку в kubernetes, это QoS Class. Кластер использует QoS - классы для принятия решения о shedulling-e или исключении подов. Есть три класса:

  • BestEffort - этот класс будет назначен тем подам, у которых не указаны ни реквесты, ни лимиты. Для кубернетес эти поды не значительные или менее важные, значит их можно прибить и запустить в другом месте.
  • Burstable - класс, который назначается подам с выставленными лимитами и реквестами по разным соотношениям. (Например, как в нашем примере). Поды с этим классом начнуть переезжать, или вырубаться во вторую очередь. То есть у подов с этим классом, приоритет немного выше, чем у подов класса - BestEffort.
  • Guaranteed - этот класс назначается, когда выставленные cpu memory для limits и requests. И когда значения cpu/memory лимитов равное cpu/memory реквестов. Поды с этим классом, кубернетес будет держать до последнего.

Полезные ссылки

Пока разбирался по этим темам, нашем много информации и решил поделиться: