С чего начинается отладка:
Первая команда всегда одна и та же:
Код: Выделить всё
kubectl get pods
NAME READY STATUS RESTARTS AGE
api-7d4b9c6f5d-x2x8q 0/1 ImagePullBackOff 0 2m
worker-6f9b8d7c4b-k9j2m 0/1 CrashLoopBackOff 4 5m
report-5c8d7f9b6c-p4n7r 0/1 Pending 0 8mКод: Выделить всё
kubectl describe pod api-7d4b9c6f5d-x2x8qРазбор по статусам:
ImagePullBackOff и ErrImagePull. Кластер не смог скачать образ. В Events будет точная причина: not found (опечатка в имени или теге), unauthorized (приватный registry, а imagePullSecrets не указан) или сетевой таймаут. Последнее особенно актуально, если ноды тянут образы с Docker Hub напрямую: надежнее держать копии в своем registry, том же Yandex Container Registry или Harbor на отдельной виртуалке.
Pending. Под даже не назначен на ноду. Шедулеру либо некуда его поставить (Insufficient cpu или Insufficient memory в Events, вспоминаем requests из главы 9), либо мешает условие: nodeSelector, который не совпадает ни с одной нодой, или PVC из главы 8, который сам завис в Pending.
CrashLoopBackOff. Образ скачан, контейнер стартует и падает, kubelet перезапускает его с растущей паузой. Здесь смотрим логи, причем именно упавшего экземпляра:
Код: Выделить всё
kubectl logs worker-6f9b8d7c4b-k9j2m --previousCreateContainerConfigError. Под ссылается на ConfigMap или Secret, которого нет (или он лежит в другом namespace). describe прямо назовет имя недостающего объекта. Привет главе 6.
OOMKilled. Контейнер убит за превышение лимита памяти. В describe это видно как Last State: Terminated, Reason: OOMKilled, exit code 137. Лечится либо поднятием limits, либо поиском утечки в приложении.
Когда describe молчит:
Иногда полезно посмотреть события всего namespace, отсортированные по времени:
Код: Выделить всё
kubectl get events --sort-by=.lastTimestamp -n productionКод: Выделить всё
kubectl debug -it worker-6f9b8d7c4b-k9j2m --image=busybox:1.36 --target=workerТипичные грабли:
Логи смотрят у нового экземпляра контейнера вместо упавшего и удивляются, что там пусто. Забывают флаг -n и ищут под не в том namespace. Путают "под не стартует" и "под Running, но 0/1 READY": второе почти всегда означает заваленную readiness-пробу из главы 10, и отлаживается она иначе. Тег latest с imagePullPolicy Always внезапно притягивает чужую свежую сборку. И помните, что события живут в кластере по умолчанию около часа: если под сломался ночью, утром секция Events может быть уже пустой, спасают только логи и мониторинг.
Что усвоили:
Алгоритм простой и почти всегда достаточный: get pods для диагноза, describe для деталей, логи упавшего экземпляра при падениях, get events для общей картины по namespace. В следующей главе соберем накопившиеся манифесты в нормальный пакет с помощью Helm, чтобы перестать таскать YAML россыпью.