3: Полноценная среда разработки с Docker Compose
Цель: Запустить App + PostgreSQL + Redis через Docker Compose. Освоить healthcheck, depends_on, volumes для данных, hot reload для кода.
Запускать контейнеры по одному (docker run) неудобно, когда их становится много. В этом уроке мы создадим реалистичный стек: Node.js приложение, которое хранит счетчик просмотров в Redis.
Мы научимся связывать контейнеры, управлять зависимостями и использовать “Горячую перезагрузку” (Hot Reload) без пересборки образов.
Подготовка
В папке docker-lesson-3:
-
package.json:{ "dependencies": { "express": "^4.18.2", "redis": "^4.6.7" } } -
index.js:const express = require('express'); const { createClient } = require('redis'); const app = express(); // Обращаемся к Redis по имени сервиса в Compose: "redis-db" const client = createClient({ url: 'redis://redis-db:6379' }); client.on('error', err => console.log('Redis Client Error', err)); app.get('/', async (req, res) => { const count = await client.incr('hits'); res.send(`Hello! This page has been viewed ${count} times.`); }); const start = async () => { await client.connect(); app.listen(3000, () => console.log('Server running on 3000')); }; start(); -
Dockerfile(для разработки):FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm install # Код НЕ копируем, мы его примонтируем через Compose! CMD ["node", "index.js"]
Магия Compose
Создайте файл compose.yaml:
services:
# Наше приложение
web:
build: .
ports:
- "3000:3000"
volumes:
# Hot Reload: монтируем текущую папку внутрь контейнера
- ./:/app
# Важно: исключаем node_modules, чтобы использовать те, что внутри контейнера (Linux),
# а не те, что на хосте (Windows/Mac)
- /app/node_modules
depends_on:
redis-db:
condition: service_healthy
environment:
- NODE_ENV=development
# База данных
redis-db:
image: redis:alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5Запуск и Работа
-
Поднимаем стенд:
docker compose up # Если хотите в фоне: docker compose up -d -
Проверка: Откройте
http://localhost:3000. Вы увидите: “This page has been viewed 1 times”. Обновите страницу: “… 2 times”. Это значит, что Node.js успешно соединился с Redis. -
Hot Reload (Проверка Bind Mount): Не останавливая контейнеры, откройте
index.jsв редакторе и измените текст:res.send('UPDATED! View count: ${count}');Сохраните файл.Вам придется перезапустить процесс Node.js, чтобы подхватить изменения (так как мы не используем nodemon).
docker compose restart webОбновите браузер. Текст изменился! Мы изменили код в контейнере, не пересобирая образ.
Уборка
Чтобы удалить все контейнеры и сеть проекта:
docker compose downИтоги
- Service Discovery: Контейнеры видят друг друга по именам (
redis-db). - Depends On + Healthcheck:
webне запустился, покаredisне сказал “PONG”. Это предотвращает ошибки подключения при старте. - Volumes Development: Мы редактируем код на хосте, а выполняется он в контейнере.
Типичные ошибки
| Ошибка | Симптом | Решение |
|---|---|---|
| App стартует раньше БД | ECONNREFUSED при подключении к PostgreSQL | depends_on: db: condition: service_healthy |
docker compose down удалил данные | «Где моя база?» | Данные в named volume выживают. -v удаляет volumes (осторожно!) |
| Порт уже занят | bind: address already in use | Другой контейнер или процесс на этом порту. docker ps или lsof -i :5432 |
| Изменения в коде не видны | Hot reload не работает | Проверить: volume примонтирован? WATCHPACK_POLLING=true для Next.js? |