Docker Compose для локальной разработки: рабочая схема
Связка Vite, Node.js и PostgreSQL в Docker Compose: исходники меняются без пересборки, зависимости не смешиваются с файлами хоста, база переживает перезапуск. Показываем конфигурацию, запуск и типичные ловушки.

Локальная среда, которая не спорит с вашим компьютером
Для проекта на Vite, Node.js 22 и PostgreSQL 16 можно собрать среду разработки на Compose без ручной установки Node и базы на хосте. Исходники будут обновляться сразу после сохранения, зависимости останутся внутри контейнера, а данные PostgreSQL не исчезнут после остановки. Ниже — конфигурация для Docker Compose v2 и существующего Vite-проекта с файлом package-lock.json.
Понадобятся Docker Desktop или Docker Engine с плагином Compose v2, каталог проекта и права запускать Docker. В проекте должны быть скрипт dev и зафиксированные npm-зависимости. Создайте в корне файл .env и добавьте в него POSTGRES_PASSWORD=YOUR_DB_PASSWORD. Это заглушка: замените её локальным значением и не добавляйте файл с паролем в репозиторий.
Конфигурация: исходники на хосте, сервисы в контейнерах
Создайте в корне compose.yaml. В примере Vite слушает стандартный порт 5173, а приложение получает адрес базы через отдельные переменные. Само приложение должно читать эти переменные; если сейчас оно ждёт строку подключения, настройте её в коде проекта отдельно.
services:
app:
image: node:22-bookworm-slim
working_dir: /workspace
command: sh -c "npm ci && npm run dev -- --host 0.0.0.0"
ports:
- "127.0.0.1:5173:5173"
volumes:
- .:/workspace
- node_modules:/workspace/node_modules
environment:
DB_HOST: db
DB_PORT: "5432"
DB_NAME: app
DB_USER: app
DB_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
ports:
- "127.0.0.1:5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
volumes:
node_modules:
postgres_data:
Поле version здесь намеренно отсутствует: актуальный Compose использует Compose Specification, и это поле больше не требуется. Зафиксированные основные версии образов упрощают повтор запуска, но не закрепляют конкретный патч-релиз. Если команде нужна полная воспроизводимость, отдельно согласуйте и зафиксируйте версии образов по digest.
Почему здесь три разных вида хранения
Bind mount* .:/workspace показывает контейнеру файлы проекта с компьютера. Поэтому правка исходника видна сразу, без пересборки образа. Отдельный именованный том для node_modules не даёт содержимому этой папки с хоста скрыть установленные в контейнере зависимости. Ещё один том хранит каталог данных PostgreSQL независимо от жизненного цикла контейнера.
| Что хранится | Решение | Плата за выбор |
|---|---|---|
| Исходники | Bind mount каталога проекта | Файлы доступны контейнеру; скорость файлового обмена зависит от ОС и Docker Desktop. |
| npm-зависимости | Именованный том node_modules | Зависимости не устанавливаются на хост, но после смены lock-файла их нужно установить заново. |
| Данные базы | Именованный том postgres_data | Данные сохраняются между запусками; для полностью чистой базы том придётся удалить отдельно. |
| Код внутри образа | COPY при сборке образа | Чище для развёртывания, но при локальной разработке изменения кода требуют пересборки. |
Для локальной разработки контейнер должен изолировать зависимости и сервисы, а не прятать от вас исходники за обязательной пересборкой.
Запуск и проверка
- Проверьте конфигурацию. Выполните
docker compose configв корне проекта. Если Compose сообщает, чтоPOSTGRES_PASSWORDне задан, проверьте наличие.envрядом сcompose.yaml. Успешная проверка выводит итоговую конфигурацию без сообщения об ошибке. - Поднимите сервисы. Запустите
docker compose up. Первый старт скачает образы и выполнитnpm ci, поэтому займёт дольше последующих. В логах приложения должна появиться информация о запуске Vite; у базы — сообщение о готовности принимать подключения. - Откройте приложение. Перейдите на
http://localhost:5173. Страница должна загрузиться, а изменение исходного файла — отобразиться после обновления или через механизм HMR Vite. - Проверьте соединение с базой. Из приложения подключайтесь к хосту
dbи порту5432. Если используете клиент базы данных на компьютере, подключайтесь кlocalhost:5432. В первом случае имяdb— адрес сервиса во внутренней сети Compose, а не имя, которое знает ваш хост.
Остановить сервисы можно сочетанием Ctrl+C, затем выполните docker compose down. Эта команда удалит контейнеры и сеть, но оставит именованные тома. Для нового запуска используйте docker compose up.
Что чаще всего ломается
- Vite запущен, но браузер не открывает страницу. Проверьте, что в команде есть
--host 0.0.0.0. Без этого сервер может слушать только loopback-интерфейс внутри контейнера, куда проброс порта с хоста не попадёт. - В контейнере не находится пакет, который есть на хосте. Это часто происходит, когда зависимости установили только на компьютере, а том
node_modulesпуст. Перезапустите сервис: команда в конфигурации выполнитnpm ciпо lock-файлу внутри контейнера. - Приложение не подключается к PostgreSQL. Внутри Compose используйте хост
db, неlocalhost: последний указывает на сам контейнер приложения. Убедитесь также, что приложение ожидает здоровье базы или повторяет попытки подключения. - Порт уже занят. Если Docker не может опубликовать 5173 или 5432, остановите другой сервис на этом порту либо измените левую часть записи в
ports. Например, для базы можно опубликовать другой порт хоста, оставив внутренний порт 5432 без изменений. - После правки зависимостей поведение не изменилось. Пересоздание контейнера не всегда означает сброс именованного тома. Перезапустите установку зависимостей через
docker compose run --rm app npm ci, затем поднимите сервисы снова.
Термин. Именованный том — хранилище, которым управляет Docker. В отличие от bind mount, он не привязан к конкретной папке проекта на хосте; поэтому зависимости контейнера и данные базы не смешиваются с файлами разработчика.
Границы этой схемы
depends_on с условием service_healthy помогает не запускать приложение раньше, чем база станет готовой при старте Compose. Но это не гарантирует, что база никогда не перезапустится позже. Клиент приложения должен корректно обрабатывать временный отказ соединения. Также пароль в .env годится для локальной среды, но не заменяет секрет-хранилище и политику доступа в продакшене.
На Linux bind mount обычно работает напрямую. В Docker Desktop на macOS и Windows обмен файлами проходит через дополнительный слой, поэтому большие проекты могут обновляться медленнее. Если Vite не замечает изменения файлов, сначала проверьте настройки наблюдения за файлами в документации используемой версии Vite и Docker Desktop: универсальный параметр для всех ОС и версий здесь обещать нельзя.
Что делать дальше
Сначала проверьте, что команда может поднять проект с нуля: клонировать репозиторий, создать локальный .env и выполнить docker compose up. Затем договоритесь, какие данные должны переживать перезапуск, и отдельно проверьте сценарий сброса базы. В рабочем процессе полезно наблюдать за временем запуска, ошибками подключения и размером томов — так локальная среда не превратится в ещё один источник сюрпризов.
Генератор изображений: Иллюстрация, обложка, баннер, схема — по текстовому описанию, без исходного фото.
Спросить за 20 ₽Источники: Docker Compose: управление порядком запуска и готовностью сервисов, Docker Compose file reference
Частые вопросы
Нужно ли добавлять поле version в compose.yaml?
Почему приложение должно подключаться к базе по адресу db, а не localhost?
Как обновить зависимости после изменения package-lock.json?
Исчезнут ли данные базы после docker compose down?
Что делать, если у меня другая версия Node.js или PostgreSQL?
Безопасно ли публиковать порт базы на компьютере?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.