Docker Compose для локальної розробки: healthcheck, профілі та override
Як описати застосунок з базою, кешем і чергою так, щоб новий розробник запускав усе однією командою, а сервіси стартували в правильному порядку.
«У мене працює» часто означає «у мене стоїть Postgres 14, а в тебе 17». Docker Compose описує все оточення в одному файлі: застосунок, базу, кеш, чергу — з фіксованими версіями й налаштуваннями. Новий розробник клонує репозиторій і запускає docker compose up.
Базовий compose.yaml
services:
api:
build: .
env_file: .env
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
REDIS_URL: redis://cache:6379/0
ports:
- "127.0.0.1:8000:8000"
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
db:
image: postgres:17-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Задайте POSTGRES_PASSWORD у .env}
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
cache:
image: redis:8-alpine
volumes:
pgdata:Що тут важливо:
- Ім'я сервісу = DNS-ім'я. Застосунок підключається до
db:5432, а не доlocalhost. ${VAR:?повідомлення}— Compose відмовиться стартувати, якщо змінну не задано, і покаже зрозуміле повідомлення.127.0.0.1:8000:8000— порт відкритий лише для вашої машини, а не для всієї локальної мережі.- Іменований том
pgdata— дані бази переживутьdocker compose down.
depends_on не чекає готовності — якщо не попросити
Звичайний depends_on: [db] гарантує лише, що контейнер бази запущено, а не що Postgres готовий приймати з'єднання. Застосунок стартує першим, падає з «connection refused» — класика.
condition: service_healthy разом з healthcheck вирішує проблему: Compose чекає, поки перевірка стане зеленою.
ПорадаНавіть з healthcheck застосунок має вміти перепідключатися до бази. У продакшені база теж іноді перезапускається — і сервіс не повинен через це падати назавжди.
Override-файли: різні налаштування для різних випадків
Compose автоматично підхоплює compose.override.yaml поруч з основним файлом. Туди зручно класти те, що потрібно лише локально:
# compose.override.yaml — лише для розробки
services:
api:
build:
target: dev
command: uvicorn app.main:app --host 0.0.0.0 --reload
volumes:
- ./app:/srv/app # код з хоста — зміни видно без перезбірки
environment:
LOG_LEVEL: debugДля інших оточень файли вказують явно:
docker compose -f compose.yaml -f compose.ci.yaml up -dПрофілі: опціональні сервіси
Не кожному розробнику щодня потрібні Kafka, Grafana чи емулятор S3. Позначте їх профілем:
services:
mailpit:
image: axllent/mailpit
ports: ["127.0.0.1:8025:8025"]
profiles: [mail]
grafana:
image: grafana/grafana
profiles: [observability]docker compose up -d # лише основні сервіси
docker compose --profile mail up -d # плюс локальна поштаWatch: автооновлення без bind-mount
Bind-mount коду на Windows і macOS буває повільним. Альтернатива — develop.watch: Compose стежить за файлами й синхронізує або перезбирає контейнер.
services:
web:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: package.jsondocker compose up --watchКоманди на кожен день
docker compose up -d --build # зібрати і запустити у фоні
docker compose ps # стан і healthcheck
docker compose logs -f api # логи одного сервісу
docker compose exec db psql -U app # консоль у працюючому контейнері
docker compose run --rm api pytest # одноразова команда в новому контейнері
docker compose down # зупинити (томи залишаються)
docker compose down -v # зупинити і ВИДАЛИТИ томи з данимиОбережно
down -vвидаляє іменовані томи, тобто локальну базу з усіма даними. Перед цим переконайтесь, що вони вам не потрібні.
Застосунок у контейнері намагається підключитися до бази за адресою localhost:5432 і отримує «connection refused». Чому?
Усередині контейнера localhost — це сам контейнер застосунку, а не хост і не контейнер бази. Треба використовувати ім'я сервісу з compose-файлу: db:5432.
Збережіть статтю собі
Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.
Увійти через Google Інші способи входу