Вы запускаете Docker контейнер, но вместо работающего сервиса видите холодное сообщение \"Exited (1)\" в статусе. Код 1 — это не просто ошибка, это крик о помощи вашего приложения из изолированной среды. В этой статье мы разберемся, что скрывается за этим кодом возврата, как системно подойти к диагностике и какими методами вернуть контейнер к жизни.
Что на самом деле означает код 1?
В мире Unix-подобных систем, на которых работает Docker, код возврата 0 означает успешное завершение, а любой ненулевой код — ошибку. Конкретно код 1 — это общий код ошибки, который приложение возвращает при неудачном завершении. Это эквивалентно EXIT_FAILURE в языке C. Проблема в том, что сам по себе код 1 не говорит, что именно пошло не так — только что что-то пошло не так.
Ключевой момент: Код 1 возвращает само приложение внутри контейнера, а не Docker Engine. Docker лишь честно сообщает вам этот код.
Системный подход к диагностике
Не пытайтесь угадать причину. Действуйте как детектив, собирая улики в строгом порядке.
Шаг 1: Проверьте логи контейнера
Первое и самое важное — получить вывод приложения. Используйте команду:
docker logs [CONTAINER_ID_OR_NAME]
Часто именно в логах содержится конкретное сообщение об ошибке: отсутствие файла, ошибка синтаксиса, недоступность порта или проблемы с переменными окружения.
Шаг 2: Запустите контейнер в интерактивном режиме
Если логи не дают ясной картины, попробуйте запустить контейнер с интерактивной оболочкой, особенно если в Dockerfile указан SHELL. Для контейнера на основе Alpine, Ubuntu и подобных:
docker run -it --entrypoint=/bin/sh ваш_образ
Это позволит вам вручную исследовать файловую систему, проверить наличие файлов и попробовать запустить команду вручную, чтобы увидеть ошибку своими глазами.
Шаг 3: Проанализируйте Dockerfile
Ошибка часто зашита в самом Dockerfile. Проверьте:
- Корректность команды
CMDилиENTRYPOINT. Существует ли указанный файл? - Правильность копирования файлов с помощью
COPYилиADD. - Не завершается ли какой-либо этап сборки (
RUN) ошибкой, которая игнорируется?
Типичные причины и их решения
1. Отсутствие или ошибка в точке входа (Entrypoint)
Самая частая причина. Контейнер запускается, сразу выполняет команду из CMD или ENTRYPOINT, она падает с ошибкой, и контейнер завершается.
Решение: Убедитесь, что файл, указанный в точке входа, существует внутри контейнера, имеет флаг исполняемости (chmod +x) и не содержит синтаксических ошибок.
2. Проблемы с правами доступа
Приложение пытается записать в файл или прочитать из директории, но у пользователя (часто non-root) нет необходимых прав.
Решение:
- В Dockerfile измените владельца файлов с помощью
RUN chownилиRUN chmod. - Или запустите контейнер от root пользователя (небезопасно для продакшена), добавив
user: rootв docker-compose.yml или флаг-u root.
3. Отсутствие зависимостей
В образе не установлены все необходимые библиотеки или пакеты для работы приложения.
Решение: Пересоберите образ, добавив в Dockerfile установку недостающих пакетов. Проверьте логи сборки (docker build).
4. Неправильные переменные окружения
Приложение ожидает определенные переменные (ENV), которые не были переданы при запуске, или они имеют неверный формат.
docker run -e \"DATABASE_URL=postgres://...\" ваш_образ
Проверьте, все ли обязательные переменные указаны в docker run или docker-compose.yml.
5. Конфликт портов
Порт, который пытается занять контейнер (например, 80 или 8080), уже занят другим процессом на хосте.
Решение: Освободите порт на хосте или измените маппинг портов при запуске:
docker run -p 8081:80 ваш_образ
Продвинутые методы отладки
- Используйте
docker inspect: Командаdocker inspect [CONTAINER_ID]покажет полную конфигурацию контейнера, включая точныйEntrypoint,Cmdи переменные окружения. - Проверьте статус выхода предыдущего контейнера:
docker ps -aпокажет список всех контейнеров и их коды завершения. - Соберите образ с отладочными инструментами: Добавьте в Dockerfile установку
curl,vim,net-toolsдля более глубокого исследования.
FAQ (Часто задаваемые вопросы)
Docker контейнер сразу завершается с кодом 1. Что делать?
Выполните три шага по порядку: 1) Проверьте логи (docker logs). 2) Запустите контейнер в интерактивном режиме с оболочкой. 3) Проанализируйте Dockerfile на предмет ошибок в CMD и копировании файлов.
Как понять, почему контейнер упал, если в логах ничего нет?
Если логи пусты, значит, приложение не успело ничего вывести в stdout/stderr. Скорее всего, падение происходит на самом раннем этапе, до инициализации логирования. Проверьте точку входа и наличие всех файлов в контейнере.
Может ли код 1 быть из-за проблем с памятью (OOM)?
Нет. Если контейнер завершился из-за нехватки памяти (Out Of Memory Kill), Docker обычно показывает статус \"Exited (137)\". Код 137 = 128 + 9 (сигнал SIGKILL). Код 1 — это ошибка самого приложения.
В чем разница между ошибками в docker build и docker run?
Ошибка на этапе docker build (сборки образа) означает проблему в инструкциях Dockerfile. Ошибка docker run (запуска контейнера) означает проблему в runtime-окружении или команде запуска внутри уже собранного образа.
Как предотвратить повторение ошибки?
Используйте практики: 1) Пишите скрипты точки входа с обработкой ошибок. 2) Всегда явно указывайте теги версий для базовых образов. 3) Используйте multi-stage build для уменьшения размера и сложности финального образа. 4) Тестируйте образ перед пушем в реестр.