Docker контейнер упал с кодом 1: Полное руководство по диагностике и решению

Docker контейнер упал с кодом 1: Полное руководство по диагностике и решению

Вы запускаете Docker контейнер, но вместо ожидаемой работы видите холодное сообщение \"Exited (1)\". Этот код ошибки — универсальный сигнал бедствия, крик о помощи изнутри контейнера. Он не говорит, что именно сломалось, но указывает на общий сбой приложения. В этой статье мы разберемся, как расшифровать этот сигнал, найти корень проблемы и вернуть ваш контейнер к жизни.

Что на самом деле означает код 1?

В мире Unix-подобных систем, на которых работает Docker, код выхода 1 означает \"общая ошибка\". Это неспецифичный код, который приложение возвращает при любом сбое, не попадающем под другие категории. Контейнер — это просто процесс, и когда основной процесс внутри него завершается с кодом 1, Docker останавливает весь контейнер.

Ключевой момент: код 1 говорит \"что-то пошло не так\", но не говорит \"что именно\". Ваша задача — стать детективом и найти улики.

Систематическая диагностика: Пошаговый план

Шаг 1: Проверьте логи контейнера

Первое и самое важное действие — посмотреть логи упавшего контейнера. Это ваш главный источник информации.

docker logs [CONTAINER_ID_OR_NAME]

Ищите в выводе:

  • Трассировки стека (stack traces)
  • Сообщения об ошибках файловой системы
  • Ошибки подключения к базам данных или другим сервисам
  • Проблемы с разрешениями
  • Отсутствующие файлы или переменные окружения

Шаг 2: Запустите контейнер в интерактивном режиме

Если логи недостаточно информативны, попробуйте запустить контейнер с интерактивной оболочкой, чтобы исследовать его изнутри.

docker run -it --entrypoint=/bin/bash your_image_name

Внутри контейнера проверьте:

  1. Существуют ли все необходимые файлы
  2. Правильно ли установлены разрешения
  3. Доступны ли переменные окружения (команда `env`)
  4. Можете ли вы вручную запустить основной процесс

Шаг 3: Проверьте Dockerfile и точку входа

Ошибка часто скрывается в Dockerfile. Распространенные проблемы:

  • Неправильная команда `CMD` или `ENTRYPOINT`
  • Отсутствие необходимых зависимостей в образе
  • Попытка запуска от неправильного пользователя
  • Отсутствие обработчика сигналов для graceful shutdown

Используйте `docker inspect [CONTAINER_ID]` чтобы увидеть точную команду, с которой запускался контейнер, и все установленные переменные окружения.

Распространенные причины и их решения

1. Отсутствие или ошибка в точке входа (ENTRYPOINT/CMD)

Если файл, указанный в `CMD`, отсутствует или неисполняемый, контейнер сразу завершится с кодом 1.

# Проверьте в Dockerfile
CMD [\"несуществующий_скрипт.sh\"]  # Ошибка!
CMD [\"./app.py\"]  # Убедитесь, что app.py существует и имеет права на выполнение

2. Проблемы с переменными окружения

Приложение может требовать определенные переменные окружения, которые не были переданы.

# Запуск с проверкой переменных
docker run -e \"DB_HOST=localhost\" your_image
# Или используйте файл с переменными
docker run --env-file .env your_image

3. Ошибки в скрипте запуска

Скрипт, который запускает ваше приложение, может содержать ошибки. Добавьте отладку:

#!/bin/bash
set -e  # Выход при любой ошибке
set -x  # Вывод каждой команды перед выполнением
# ... ваш код ...

4. Проблемы с зависимостями

Библиотеки или пакеты, установленные во время сборки, могут отсутствовать или быть несовместимыми.

Решение: пересоберите образ с явным указанием версий зависимостей и проверьте, что все необходимое включено в финальный образ.

5. Конфликты портов

Если порт, который пытается занять контейнер, уже занят другим процессом, приложение может завершиться с ошибкой.

# Проверьте занятые порты
netstat -tulpn | grep :порт
# Или используйте другой порт
docker run -p 8080:80 your_image

Продвинутые техники отладки

Использование Healthcheck

Добавьте healthcheck в Dockerfile, чтобы Docker мог мониторить состояние приложения:

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
  CMD curl -f http://localhost/ || exit 1

Отладка с помощью временных контейнеров

Создайте минимальный тестовый контейнер, чтобы изолировать проблему:

# Минимальный образ для тестирования
FROM alpine:latest
COPY ваш_скрипт.sh /
CMD [\"/ваш_скрипт.sh\"]

Логирование в stdout/stderr

Убедитесь, что ваше приложение пишет логи в стандартные потоки вывода, а не в файлы внутри контейнера. Docker перехватывает только stdout/stderr.

Профилактика будущих ошибок

  • Всегда используйте конкретные теги образов (не `latest`)
  • Пишите скрипты запуска с обработкой ошибок
  • Используйте multi-stage builds для минимизации образов
  • Добавляйте метаданные и labels для лучшей трассировки
  • Тестируйте образы локально перед отправкой в production

Создайте чек-лист проверок перед запуском в production: зависимости, переменные окружения, разрешения, порты, здоровье приложения.

FAQ: Часто задаваемые вопросы

Как быстро посмотреть, почему контейнер упал?

Используйте команду `docker logs [контейнер]` сразу после падения. Для автоматического просмотра последних логов: `docker logs --tail 50 -f [контейнер]`.

Мой контейнер падает сразу после запуска. Что делать?

Запустите его с флагом `-it` и интерактивной оболочкой (`--entrypoint=/bin/bash`) чтобы исследовать внутреннее состояние перед запуском основного процесса.

Как отличить ошибку приложения от ошибки Docker?

Если `docker logs` показывает логи вашего приложения перед падением — это ошибка приложения. Если контейнер падает мгновенно без логов — проблема в точке входа или зависимостях.

Почему контейнер работает локально, но падает на сервере?

Частые причины: разные версии Docker, отсутствие переменных окружения на сервере, конфликты портов, различия в файловых системах или разрешениях.

Как предотвратить автоматический удаление упавших контейнеров?

Не используйте флаг `--rm` при запуске, или настройте политику хранения логов в Docker daemon.

Можно ли автоматически перезапускать контейнер при падении?

Да, используйте политику перезапуска: `docker run --restart=always ваш_образ`. Но сначала устраните причину падения!