Под перезапускается в пятый раз. Вы вводите kubectl logs my-pod и получаете одну строку — или вообще ничего. Вы переразвёртываете. Он снова перезапускается. Где-то между третьим и четвёртым перезапуском наступает паника, потому что кластер вам что-то говорит, а вы не слышите. Эта статья о том, как научиться это слышать: конкретный порядок диагностики, коды выхода, которые подсказывают, где искать, и несколько причин, стоящих за большинством событий CrashLoopBackOff — каждая с точной командой kubectl и однострочным исправлением манифеста.
Почему kubectl logs ничего не показывает (и что запускать вместо этого)
Вот ловушка, в которую попадают почти все. Контейнер, падающий при запуске, записывает ошибку и умирает. Новый контейнер стартует с пустым буфером логов. kubectl logs показывает вам текущий контейнер, который, возможно, ещё ничего не записал. Нужная вам ошибка — в предыдущем.
kubectl logs my-pod --previous
Этот единственный флаг решает большую часть случаев «логи пустые». Если он всё равно ничего не показывает, контейнер, вероятно, даже не дошёл до запуска процесса — а значит, проблема вовсе не внутри вашего приложения.
Итак, порядок диагностики:
kubectl describe pod my-pod— прочитайте Events внизу и State/Last State контейнера вверху.kubectl logs my-pod --previous— вывод падения из мёртвого контейнера.- Проверьте код выхода в Last State. Это сужает круг быстрее любых логов.
Девять причин, с которыми вы действительно столкнётесь
Как только вы знаете код выхода, причины быстро сужаются. Вот карта — каждая строка это реальный шаблон, а не гипотеза.
Симптом в describe |
Вероятная причина | Исправление |
|---|---|---|
CreateContainerConfigError |
Отсутствует ConfigMap или ключ Secret | Создайте ключ или исправьте имя configMapKeyRef / secretKeyRef |
| Код выхода 1, мгновенное падение | Неверные command или entrypoint |
Запустите kubectl exec в рабочий образ и проверьте путь к бинарнику |
| Код выхода 137, нет сообщения OOMKilled | Liveness-проба убивает медленно стартующее приложение | Добавьте initialDelaySeconds / увеличьте failureThreshold |
OOMKilled: true |
Контейнер достиг лимита памяти | Увеличьте resources.limits.memory или исправьте утечку |
Read-only file system |
readOnlyRootFilesystem: true без записываемого тома |
Смонтируйте emptyDir туда, куда пишет приложение |
Под застрял в Init:0/1 |
Init-контейнер ждёт зависимость | Проверьте логи init-контейнера — kubectl logs my-pod -c init-name |
ImagePullBackOff |
Приватный реестр, отсутствует imagePullSecrets |
Создайте секрет и укажите его в спецификации пода |
| Падение с ошибкой типа | Неверная переменная окружения (например, PORT=abc) |
Исправьте значение в ConfigMap или блоке env |
| Падение после запуска | База данных или сервис ещё не готовы | Добавьте readiness-пробу или цикл повторных попыток в приложении |
Некоторые из них заслуживают более пристального взгляда, потому что исправление не так очевидно, как подсказывает строка.
Liveness-проба, которая убивает здоровое приложение
Liveness-проба отвечает на один вопрос: жив ли этот контейнер? Если она проваливается failureThreshold раз, kubelet убивает контейнер и перезапускает его. Это правильное поведение для зависшего процесса — и катастрофическое для приложения, которому просто нужно 40 секунд на прогрев, а проба начинает проверку через 10. Контейнер убивают, он перезапускается, снова прогревается, его снова убивают. Вы видите цикл перезапусков и здоровые логи. Исправление — initialDelaySeconds (или startupProbe), а не больше памяти.
OOMKill из-за отсутствия лимита
Контейнер без лимита памяти может потреблять ресурсы узла, пока не вмешается OOM-killer ядра — и он не всегда выбирает ваш контейнер. Установка resources.requests.memory и resources.limits.memory делает сбой локальным и читаемым: под убит, describe показывает OOMKilled, и вы точно знаете, какой сервис смотреть. Без лимитов симптом — инцидент на весь узел без явного виновника.
Зависимость, которая ещё не готова
Эта причина обманывает людей, потому что собственные логи приложения выглядят чисто. Контейнер запускается, пытается подключиться к базе данных или вышестоящему сервису, терпит неудачу и завершается. kubectl describe показывает код выхода 1 и больше ничего. Исправление не в Deployment — оно в том, как приложение обрабатывает медленную зависимость: цикл повторных попыток или readiness-проба, чтобы трафик ждал, пока соединение установится. Смежный разбор: Архитектура микросервисов на практике рассказывает, как это разворачивается между сервисами. Подробнее — в статье «Docker и Kubernetes».
Отладка вручную vs. построение кластера, который не падает
Есть два способа изучить этот материал, и они дают разные навыки.
Читать об этом vs. ломать это. Вы можете запомнить таблицу кодов выхода за двадцать минут. Вы всё равно замрёте в первый раз, когда реальный под зациклится, потому что навык — не таблица, а привычка запускать describe перед logs и читать Events перед догадками. Эта привычка приходит от повторения на кластере, который можно уничтожить. Локальный кластер kind или minikube стоит только времени; компромисс в том, что никто не скажет вам, был ли ваш диагноз верным.
Самообучение vs. структурированная практика. Самообучение дёшево и гибко, и для опытного инженера его достаточно. Цена проявляется в пробелах: вы изучаете причины, на которые случайно наткнулись, и никогда — те, которые ваш рабочий процесс не порождает. Структурированный путь с лабораторными работами и сессиями по устранению неполадок на время знакомит вас с девятью причинами выше в контролируемой обстановке — включая те, которые ваши собственные проекты никогда бы не выявили. Если вы хотите понять, насколько эта работа на самом деле состоит в чтении вывода об ошибках, DevOps и облачная инфраструктура — хорошее дополнение.
Индивидуальная отладка vs. формат экзамена. В повседневной работе у вас есть час и коллега, к которому можно обратиться. В условиях CKA и CKAD у вас минуты и терминал. Эту разницу стоит отрабатывать специально: пробный экзамен из 24 заданий на два часа — это не о знаниях, которых вам не хватает, а о скорости вашего порядка диагностики.
Для кого это
Если вы уже запускаете рабочие нагрузки в Kubernetes и хотите, чтобы режимы отказа перестали быть загадочными, этот материал окупится сразу — один только порядок диагностики сэкономит вам часы в первый месяц. Если вы готовитесь к CKA или CKAD, это та часть программы, которая на самом деле решает ваш результат, потому что задания по устранению неполадок вознаграждают фиксированную последовательность, а не импровизацию. Подробнее — в статье «Kubernetes без паники».
Это менее полезно, если вы никогда не развёртывали контейнер. CrashLoopBackOff — проблема второй недели; вам нужна первая неделя — поды, Deployment, Services — прежде чем коды выхода что-то значить. И никакое чтение не заменит кластер, где вы можете выполнить kubectl delete pod и посмотреть, что произойдёт дальше.
В следующий раз, когда под зациклится, не переразвёртывайте. Запустите kubectl describe, прочитайте код выхода, затем --previous. В девяти случаях из десяти ответ уже на вашем экране. Курс проходит этот порядок диагностики в практических лабораторных работах на реальном кластере, с сессиями по устранению неполадок и пробными экзаменами на время, повторяющими формат CKA и CKAD — подробности на странице CKA + CKAD — администратор и разработчик Kubernetes. Подробнее — в статье «Промты для Docker и Kubernetes».