Топовые ошибки Kubernetes: причины и решения
Опубликовано:
Используемые термины: Kubernetes.
В этой статье разберем самые частые сценарии устранения неполадок в Kubernetes — не все подряд, а топ ошибок, с которыми сталкиваются чаще всего. Для каждой — причина, решение и команда для диагностики.
Для удобства, мы разобьем ошибки на категории.
Ошибки контейнеров
Проблемы на уровне подов
Конфигурация и права
Сетевые и инфраструктурные ошибки
Шпаргалка по диагностике
Ошибки на уровне контейнера
Проблемы внутри самого контейнера или с его запуском.
CrashLoopBackOff
Причина: контейнер запускается и сразу падает, Kubernetes пытается перезапустить его снова и снова.
Решение: сначала смотрим текущие логи пода:
kubectl logs <имя-пода>
* если под успел упасть до вывода логов — берем логи предыдущей попытки:
kubectl logs <имя-пода> --previous
Для пода с несколькими контейнерами обязательно указываем нужный через -c <имя-контейнера>. Если логов нет вообще ни там, ни там — смотрим exit code через:
kubectl describe pod <имя-пода>
Часто причина — ошибка в команде запуска или отсутствие нужной переменной окружения.
OOMKilled
Причина: контейнер превысил лимит памяти, и ядро принудительно завершило процесс.
Решение: сначала смотрим графики потребления памяти приложением, а не сразу увеличиваем лимит. Проверить факт OOM можно командой describe — статус контейнера покажет Reason: OOMKilled.
* если потребление памяти постоянно растет — это похоже на утечку в приложении, и увеличение лимита лишь отсрочит проблему. Также не стоит без необходимости выставлять limits и requests памяти одинаковыми — это лишает под гибкости.
Ошибка запуска контейнера (RunContainerError)
Причина: классическая ошибка запуска контейнера в Kubernetes — среда выполнения (Docker или containerd) не смогла создать контейнер: неверный путь к volume, отсутствующий файл конфигурации или проблема с правами.
Решение: изучаем детали ошибки в событиях пода и логах узла (kubelet). Часто помогает проверка монтируемых volume и путей внутри манифеста.
CreateContainerConfigError и CreateContainerError
Причина: kubelet не может создать контейнер еще до его запуска — проблема в самой конфигурации: ошибка в command/args, ссылка на несуществующий ConfigMap или Secret.
Решение: причина обычно видна прямо в событиях пода:
kubectl describe pod <имя-пода>
* типичная строка в Events — secret "db-creds" not found. Эта ошибка возникает раньше, чем CrashLoopBackOff или RunContainerError, — стоит проверять ее первой, если под вообще не стартует.
Init:Error и Init:CrashLoopBackOff
Причина: упал init-контейнер. Основные контейнеры пода в этом случае даже не запускаются, пока init-контейнер не отработает успешно.
Решение: логи основного контейнера тут не помогут — смотрим логи именно init-контейнера, указав его имя явно:
kubectl logs <имя-пода> -c <имя-init-контейнера>
* под в статусе Init:Error — это не ошибка основного приложения, а сигнал смотреть именно на подготовительный шаг перед стартом.
Ошибки на уровне пода
Под не может стартовать или работает некорректно из-за внешних факторов.
ImagePullBackOff и ErrImagePull
Причина: кластер не может скачать образ — неверное имя, приватный registry без авторизации или образ вообще не существует.
Решение: проверяем имя и тег образа, а также доступ к registry:
kubectl describe pod <имя-пода>
* для приватных registry нужен secret с учетными данными — создаем его через kubectl create secret docker-registry.
Зависание в Pending
Причина: планировщику не хватает ресурсов — CPU, памяти или подходящей ноды под заданные лимиты и селекторы. Это одно из типичных состояний ошибки пода в Kubernetes.
Решение: смотрим события пода:
kubectl describe pod <имя-пода>
В блоке Events обычно видно точную причину — недостаточно ресурсов, taints на нодах или не найден подходящий PersistentVolume.
Evicted
Причина: нода испытывает нехватку ресурсов — диска или памяти, и kubelet принудительно выселяет поды с низким приоритетом, чтобы освободить место.
Решение: смотрим причину на самой ноде:
kubectl describe node <имя-ноды>
* вручную чистить логи контейнеров на ноде не стоит — это может сломать сбор логов рантайма. Вместо этого настраиваем ротацию логов на уровне containerd/Docker или переносим сбор в централизованную систему (EFK, Loki). Для образов настраиваем garbage collection на самой ноде, а не удаляем их руками. Если Evicted повторяется системно — пересматриваем requests и limits у подов, а не боремся с симптомом.
Ошибка Readiness и Liveness Probe
Причина: приложение внутри контейнера не отвечает на проверки готовности или живости — под запущен, но Kubernetes считает его нездоровым и постоянно перезапускает или не пускает трафик.
Решение: смотрим события пода — там видна конкретная проверка, которая падает:
kubectl describe pod <имя-пода>
* частая причина — слишком короткий initialDelaySeconds, приложение просто не успевает подняться до первой проверки. Увеличиваем задержку или таймаут в манифесте. У новичков не реже встречается другая причина — неверный путь эндпоинта или код ответа: убедитесь, что /healthz (или тот путь, что указан в манифесте) действительно существует и возвращает ожидаемый HTTP-код.
Terminating (под или namespace не удаляется)
Причина: под или целый namespace зависает в статусе Terminating при удалении — контроллер не может корректно завершить финализаторы (finalizers) или на ресурсе держится блокировка.
Решение: смотрим, какие финализаторы висят на объекте:
kubectl get pod <имя-пода> -o yaml
* ищем секцию finalizers в выводе. Убирать финализаторы вручную стоит только когда точно понятна причина зависания — иначе можно потерять связанные с объектом ресурсы.
Ошибки конфигурации и RBAC
Проблемы из-за неверных манифестов или недостатка прав.
ConfigMap или Secret не найден
Причина: под ссылается на ConfigMap или Secret, которого нет в нужном namespace — опечатка в имени или объект создан не в том пространстве имен.
Решение: проверяем, что объект вообще существует:
kubectl get configmap,secret -n <namespace>
* если объект есть, а под все равно не стартует — сверяем namespace в манифесте пода и в самом ConfigMap/Secret, они должны совпадать.
Forbidden (ошибки RBAC)
Причина: у пода или пользователя нет прав на нужное действие — не настроена или неверно настроена Role/ClusterRole и привязка к ней.
Решение: проверяем, какие права реально есть:
kubectl auth can-i <действие> <ресурс>
* если прав не хватает — правим RoleBinding или ClusterRoleBinding, добавляя нужный ServiceAccount. Не выдаем прав больше, чем реально нужно для задачи.
PVC и StorageClass
Причина: под висит в Pending, но первопричина не в CPU или памяти, а в том, что PersistentVolumeClaim не может связаться (bound) с PersistentVolume.
Решение: проверяем сам PVC, а не только под:
kubectl get pvc
* если PVC в статусе Pending — смотрим его describe. Частые причины: не указан storageClassName: "" для статического PV, дефолтный StorageClass не может динамически создать диск, либо в кластере отсутствует нужный CSI-драйвер.
Сетевые и инфраструктурные ошибки
Связность внутри кластера и доступ к нему.
Проблемы с DNS и сетевой доступностью
Причина: под не может подключиться к другому сервису по имени — проблема в CoreDNS, неверном имени сервиса или сетевой политике, которая блокирует трафик.
Решение: проверяем резолвинг DNS прямо из пода:
kubectl exec -it <имя-пода> -- nslookup <имя-сервиса>
* утилиты nslookup или dig есть не в каждом образе. Если их нет — поднимаем временный под для диагностики: kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup <имя-сервиса>. Если резолвинг не работает вообще — смотрим статус подов CoreDNS: kubectl get pods -n kube-system -l k8s-app=kube-dns. Если резолвинг работает, а соединения нет — ищем ограничивающий NetworkPolicy.
Проблемы подключения kubectl к кластеру
Причина: kubectl не может достучаться до API-сервера — неверный контекст, устаревший kubeconfig или сетевые ограничения.
Решение: проверяем подключение к кластеру:
kubectl cluster-info
* если команда зависает или возвращает ошибку — сверяем контекст: kubectl config current-context, и адрес сервера в файле kubeconfig.
Несовместимость версии kubectl
Причина: версия kubectl, установленная локально, слишком сильно расходится с версией сервера, а нужная версия клиента в системе может вообще отсутствовать.
Решение: проверяем обе версии:
kubectl version
* при большом расхождении kubectl предупредит об этом сам — тогда нужно скачать подходящую версию клиента с официального сайта Kubernetes и переключиться на нее.
Шпаргалка по диагностике
Коды ошибок Kubernetes почти всегда указывают направление поиска — сначала смотрим статус пода, потом события, потом логи. Собрали все случаи из статьи в одну таблицу — держите ее под рукой при разборе инцидентов.
| Ошибка | Вероятная причина | Команда для диагностики |
|---|---|---|
| CrashLoopBackOff | контейнер падает при старте | kubectl logs <под> --previous |
| ImagePullBackOff | образ недоступен или не существует | kubectl describe pod <под> |
| Pending | не хватает ресурсов или подходящей ноды | kubectl describe pod <под> |
| OOMKilled | превышен лимит памяти | kubectl describe pod <под> |
| Evicted | нехватка диска или памяти на ноде | kubectl describe node <нода> |
| RunContainerError | ошибка создания контейнера в среде выполнения | kubectl describe pod <под> + логи kubelet |
| CreateContainerConfigError | ошибка в конфигурации до запуска контейнера | kubectl describe pod <под> |
| Init:Error | упал init-контейнер | kubectl logs <под> -c <init-контейнер> |
| PVC Pending | PVC не биндится к PV | kubectl get pvc |
| Terminating | висят финализаторы или блокировка ресурса | kubectl get pod <под> -o yaml |
| Readiness/Liveness Probe failed | приложение не отвечает на проверку | kubectl describe pod <под> |
| Forbidden | не хватает прав RBAC | kubectl auth can-i <действие> <ресурс> |
| ConfigMap/Secret не найден | объект отсутствует или не в том namespace | kubectl get configmap,secret -n <namespace> |
| Ошибка DNS/сети | не резолвится сервис или блокирует NetworkPolicy | kubectl exec <под> -- nslookup <сервис> |
| kubectl не подключается | неверный контекст или kubeconfig | kubectl cluster-info |
| Несовместимость версии | расхождение client/server | kubectl version |