
Диагностика Docker Compose: как найти причину сбоя по шагам
Проверяем Compose-стек от конфигурации и состояния контейнеров до логов, healthcheck, сети, volumes и ресурсов, не удаляя полезную диагностику.
Содержание
При сбое Compose-стека легко начать менять всё сразу: перезапустить Docker, пересоздать контейнеры и очистить старые ресурсы. После этого исчезают сведения, которые могли указать причину. Полезнее идти от наблюдаемого симптома к конкретному слою: конфигурации, процессу, журналу, сети, данным или ресурсам.
Запишите симптом до изменений
Сначала зафиксируйте время, адрес запроса, код ответа и последнюю известную рабочую операцию. «Сайт не работает» недостаточно: 502, таймаут, отказ DNS, перезапуск контейнера и ошибка записи в volume требуют разных проверок.
Не запускайте down, rm -f, prune и массовый restart до сохранения состояния. Если данные меняются, остановите только опасную запись, когда это необходимо для предотвращения дальнейшего повреждения.
Убедитесь, какой проект вы проверяете
Откройте каталог с нужным compose.yaml. Следующие команды показывают имя проекта, развёрнутую конфигурацию и список сервисов без изменения контейнеров:
docker compose ls
docker compose config --quiet
docker compose config --services
docker compose config --images
Ошибка config часто объясняет сбой раньше запуска: отсутствующая переменная, неверный YAML или неподдерживаемое поле. Полный вывод docker compose config может содержать подставленные чувствительные значения, поэтому не публикуйте его целиком в общем тикете.
Посмотрите все контейнеры, включая остановленные
Команда ps -a показывает контейнеры текущего Compose-проекта, в том числе завершившиеся. Формат с JSON удобен для сохранения, если его поддерживает установленная версия Compose:
docker compose ps -a
docker compose ps -a --format json
docker compose top
Обратите внимание на состояние, код завершения, число перезапусков и опубликованные порты. top показывает процессы только работающих контейнеров. Если сервис отсутствует, проверьте профили Compose и условия, с которыми выполнялся up.
Сохраните inspect и журналы
Получите идентификатор проблемного сервиса web и сохраните его полное состояние в файл с ограниченными правами. В inspect могут быть переменные окружения, поэтому каталог диагностики не должен быть общедоступным:
install -d -m 0700 ./diagnostics
container_id="$(docker compose ps -q web)"
docker inspect "$container_id" > ./diagnostics/web-inspect.json
docker compose logs --no-color --timestamps --tail 300 web \
> ./diagnostics/web.log 2>&1
Замените web фактическим именем сервиса. Пустой container_id означает, что контейнер не создан или команда выполняется не в том проекте. В этом случае не запускайте docker inspect ""; вернитесь к docker compose ps -a и конфигурации.
Для краткого ответа о завершении выберите только нужные поля:
docker inspect "$container_id" --format \
'status={{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}} error={{.State.Error}} started={{.State.StartedAt}} finished={{.State.FinishedAt}}'
OOMKilled=true указывает на завершение из-за нехватки памяти в cgroup. Код 137 означает сигнал SIGKILL, но его могли отправить и вручную; сопоставьте поля с журналом ядра и временем действий.
Отделите ошибку образа от ошибки приложения
Если контейнер не создаётся, проверьте доступность и платформу образа. Если создаётся и сразу завершается, читайте команду запуска, код выхода и stderr. Если работает, но не проходит healthcheck, смотрите историю проверок:
docker compose images
docker inspect "$container_id" --format \
'image={{.Config.Image}} entrypoint={{json .Config.Entrypoint}} cmd={{json .Config.Cmd}}'
docker inspect "$container_id" --format '{{json .State.Health}}'
Отсутствие .State.Health не является ошибкой Docker: вероятно, healthcheck не задан. Не добавляйте произвольную проверку во время аварии. Сначала подтвердите, какую команду приложение считает признаком готовности.
Проверьте сеть из того места, где возникает ошибка
localhost внутри контейнера указывает на этот же контейнер, а не на соседний сервис и не на хост. В одной Compose-сети клиент обращается к имени сервиса и его внутреннему порту.
Сначала выведите сети обоих сервисов и их сохранённые параметры:
docker network ls
docker inspect "$(docker compose ps -q web)" \
--format '{{json .NetworkSettings.Networks}}'
docker inspect "$(docker compose ps -q db)" \
--format '{{json .NetworkSettings.Networks}}'
Затем выполните встроенную диагностическую команду самого приложения или отдельного разрешённого контейнера в той же сети. Не устанавливайте отладочные пакеты вручную в рабочий контейнер: изменение исчезнет после пересоздания и запутает сравнение с образом.
Если запрос с хоста проходит, а из web нет, сравните имя сервиса, внутренний порт и общую сеть. Если из web проходит, а снаружи нет, переходите к публикации порта, Nginx и firewall.
Убедитесь, что данные подключены туда, куда ожидает приложение
Выведите mounts проблемного контейнера. Команда только читает список подключённых volumes и каталогов:
docker inspect "$container_id" --format '{{json .Mounts}}'
docker compose config --volumes
docker system df -v
Проверьте путь назначения, режим чтения, имя volume и свободное место. Ошибка Permission denied требует сравнить числовые UID/GID процесса и файлов, а не применять chmod -R 777. Ошибка No space left on device может относиться к месту или inode; проверьте обе величины на хосте.
Не удаляйте «неиспользуемый» volume только по имени. Сначала убедитесь через docker ps -a --filter volume=ИМЯ, что он не нужен остановленному контейнеру и не служит копией для отката.
Сопоставьте сбой с ресурсами хоста
Следующие команды показывают текущую нагрузку контейнеров, память хоста, место на файловых системах и сообщения ядра за последние 30 минут:
docker stats --no-stream
free -h
df -h
df -i
journalctl -k --since '-30 min' | grep -i -E 'oom|out of memory|killed process'
Высокое потребление сейчас не доказывает причину прошлого сбоя, а спокойный снимок не исключает короткий пик. Сверяйте время журнала приложения, FinishedAt, события Docker и сообщения ядра.
Посмотрите события рядом со временем ошибки
Для повторяющегося сбоя откройте поток событий в отдельном терминале и воспроизведите один контролируемый запрос:
docker events \
--filter type=container \
--since '30m'
В выводе видны start, die, restart, oom и изменения health status. Остановите просмотр через Ctrl+C. Если проблема уже произошла, помните, что Docker хранит события ограниченное время; постоянный мониторинг настраивается отдельно.
Исправляйте только подтверждённую причину
| Подтверждённая причина | Следующее действие |
|---|---|
| неверная переменная или Compose-поле | исправить конфигурацию, проверить config, пересоздать один сервис |
| приложение завершается с ошибкой | исправить код или вернуть предыдущий образ |
| healthcheck неверен | проверить команду вручную и скорректировать интервалы или endpoint |
| сервисы в разных сетях | добавить только необходимое сетевое подключение |
| volume подключён не туда | исправить mount после проверки данных и прав |
| OOM подтверждён | найти рост памяти, скорректировать процесс или измеренный лимит |
| Nginx даёт 502 при рабочем loopback | исправить адрес proxy и проверить конфигурацию Nginx |
После одного изменения повторите тот же запрос, который воспроизводил проблему. Затем проверьте соседние функции и сохраните итог: симптом, причина, исправление и способ предотвращения.
Что сохранить перед очисткой
Оставьте compose.yaml, хеш коммита, digest образов, inspect, журналы, время сбоя и точные команды проверки. Только после этого удаляйте тестовые контейнеры или устаревшие файлы конкретными командами. docker system prune -a --volumes не является диагностикой и может лишить вас данных и образа для возврата.
Базовые команды подробно разобраны в уроке о run, logs и inspect. Сетевые проверки продолжены в материале о DNS и портах, причины unhealthy — в главе о healthcheck, а OOM — в статье о лимитах.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Почему не стоит начинать диагностику с docker compose down?
Удаление контейнеров стирает часть их состояния и затрудняет просмотр кода выхода, времени завершения и конфигурации. Сначала сохраните ps, inspect и logs.
Что означает ExitCode 137?
Процесс получил SIGKILL, но код сам по себе не доказывает нехватку памяти. Проверьте OOMKilled, журнал ядра и действия администратора или платформы.
Почему сервис доступен с хоста, но не из соседнего контейнера?
Проверки идут из разных сетевых контекстов. Сверьте сети обоих сервисов, имя сервиса, внутренний порт и адрес, который слушает приложение внутри контейнера.


