Урок по треку Docker и Kubernetes 8 мин

Probes, requests и limits за 8 минут

liveness, readiness, startup, requests и limits, QoS-классы, троттлинг CPU и OOMKilled.

Две настройки отличают «работает в кластере» от «работает надёжно»: проверки здоровья (probes) и ресурсы (requests и limits). Ошибки в них дают самые частые продовые инциденты: каскадные рестарты, OOMKilled и необъяснимые тормоза.

Три вида probes

ProbeВопросЕсли не прошла
startupприложение уже запустилось?пока не прошла, остальные probes не выполняются; при провале контейнер перезапускается
livenessпроцесс жив, а не завис?kubelet перезапускает контейнер
readinessготов принимать трафик?под убирают из эндпоинтов Service, перезапуска нет

Типы проверок: httpGet (код 200-399 считается успехом), tcpSocket, exec (команда с кодом 0), grpc.

startupProbe:
  httpGet: { path: /healthz, port: 8080 }
  periodSeconds: 5
  failureThreshold: 30       # до 150 секунд на старт
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  periodSeconds: 10
  failureThreshold: 3
readinessProbe:
  httpGet: { path: /ready, port: 8080 }
  periodSeconds: 5

Параметры: initialDelaySeconds, periodSeconds, timeoutSeconds (по умолчанию 1 секунда), failureThreshold, successThreshold.

Правила хороших probes

  • Liveness проверяет только сам процесс. Никаких запросов в базу или к соседним сервисам. Если база легла, liveness всех подов упадёт, и kubelet начнёт перезапускать здоровые поды, превращая проблему базы в каскадный отказ.
  • Readiness может учитывать зависимости, без которых под бесполезен, и прогрев (кеши, соединения). Под временно выйдет из балансировки и вернётся сам.
  • Медленный старт (JVM, миграции, загрузка моделей) закрывают startupProbe, а не огромным initialDelaySeconds у liveness.
  • Таймаут 1 секунда под нагрузкой легко превышается: GC-пауза или перегруженный event loop, и здоровый под убит. Таймауты и пороги выбирают с запасом.
  • Liveness не обязательна. Если процесс при зависании падает сам, её можно не ставить, а неудачная liveness опаснее отсутствующей.

Requests и limits

resources:
  requests:
    cpu: 250m        # 0.25 ядра
    memory: 256Mi
  limits:
    memory: 256Mi
  • requests это то, что планировщик резервирует на узле. Под попадёт только на узел, где сумма requests помещается в доступные ресурсы. Requests не ограничивают реальное потребление.
  • limits это жёсткий потолок.

CPU и память ведут себя по-разному:

  • CPU сжимаемый. При превышении лимита процесс не убивают, а троттлят: CFS-квота не даёт работать больше, чем limit за период (100 мс). Симптомы: рост задержек при невысокой средней загрузке. Видно по метрике container_cpu_cfs_throttled_periods_total.
  • Память несжимаемая. При превышении лимита ядро убивает процесс в cgroup контейнера: статус OOMKilled, код выхода 137.

Единицы: CPU в ядрах или милли-ядрах (500m), память в Mi, Gi (двоичные) или M, G (десятичные). 100M и 100Mi это разные числа.

QoS-классы

Kubernetes присваивает поду класс по ресурсам:

  • Guaranteed: у каждого контейнера requests = limits и для CPU, и для памяти.
  • Burstable: requests заданы хотя бы частично, но не равны limits.
  • BestEffort: ничего не задано.

При нехватке памяти на узле kubelet вытесняет (evict) поды: сначала те, что больше всего превышают свои requests, в первую очередь BestEffort, затем Burstable. Guaranteed трогают в последнюю очередь.

Практические рекомендации

  • Память: requests = limits. Тогда под не попадёт на узел, где ему не хватит памяти, и поведение предсказуемо.
  • CPU: requests по реальному потреблению, а лимит CPU многие команды не ставят вовсе или ставят с запасом: троттлинг вредит задержкам, а свободное CPU узла простаивает. Это предмет споров, но объяснить свою позицию нужно уметь.
  • Значения подбирают по метрикам (p95 потребления) и пересматривают. В помощь VPA в режиме рекомендаций.
  • В языках с рантаймом выставляй лимит кучи меньше лимита контейнера: JVM -XX:MaxRAMPercentage, Node.js --max-old-space-size, Go GOMEMLIMIT.
  • Многие рантаймы определяют число ядер по узлу, а не по лимиту: Go до версии 1.25 (GOMAXPROCS), пулы потоков. Слишком много потоков при маленьком лимите CPU усиливает троттлинг.

LimitRange и ResourceQuota

  • LimitRange задаёт значения по умолчанию и минимум/максимум для контейнеров в namespace. Спасает от подов без ресурсов.
  • ResourceQuota ограничивает суммарные requests, limits и число объектов в namespace.

Частые ошибки

  • Liveness проверяет базу и вызывает каскадные рестарты.
  • Нет readiness: трафик идёт на неготовые поды при старте и деплое.
  • initialDelaySeconds: 120 вместо startupProbe.
  • Нет requests: планировщик набивает узел, поды BestEffort вытесняются первыми.
  • Лимит памяти меньше реального пика, поды в цикле OOMKilled.
  • CPU-лимит слишком маленький, задержки растут из-за троттлинга.

Что спросят на собесе

  • Чем liveness отличается от readiness, зачем startupProbe.
  • Почему liveness не должна проверять базу.
  • Что такое requests и limits, как ведут себя CPU и память при превышении.
  • Какие бывают QoS-классы и кого вытесняют первым.
  • Почему сервис тормозит при CPU 30% и что такое троттлинг.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.