DockerSeniorExperience
Представьте, контейнер работает локально, но падает или не отвечает на сервере. Как вы будете разбираться?
Проверяем по порядку: тот ли образ (digest), логи и ExitCode на сервере, сравниваем env vars и HostConfig, воспроизводим с prod-конфигурацией интерактивно, проверяем ресурсы хоста (disk, memory, dmesg OOM). Самые частые причины: floating tag, отсутствующие env vars, memory limit, архитектура образа.
Почему «работает локально» — это не информация
Контейнер работает локально, но падает на сервере. Первый шаг — собрать конкретные данные, а не делать предположения. «Падает» может означать разное: crash при старте, OOM kill, timeout healthcheck, зависание без ответа.
Шаг 1: убедиться, что это тот же образ
# Локально:
docker inspect my-image --format '{{.Id}}'
# На сервере:
docker inspect my-image --format '{{.Id}}'
Digest должен совпадать. Если отличается — деплоится другой образ (floating tag, обновление в registry).
Шаг 2: проверить логи на сервере
docker logs my-container --tail 100 --timestamps
docker inspect my-container --format '{{json .State}}'
# Проверить OOMKilled, ExitCode, Error
Шаг 3: сравнить конфигурацию запуска
# На сервере:
docker inspect my-container --format '{{json .HostConfig}}'
docker inspect my-container --format '{{json .Config.Env}}'
Типичные расхождения между локальным и серверным запуском:
- Переменные окружения: локально есть
.envфайл, на сервере — нет. DB_HOST, API_KEY, SECRET_KEY могут отсутствовать или быть неверными. - Сеть: локально контейнер обращается к
host.docker.internalили к другому контейнеру по имени сервиса. На сервере сеть может быть другой. - Ресурсы: memory limit на сервере ниже. Проверьте
docker statsиdmesg | grep oom. - Архитектура: образ собран под amd64, сервер arm64 (или наоборот). Проверьте
docker inspect my-image --format '{{.Architecture}}'.
Шаг 4: воспроизвести на сервере с минимальными отличиями
# Запустить интерактивно с теми же переменными что в prod:
docker run --rm -it \
--env-file /etc/my-app/prod.env \
--memory 512m \
my-image sh
# Внутри проверить:
env | grep -E 'DB|SECRET|API'
curl -v http://db:5432 # доступна ли зависимость?
df -h # есть ли место на диске?
Шаг 5: проверить хост
df -h /var/lib/docker # место для overlay filesystem
free -h # доступная память
systemctl status docker # состояние daemon
dmesg | tail -50 # kernel messages (OOM, segfault)
Подводные камни
- Floating tag:
:latestили:mainна сервере может указывать на другой образ, чем локально. Всегда деплоить по digest. - Разные версии Docker Engine: локально Docker Desktop 4.x, на сервере Docker CE 23.x — поведение networking и cgroups может различаться.
- seccomp и AppArmor: на сервере могут быть профили безопасности, которых нет локально. Если приложение использует системные вызовы, заблокированные профилем — это silent failure.
- Объём логов: если logging driver настроен на
json-fileбез ротации, диск заполняется, и контейнер падает из-за нехватки места. На сервере это критичнее, чем локально. - Timezone: сервер может быть в UTC, локальная машина — нет. Если приложение зависит от системного времени — учитывайте это.
What hurts your answer
- Сразу обвинять Docker, не проверив соседние слои системы
- Чинить симптом без минимального воспроизведения и evidence
- Не учитывать версии, конфигурацию, окружение и recent changes
What they're listening for
- Умеет локализовать проблему вокруг Docker
- Двигается от симптома к гипотезам и проверкам
- Отличает баг инструмента от ошибки использования или окружения