Docker Compose для разработки: типичные ошибки и решения
Контейнеры запустились, но приложение не видит базу, изменения в коде пропали, а после очистки исчезли данные. Разбираем типичные ошибки Docker Compose в локальной разработке и показываем, как настроить зависимости, порты и тома.

В Docker Compose приложение может стартовать раньше базы, подключаться к ней по неверному адресу или терять данные после пересоздания контейнера. Исправление обычно не требует сложной архитектуры: важно правильно выбрать адрес сервиса, описать готовность зависимости и понимать, что именно монтируется в контейнер. Примеры ниже рассчитаны на Docker Compose v2 и формат Compose Specification.
Сначала проверьте конфигурацию, потом запускайте
В Compose файл описывает сервисы, сети и тома; сам контейнер — только запущенный экземпляр сервиса. Это различие объясняет часть ошибок: контейнер можно удалить и создать заново, а данные в томе могут остаться. Перед разбором убедитесь, что используете команду с пробелом — docker compose, а не устаревшую запись через дефис, и проверьте версию командой:
docker compose version
У Compose v2 поле version в начале YAML больше не задаёт версию формата. В новых файлах его обычно опускают: Compose ориентируется на Compose Specification. Если конфигурация ведёт себя не так, как ожидаете, сначала попросите Compose разобрать её:
docker compose config
Команда выводит итоговую конфигурацию с учётом подстановок. Если здесь ошибка, проблема не в запуске приложения: Compose пока не может корректно прочитать файл.
Ошибка 1. Приложение подключается к базе через localhost
Внутри контейнера localhost указывает на этот же контейнер. Поэтому адрес базы данных localhost:5432 из контейнера приложения обычно ведёт не к сервису PostgreSQL, а обратно в приложение. В Docker Compose сервисы в одной сети находят друг друга по имени сервиса: для сервиса db адрес будет db:5432.
Снаружи Compose — например, в клиенте баз данных на вашем компьютере — используют опубликованный порт. Внутри сети контейнеров нужен внутренний порт сервиса, а не порт, выбранный для доступа с компьютера.
Правило, которое экономит время: из контейнера обращайтесь к соседу по имени сервиса; с компьютера — по адресу опубликованного порта.
Если приложение запускается не в контейнере, а прямо на хосте, оно не сможет использовать имя db без отдельной настройки DNS. Для такого сценария подключение обычно настраивают через опубликованный порт.
Ошибка 2. depends_on принимают за проверку готовности
Обычный depends_on задаёт порядок запуска, но не означает, что база уже принимает соединения. Контейнер PostgreSQL может считаться запущенным, пока база ещё выполняет инициализацию. Если приложение в этот момент попробует подключиться один раз и завершится, Compose не обязан автоматически повторить подключение за него.
Для локального проекта можно описать healthcheck базы и попросить Compose запускать зависимый сервис после статуса healthy. Это не отменяет повторных попыток подключения в самом приложении: при перезапуске базы соединение всё равно может оборваться.
services:
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
app:
build: .
depends_on:
db:
condition: service_healthy
Переменную POSTGRES_PASSWORD задайте для локального окружения и не коммитьте файл с реальным паролем. Синтаксис ${VAR:?message} заставляет Compose сообщить об отсутствующей переменной, а не молча подставить пустое значение.
Ошибка 3. Не различают опубликованный порт и порт контейнера
Запись вида 5433:5432 означает: подключение с хоста к порту 5433 перенаправляется на порт 5432 внутри контейнера. Если приложение тоже находится в Compose-сети, оно обращается к db:5432, а не к db:5433. Изменение левой части полезно, когда нужный порт занят на компьютере; оно не меняет порт PostgreSQL внутри контейнера.
Чтобы база разработки не слушала на всех сетевых интерфейсах хоста, ограничьте публикацию loopback-адресом:
ports:
- "127.0.0.1:5433:5432"
Теперь клиент на компьютере подключается к 127.0.0.1:5433, а соседний контейнер — к db:5432. Если порт занят, Compose сообщит об ошибке привязки; смените порт хоста или остановите процесс, который его использует.
Ошибка 4. Bind mount затирает файлы контейнера
Монтирование папки проекта удобно: изменения на хосте сразу видны в контейнере. Но bind mount поверх каталога, где при сборке установили зависимости, скрывает содержимое этого каталога из образа. Например, если смонтировать весь проект в /app, папка зависимостей, подготовленная при сборке в /app, может исчезнуть из вида. Тогда приложение жалуется, что не находит пакет или команду.
Решение зависит от стека и цели. Можно хранить зависимости в отдельном томе или устанавливать их при запуске контейнера, но второй путь часто замедляет старт. Не копируйте конфигурацию чужого проекта вслепую: сначала проверьте, какие именно каталоги затирает bind mount и где образ хранит установленные зависимости.
Ошибка 5. Удаляют контейнеры вместе с нужными данными
База данных, чей каталог данных существует только внутри контейнера, теряет данные при пересоздании контейнера. Для локального проекта обычно используют именованный том: Compose управляет им отдельно от жизненного цикла контейнера.
services:
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Обычная команда docker compose down останавливает проект и удаляет его контейнеры, но не удаляет именованные тома. Команда docker compose down -v удаляет и тома, поэтому данные базы пропадут. Перед очисткой проверьте, что в томе нет единственной копии нужной базы.
Какой способ ожидания базы выбрать
У этих решений разная цена. Проверка готовности помогает контролировать порядок старта, а повторные подключения защищают приложение от временных сбоев уже после запуска.
| Подход | Что решает | Цена и ограничение |
|---|---|---|
Обычный depends_on | Запускает сервисы в заданном порядке | Не ждёт, пока база начнёт принимать соединения |
healthcheck и condition: service_healthy | Позволяет ждать успешной проверки сервиса перед запуском зависимого | Нужно поддерживать подходящую проверку; она не заменяет обработку обрывов соединения |
| Повторные подключения в приложении | Помогают пережить задержку старта и временное отключение базы | Требуют настройки в самом приложении и не заменяются настройкой Compose |
Когда что выбирать и что ломается
Для локальной базы используйте healthcheck, если приложение стартует в Compose и должно дождаться инициализации. Если приложение запускается с хоста, настраивайте подключение через опубликованный порт. Для устойчивости к перезапускам базы добавьте повторные попытки соединения на стороне приложения — особенно если те же настройки используют в тестовом окружении.
- Ошибка подключения к localhost. Проверьте, где запущено приложение. Из контейнера используйте имя сервиса базы и её внутренний порт.
- Compose сообщает, что порт занят. Выберите другой порт хоста или остановите конфликтующий процесс. Не меняйте внутренний порт без необходимости.
- Зависимости пропали после монтирования проекта. Проверьте, не перекрывает ли bind mount каталог установки зависимостей.
- База снова пустая после перезапуска. Убедитесь, что каталог данных подключён к именованному тому и вы не удаляли том командой с флагом
-v.
Термин. Bind mount — подключение конкретной папки с компьютера к пути внутри контейнера. Именованный том — отдельное хранилище, которым управляет Docker; оно не привязано напрямую к папке проекта.
Что сделать дальше
После правок выполните docker compose config, затем запустите сервисы командой docker compose up. Проверьте логи через docker compose logs и отдельно проверьте соединение с базой из того же окружения, где работает приложение. Убедитесь, что данные переживают пересоздание контейнера, но не запускайте очистку томов, пока не проверили резервную копию.
Инфобез и 152-ФЗ: Аудит политик конфиденциальности, правила сбора cookie.
Спросить за 20 ₽Источники: Docker Compose: управление порядком запуска и готовностью сервисов, Docker Compose file reference: services
Частые вопросы
Почему приложение в контейнере не подключается к localhost:5432?
Разве depends_on не ждёт, пока база будет готова?
Удалит ли docker compose down мою базу?
Почему изменения в проекте ломают приложение после добавления volumes?
Эти примеры подходят для другой версии Docker Compose?
Можно ли использовать такой compose-файл в продакшене?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.