Вы запускаете 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
Внутри контейнера проверьте:
- Существуют ли все необходимые файлы
- Правильно ли установлены разрешения
- Доступны ли переменные окружения (команда `env`)
- Можете ли вы вручную запустить основной процесс
Шаг 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 ваш_образ`. Но сначала устраните причину падения!