Снаружи все инциденты в Kubernetes выглядят одинаково — «сервис не работает». Но причины разные: упал сам процесс, кончилась память, не скачался образ, не прошла проверка здоровья, сломалась маршрутизация. Эта статья — набор команд и пошаговый разбор типичных ситуаций: по симптому находим причину и понимаем, что делать.
Базовый набор команд
Прежде чем разбирать конкретные симптомы — десяток команд, которые нужны постоянно. Все примеры с неймспейсом payments, подставьте свой.
kubectl -n payments get pods # общее состояние: STATUS, RESTARTS, AGE
kubectl -n payments describe pod order-service-xxx # подробности пода: события, причины
kubectl -n payments logs order-service-xxx # логи текущего контейнера
kubectl -n payments logs order-service-xxx -p # логи ПРЕДЫДУЩЕГО запуска (до рестарта!)
kubectl -n payments logs deploy/order-service --tail=200 -f # логи всех реплик деплоймента
kubectl -n payments get events --sort-by=.lastTimestamp # лента событий неймспейса
kubectl -n payments exec -it order-service-xxx -- sh # шелл внутри контейнера
kubectl -n payments port-forward svc/order-service 8080:80 # сервис к себе на localhost
kubectl -n payments top pods # фактический CPU и память
kubectl -n payments get endpoints order-service # кто реально стоит за Service
kubectl -n payments rollout status deploy/order-service # как идёт выкатка
Две команды недооценены больше остальных. logs -p — единственный способ увидеть, что происходило до рестарта: текущие логи начинаются с нуля после перезапуска. get events --sort-by=.lastTimestamp — Kubernetes прямым текстом пишет причины: не хватило памяти на ноде, не смог скачать образ, проверка здоровья провалилась.
CrashLoopBackOff: под перезапускается снова и снова
Под стартует, падает, Kubernetes ждёт (пауза нарастает с каждым разом) и перезапускает снова. Это не отдельная проблема — это симптом: приложение завершается. Причина внутри.
Порядок разбора:
logs -p— что сказало приложение перед тем, как упасть? Стектрейс? Сообщение «port already in use»? Ошибка чтения конфига?describe pod— смотрим exit code. Код1— процесс упал сам, причина в логах. Код137— процесс убит снаружи, см. OOMKilled ниже.- Если логов нет совсем — приложение не успело добраться до логгера: проверьте entrypoint образа и настройки логирования.
Отдельный частый случай — убийство liveness probe. Приложение запускается 90 секунд, а liveness probe начинает проверки через 30 — под убивается снова и снова, так и не успевая стартовать. Лечится startup probe с честным failureThreshold. Подробнее про probes — в статье Spring Boot в Kubernetes.
OOMKilled: контейнер убит из-за памяти
Контейнер превысил memory limit — и ядро операционной системы его убило. Мгновенно, без стектрейса и прощальных сообщений в логах. В выводе describe pod будет: Last State: Terminated, Reason: OOMKilled.
Exit code при этом — 137 (128 + сигнал SIGKILL).
Для приложений на виртуальной машине — Java (JVM), .NET, Kotlin — причина почти всегда одна из двух: рантайм не знает об ограничении контейнера и выделяет heap пропорционально всей памяти ноды, а не лимиту. Современные JVM умеют читать cgroup-лимиты автоматически начиная с Java 10 — убедитесь, что версия подходящая и нужные флаги выставлены. Подробнее — в настройках ресурсов.
Важно не путать: OutOfMemoryError в логах — это не OOMKilled. Это heap закончился внутри живого процесса. Лечится по-другому: смотрим, что держит память, и либо увеличиваем heap, либо ищем утечку.
ImagePullBackOff: образ не скачивается
Нода не может загрузить образ из реестра. Три причины закрывают почти всё:
- Опечатка в теге, или тег не был отправлен — CI собрал образ, но push упал.
- Нет прав к реестру: protух imagePullSecret или он вовсе не указан.
- Реестр недоступен с ноды.
describe pod покажет точную ошибку реестра в разделе events. Это единственный инцидент из всех, где код приложения гарантированно ни при чём.
Pending: под висит и никуда не идёт
Под создан, но Kubernetes не назначил его ни на одну ноду. describe pod → events → там будет причина словами.
Самые частые:
Insufficient memory/Insufficient cpu— ни на одной ноде нет столько свободных requests. Планирование идёт по requests, а не по фактическому потреблению. Кластер может быть «полон» при низком реальном использовании.- Несовпадение nodeSelector, affinity или taints — под ищет ноду с определёнными метками, но таких нет.
Что делать разработчику: проверить, не завышены ли requests у сервиса. Если нет — разговор с командой, которая управляет кластером, про ёмкость.
Мигающая readiness: соседи получают 503
Симптом: сервис «работает», но потребители периодически ловят 503 или таймауты. Под то входит в ротацию, то выпадает.
Причина — readiness probe нестабильна. Когда под не проходит проверку, Kubernetes убирает его из endpoints: трафик на него не идёт. Когда проходит — возвращает обратно.
Типичные сценарии:
- В readiness включена нестабильная внешняя зависимость. Мигает она — мигает весь сервис.
- GC-паузы или перегрузка заставляют probe не укладываться в timeout.
- Слишком агрессивные
periodSecondsиfailureThreshold.
Проверка: kubectl get endpoints несколько раз подряд — список то сокращается, то восстанавливается. В describe pod — Readiness probe failed в событиях.
Решение: вынести из readiness зависимости, без которых сервис может отвечать в деградированном режиме, и скорректировать пороги.
«Запрос не доходит»: проверяем цепочку
Снаружи 502 или 504, а поды зелёные. Проверяем цепочку по пути запроса сверху вниз, каждое звено отдельно:
kubectl -n payments get ingress api # 1. Ingress есть, host/path верные?
kubectl -n payments get endpoints order-service # 2. За Service есть поды?
kubectl -n payments port-forward svc/order-service 8080:80 # 3. Service отвечает?
kubectl -n payments port-forward pod/order-service-xxx 8080:8080 # 4. Сам под отвечает?
Где цепочка рвётся — там и уровень проблемы:
- Шаг 4 не работает → проблема в приложении.
- Шаги 2–3 → selector или readiness.
- Шаг 1 → Ingress, DNS или TLS.
Пустые endpoints при живых подах — почти всегда readiness или опечатка в selector (метки пода не совпадают с selector сервиса — после переименования манифестов такое бывает). Также стоит проверить NetworkPolicy: «запрос не доходит» между неймспейсами может быть политикой, а не поломкой.
Под перезапустился «сам»
RESTARTS > 0 без деплоя — у рестарта всегда есть причина, и она записана. describe pod → Last State. Варианты:
- OOMKilled — см. выше.
- Liveness probe failed — проверьте, не проверяет ли она внешнюю базу данных или другой сервис.
- Нода ушла в drain или на обновление — это штатная ситуация. Поды обязаны переживать переезд: для этого нужны
PodDisruptionBudgetи минимум две реплики. - Evicted — нода исчерпала дисковое пространство или другой ресурс и вытеснила под.
Что должно быть до инцидента
Всё описанное разбирается за минуты, когда у сервиса есть базовая гигиена:
- Структурированные логи в stdout — платформа их собирает. Файлы внутри контейнера умирают вместе с ним.
- Метрики в формате Prometheus — де-факто стандарт в Kubernetes.
- Алерты на рестарты и недоступность endpoints.
- Дашборд с памятью и CPU по подам в сравнении с limits.
Без этого отладка превращается в угадывание. Подробнее — в Observability Style Guide.
Коротко
logs -pпоказывает логи до рестарта — это первое, что смотрят при CrashLoopBackOff.get events --sort-by=.lastTimestamp— Kubernetes прямым текстом пишет, что пошло не так.- CrashLoopBackOff — приложение падает; exit code 1 → смотрим логи, exit code 137 → OOMKilled.
- OOMKilled: рантайм не видит cgroup-лимит или лимит мал; в логах следа нет.
- ImagePullBackOff: тег не существует, нет прав к реестру или реестр недоступен.
- Pending: requests не помещаются на ноде; планирование идёт по requests, не по факту.
- Мигающая readiness → под выпадает из endpoints → 503 у потребителей.
- 502/504 при живых подах: проверяем цепочку Ingress → Service → endpoints → под.
Что почитать дальше
- Spring Boot в Kubernetes — probes и ресурсы: профилактика половины этих ситуаций.
- Сеть и трафик — endpoints, Ingress и NetworkPolicy.
- Деплой и конфигурация — rollout status и откаты.
- Observability Style Guide — логи, метрики и алерты, без которых отладка слепа.