Войти в платформу

Алерты Kubernetes: минимальный набор правил с первого дня

Алерты Kubernetes легко превратить в шум: готовые наборы правил приносят сотню условий, и через неделю канал с уведомлениями никто не читает. Для первого дня хватит десятка правил, каждое из которых означает «нужно что-то сделать». Ниже — такой набор на метриках kube-state-metrics и kubelet, с условиями и длительностями.

Узлы: NotReady, нехватка диска и памяти

Главное правило про узлы: kube_node_status_condition{condition="Ready",status="true"} == 0 дольше 5 минут, важность critical. Условие написано через status="true" не случайно. У условия Ready три состояния: true, false и unknown. Unknown появляется, когда кубелет перестал отчитываться, то есть узел пропал целиком, и проверка status="false" == 1 такой узел пропустит.

Рядом — два предупреждения: DiskPressure и MemoryPressure в состоянии true дольше 5 минут. Это поздний сигнал: кубелет выставляет давление, когда свободного места или памяти меньше порогов вытеснения, а по умолчанию это memory.available меньше 100Mi, nodefs.available меньше 10% и imagefs.available меньше 15% (подробно — в документации о вытеснении при нехватке ресурсов узла). Поэтому добавьте обычное правило на файловую систему узла по node_filesystem_avail_bytes с порогом занятости 85%: оно сработает раньше, чем начнётся вытеснение.

И одно правило не на значение, а на наличие данных. Если кластер целиком перестал присылать метрики, все правила выше молчат: им не с чем сравнивать. Мы подробно разбирали эту ловушку в статье о том, почему алерт молчит, когда база упала. Для кластера нужен отдельный сигнал жизни: heartbeat раз в минуту и алерт, если его нет 5 минут.

Поды: CrashLoopBackOff, Pending и нехватка реплик

Самое частое правило — на рестарты: increase(kube_pod_container_status_restarts_total[15m]) больше порога. Оно ловит начало аварии, но у него есть слепое пятно. Кубелет перезапускает упавший контейнер с растущей задержкой 10, 20, 40 секунд и так далее, до потолка в 5 минут, а после 10 минут нормальной работы сбрасывает задержку (это описано в жизненном цикле пода). Первые пять рестартов укладываются примерно в 5 минут, а дальше устоявшаяся петля даёт не больше трёх рестартов за 15 минут. Правило с порогом выше трёх в какой-то момент снимается, хотя под так и не поднялся.

Поэтому второе правило — на саму причину ожидания: max_over_time(kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"}[5m]) >= 1 дольше 15 минут. Обёртка max_over_time нужна потому, что между попытками контейнер на секунды переходит в running, ряд с причиной ожидания пропадает, и без неё таймер длительности сбрасывался бы. Тем же способом ловятся ImagePullBackOff и ErrImagePull — под с неверным тегом образа.

Pending — отдельная история. В документации Kubernetes фаза Pending включает и ожидание планирования, и скачивание образов, поэтому короткий Pending — норма. Правило: kube_pod_status_phase{phase="Pending"} == 1 дольше 15 минут. Причину покажет второе правило — kube_pod_status_unschedulable == 1: планировщик не нашёл узел из-за запросов ресурсов, taints или affinity.

Последнее в этом блоке — нехватка реплик: kube_deployment_status_replicas_available меньше kube_deployment_spec_replicas дольше 10 минут. Для StatefulSet то же условие строится на kube_statefulset_status_replicas_ready и kube_statefulset_replicas, для DaemonSet — kube_daemonset_status_number_unavailable больше нуля. Длительность в 10 минут переживёт обычный rolling update. Почему для кластера важно, что собирать, а что отсечь, мы разбирали на странице про мониторинг Kubernetes.

OOMKilled, PVC и сертификаты: что ломается тихо

OOMKilled виден в kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}. Ловушка в слове last: метрика описывает последнее завершение и держит значение 1, пока контейнер не завершится по другой причине. Правило на неё одну будет гореть сутками после единственного OOM. Рабочий вариант — связать её с рестартами: был рестарт за последние 15 минут, и последняя причина завершения — OOMKilled. Предупреждение заранее: container_memory_working_set_bytes дольше 15 минут выше 90% от kube_pod_container_resource_limits{resource="memory"}.

Заполнение томов показывает кубелет: kubelet_volume_stats_available_bytes, делённое на kubelet_volume_stats_capacity_bytes, меньше 15% — warning, меньше 5% — critical. Для томов, которые растут равномерно, добавьте прогноз: predict_linear по свободному месту за 6 часов уходит ниже нуля в ближайшие сутки. Не все драйверы хранилища отдают эту статистику, поэтому проверьте, что ряды вообще есть для ваших PVC. Ещё одно правило — на PVC, который не привязался: kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1 дольше 15 минут.

Сертификаты истекают без предупреждений, а потом отказывает сразу всё. Клиентские сертификаты, которые выпускает kubeadm, действуют один год, и kubeadm обновляет их при каждом обновлении кластера (раздел о сертификатах kubeadm). Кластер, который год не обновляли, однажды перестанет пускать kubectl и компоненты плоскости управления. Минимум — команда kubeadm certs check-expiration в регламенте. Если сертификаты выпускает cert-manager, алерт строится на certmanager_certificate_expiration_timestamp_seconds минус time() меньше 14 дней. Сертификат на ingress стоит проверять ещё и снаружи, HTTP-запросом к сайту: так видно то, что видит пользователь.

Что проверить у себя

— Ловит ли правило NotReady состояние unknown, а не только false? Выключите кубелет на тестовом узле и проверьте.

— Есть ли алерт на исчезновение данных кластера целиком, а не только на значения метрик?

— Срабатывает ли алерт на рестарты на поде, который падает уже час? Запустите контейнер с неверной командой и подождите 30 минут.

— Не горит ли OOMKilled сутками после единственного случая?

— Есть ли правило на заполнение PVC и приходят ли ряды kubelet_volume_stats для ваших томов?

— Когда истекают сертификаты кластера и сколько дней осталось до ближайшего?

— Сколько алертов пришло за прошлую неделю и на сколько из них кто-то отреагировал?

Сколько правил нужно на старте?

Около десятка: NotReady, давление на узле, место на узле, сигнал жизни кластера, CrashLoopBackOff, долгий Pending, нехватка реплик, OOMKilled, заполнение PVC и срок сертификатов. Перцентили apiserver, etcd и очередей контроллеров на старте не нужны: это диагностика, а не повод будить дежурного. Новое правило добавляйте после разбора инцидента, который нынешние правила пропустили.

Что делать с алертами во время обновления кластера?

При drain узлы помечаются как неназначаемые, поды переезжают и успевают побыть в Pending, реплик временно не хватает. Длительности в 10–15 минут закрывают большую часть таких всплесков. Для долгих работ ставьте тишину на конкретные алерты на время окна, а не выключайте уведомления целиком: тогда настоящая авария во время работ не потеряется.

Как это сделано в Voltir

Кластер подключается одним манифестом (что в нём устанавливается), и сразу работают правила K8sClusterDown, K8sNodeNotReady, K8sNodeDiskPressure, K8sNodeMemoryPressure, K8sPodCrashLooping и K8sDeploymentDegraded; пороги и длительности правятся в кабинете.

Метрики kube-state-metrics и кубелета уже собираются, поэтому правила на CrashLoopBackOff, OOMKilled, Pending и заполнение PVC добавляются как свои правила на PromQL.

Интерфейс, дашборды и алерты можно посмотреть в живом демо.

← Все новости