Preq: проактивная диагностика Kubernetes-кластера

Обложка статьи о поиске и исправлении кодов завершения и неправильных конфигураций Kubernetes

Kubernetes — мощная платформа, однако отлаживать проблемы в работающем кластере бывает очень непросто. В сложном окружении критические предупреждающие сигналы нередко тонут в тысячах строк логов и событий. А что если научиться выявлять такие проблемы с надёжностью до того, как они роняют приложения?

Preq (произносится «прик») — инструмент с открытым исходным кодом, реализующий проактивный подход к диагностике Kubernetes. Это детектор проблем надёжности, который проверяет логи, события и конфигурации кластера по управляемому сообществом каталогу шаблонов сбоев (failure patterns) [1]. С помощью Preq можно следить за кластером и обнаруживать неправильные конфигурации, антипаттерны или баги заблаговременно — вместо того чтобы натыкаться на них в два часа ночи во время инцидента [1].

preq распространяется как плагин kubectl, поэтому его удобно устанавливать через менеджер плагинов Kubernetes Krew. Сначала убедитесь, что Krew настроен (если нет — установите его по инструкции на сайте).

Через несколько секунд плагин готов к работе [1]. Дополнительная настройка не нужна. Preq поставляется с последними пакетами правил CRE (common reliability enumeration — общая нумерация проблем надёжности) и автоматически обновляет их, так что вы всегда проверяете кластер по актуальному набору.

После установки Preq можно запускать прямо через kubectl для проверки различных ресурсов Kubernetes и их логов:

  • Поды (Pods): сканирование логов и связанных событий отдельного пода. Например, kubectl preq my-pod-abc123 получит логи и события пода, а затем сравнит их с библиотекой правил CRE [1].

  • Сервисы (Services): команда kubectl preq service/my-service заставит Preq проверить поды за этим сервисом. У самих сервисов логов нет, но Preq определит связанные endpoints/поды и проверит их логи и события на наличие известных проблем.

  • Задания и планировщики (Jobs и CronJobs): запустите Preq на Job или на подах, созданных CronJob, чтобы изучить логи выполнения и события [12].

Под капотом плагин Preq использует API Kubernetes. Это означает, что его можно запускать для любого типа ресурсов, у которых есть логи или события, — получается гибкий «детектив» для вашего кластера.

Текущая версия Preq ориентирована прежде всего на логи и манифесты, однако при желании её можно задействовать и для конфигурационных файлов и событий кластера.

ConfigMaps — прямое сканирование объекта ConfigMap плагином:

kubectl preq -n <namespace> configmap/<name-of-config-map>

События Kubernetes (Kubernetes events) — используйте этот фидер, чтобы передать в Preq поток меток времени вместе с необработанным событием:

kubectl get events -A -o json | jq -r '.items[] | "(.metadata.creationTimestamp) (tojson)"' | kubectl preq

Прочие конфигурации рабочих нагрузок помимо ConfigMaps — используйте следующий обходной приём для передачи Deployment и аналогичных манифестов в виде компактного JSON, с одной меткой времени UTC на строку:

kubectl get deploy -A -o json | jq -c . | sed -e "1s/^/$(date -u +"%Y-%m-%dT%H:%M:%SZ") /" | kubectl preq

Отметим несколько правил CRE (Common Reliability Enumerations), созданных участниками сообщества [2][3][4][5]:

CRE

Что ломается

Сигналы, которые вы увидите

Теперь поговорим о другом виде проблем: контейнеры периодически завершают работу с непонятными кодами статуса. Preq содержит правила CRE [7] для распространённых кодов завершения, которые помогают точно определить причину сбоя контейнера. Разберём основных «подозреваемых»:

Код завершения 137 — как правило, означает, что процесс был принудительно завершён сигналом SIGKILL. В Kubernetes это чаще всего указывает на уничтожение из-за нехватки памяти (OOM kill): контейнер превысил допустимый объём памяти, и OOM killer операционной системы завершил его [6][7]. Такое может произойти и при ручном kill -9, но OOM — наиболее распространённая причина. В статусе пода при этом нередко отображается Reason: OOMKilled.

Причина: приложение превысило лимит памяти или на узле закончилась свободная память. Что делать: проверьте лимиты и потребление памяти контейнера. Команда kubectl top pod покажет, насколько активно использовалась память. Увеличение лимита (или запроса) памяти для контейнера поможет избежать OOMKill, либо нужно оптимизировать само приложение. Preq поможет, фиксируя частые OOM kill, — чтобы вы успели принять меры до того, как это затронет пользователей.

Код завершения 127 — означает «команда не найдена» (command not found). Процесс пытается выполнить файл или команду, которой не существует в файловой системе контейнера [8][9]. Это распространённая ошибка при неправильно настроенной команде запуска или entrypoint контейнера.

Причина: нужный бинарный файл не установлен, указан неверный путь или отсутствует зависимость. Иногда виноваты проблемы с экранированием в shell или с правами доступа к файлу, но чаще всего причина — просто отсутствующий исполняемый файл. Что делать: выполните kubectl describe pod — Kubernetes нередко записывает сообщение «command not found» в события. Исправьте команду в спецификации контейнера или в Dockerfile. Убедитесь, что образ содержит нужную программу по корректному пути. Preq умеет обнаруживать это, сканируя события или сообщения о завершении на наличие строки «exited with code 127» и характерного текста ошибки. Решение обычно очевидно: установить недостающий инструмент или исправить путь к команде.

Код завершения 134 — означает, что процесс получил сигнал SIGABRT (сигнал аварийного завершения) [10]. Проще говоря, приложение завершило себя само — нередко из-за внутренней ошибки: провала проверки (assertion failure), вызова abort() или фатальной ошибки.

Причина: типичные причины — баги (например, ложная проверка или недопустимый доступ к памяти, приводящий к abort), иногда — нехватка памяти в другом проявлении, либо достижение ресурсного лимита, вызывающего аварийное завершение. Что делать: просмотрите логи контейнера в поисках сообщений об ошибках или трассировки стека непосредственно перед завершением. Обычно там есть строка об assertion или фатальной ошибке. Preq зафиксирует факт завершения с кодом 134 и укажет, соответствует ли это известному шаблону. Убедитесь, что в используемой версии приложения нет известных багов, и при частых abort рассмотрите добавление liveness probe.

Код завершения 139 — это печально известная ошибка сегментации (segmentation fault, SIGSEGV) [10]. Процесс попытался обратиться к памяти, к которой не имел права (нулевой указатель, выход за границы буфера и т. п.), и ОС завершила его. Почти всегда это баг в коде приложения (или используемой им библиотеки).

Причина: segfault могут вызывать многие вещи: разыменование нулевого указателя, чтение/запись за пределами буфера, несовместимые нативные библиотеки и т. д. В некоторых случаях к segfault приводит даже переполнение стека. Что делать: как и в случае с кодом 134, первым делом изучите логи приложения или включите создание core dump для отладки. Если segfault происходит при запуске, причиной может быть несовместимость (например, неверная архитектура CPU или отсутствующие зависимости). Убедитесь, что образ собран для правильной архитектуры. Правило Preq для кода 139 оповестит вас о том, что контейнер получил SIGSEGV. Починить код оно не может, но гарантирует, что сбой не останется незамеченным.

Быстро проверить кластер на наличие подов, завершившихся с этими кодами, можно следующим фидером — он ищет коды завершения и передаёт результат в Preq:

kubectl get pods --all-namespaces -o json | jq -r '

В идеальном мире проблемы обнаруживаются до того, как вызывают простой, — и здесь Preq раскрывается в полной мере. Внедрение Preq в повседневные рабочие процессы с Kubernetes способно существенно сократить среднее время обнаружения проблем (mean time to detection):

  • Интеграция с CI/CD: рассмотрите запуск Preq как шага пост-деплойной проверки в пайплайне непрерывного развёртывания. Например, после выката новой версии приложения добавьте шаг kubectl preq для данного namespace или конкретных новых подов.

  • Плановые превентивные запуски: используйте kubectl preq -j, чтобы сгенерировать шаблон CronJob для Kubernetes. Команда создаст файл cronjob.yaml. Откройте его, задайте расписание, добавьте нужную команду Preq с параметрами -a (действие) и -o (вывод), укажите namespace и примените с помощью kubectl apply -f cronjob.yaml.

Обратите внимание: kubectl preq не поддерживает флаг для сканирования всех namespace одновременно. Чтобы проверить множество объектов, передайте шаблон источника данных в Preq или оберните несколько вызовов в небольшой скрипт, который выполняет CronJob.

  • Разбор инцидентов и непрерывное улучшение: после любого инцидента или простоя, если проблема оказалась новой, напишите правило CRE (и отправьте его в проект!). Фреймворк Preq позволяет закодировать накопленный опыт так, чтобы ни вы, ни кто-либо другой больше не наступали на те же грабли.

Подводя итог: Preq — мощный помощник для пользователей Kubernetes. Он превращает богатый опыт сообщества в работе с типичными сбоями в практические выводы, доступные по требованию. Встраивая Preq в CI/CD пайплайны, плановые сканирования и сессии диагностики, вы сможете проактивно выявлять и устранять проблемы — зачастую до того, как они станут заметны пользователям. Удачного мониторинга, и пусть ваши кластеры работают чисто и стабильно!

Если вас интересуют корпоративные возможности, такие как:

  • распределённый движок обнаружения, работающий на множестве узлов и кластеров;

  • веб-интерфейс с управляемыми сценариями расследования и совместной работой;

  • глубокие интеграции (например, с системами отслеживания инцидентов);

  • плоскость управления (control plane) для распределённого движка;

  • расширенный проприетарный набор правил CRE, поддерживаемый командой Prequel Reliability Research Team (PRRT),

— обратите внимание на Prequel, наш коммерческий продукт, и поделитесь впечатлениями!

© 2026 meganuke