Docker Compose
Описываем стек в yaml, поднимаем одной командой. depends_on, healthcheck, profiles, основные команды и граница с Kubernetes.
Зачем compose
Когда у тебя один сервис, docker run хватает. Когда два, три,
пять, команда раздувается до десятка строк с тонной флагов, и
воспроизводить её руками больно.
Compose решает это: один yaml-файл описывает весь стек, одна команда его поднимает.
docker compose up -d
Всё. Сети созданы, volume'ы подмонтированы, контейнеры запущены в правильном порядке.
Минимальный пример
services:
api:
build: .
ports:
- "127.0.0.1:3000:3000"
environment:
DB_HOST: db
REDIS_HOST: cache
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: example # только для локальной разработки; в проде — секрет
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
cache:
image: redis:7-alpine
restart: unless-stopped
volumes:
pgdata:
Что произошло:
- Три сервиса:
api,db,cache. - Сеть создастся автоматически, имя —
<projectname>_default. - Volume
pgdataхранит данные postgres между перезапусками. apiждёт, покаdbпройдёт healthcheck, и только потом стартует.apiобращается к базе по имениdb:5432и к redis поcache:6379- встроенный DNS compose.restart: unless-stopped— если упал, перезапустить; но если ты сам его остановил, не трогать.
Ключевые поля сервиса
| Поле | Что значит |
|---|---|
image | готовый образ из registry |
build | путь к Dockerfile / build-контекст (вместо image) |
ports | публикация портов (см. урок про сети) |
environment | переменные окружения как map или список |
env_file | подгрузить переменные из файла |
volumes | bind или named volume mounts |
depends_on | порядок запуска и (опционально) ожидание healthcheck |
networks | в каких сетях участвует |
restart | политика перезапуска |
healthcheck | проверка живости контейнера |
command | переопределить CMD образа |
entrypoint | переопределить ENTRYPOINT образа |
profiles | в каких профилях сервис активен |
depends_on и healthcheck
Сам по себе depends_on: [db] означает только «запусти db раньше».
Это не значит «жди, пока db готова принимать соединения». Postgres
стартует за несколько секунд, и api успеет упасть с connection refused.
Чтобы дождаться готовности, нужен healthcheck:
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
api:
image: myapp
depends_on:
db:
condition: service_healthy # ← ждёт healthcheck
Возможные condition:
service_started— дефолт, не ждёт здоровья.service_healthy— ждёт, пока healthcheck не пройдёт.service_completed_successfully— ждёт, пока сервис завершится с кодом 0. Полезно для миграций.
Volumes и networks в compose
Named volume объявляется на верхнем уровне и используется в сервисе:
services:
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data # named
- ./initdb:/docker-entrypoint-initdb.d # bind
volumes:
pgdata:
Сети — так же. Если ничего не указано, compose создаёт <project>_default
и все сервисы туда подключены. Если хочешь несколько:
services:
web:
networks: [public, db-net]
db:
networks: [db-net]
admin:
networks: [public]
networks:
public:
db-net:
Внешняя сеть нужна, чтобы общаться между разными compose-проектами:
networks:
shared:
external: true # сеть уже существует, не создавай
Перед этим её надо создать вручную:
docker network create shared.
Profiles: опциональные сервисы
Иногда нужны сервисы, которые не нужны в каждом запуске: admin-панель, worker для тяжёлых задач, инструменты дебага. Профили решают:
services:
api:
image: myapp
db:
image: postgres:16
adminer:
image: adminer
profiles: [admin]
pgcli:
image: dbcli/pgcli
profiles: [debug]
depends_on: [db]
По умолчанию docker compose up поднимет только api и db. Чтобы
включить админку:
docker compose --profile admin up -d
docker compose --profile admin --profile debug up -d
Основные команды
| Команда | Что делает |
|---|---|
docker compose up [-d] | создать и запустить стек |
docker compose down | остановить и удалить контейнеры + сети |
docker compose down -v | то же + удалить named volumes |
docker compose ps | статус сервисов |
docker compose logs [-f] [service] | логи; -f стримит |
docker compose exec <svc> sh | зайти внутрь как docker exec |
docker compose pull | подтянуть новые версии образов |
docker compose build | пересобрать образы из build: |
docker compose config | отрендерить итоговый yaml (после env-подстановок) |
docker compose restart [service] | перезапустить, не пересоздавая |
Типичный апгрейд в проде:
docker compose pull && docker compose up -d
Pull тянет новые образы по тэгам, up -d пересоздаёт контейнеры с
новыми образами. Volume'ы остаются, простой минимальный.
Несколько compose-файлов
Compose автоматически читает compose.yaml (или docker-compose.yml).
Можно указать другой или склеить несколько:
docker compose -f compose.yaml -f compose.prod.yaml up -d
Второй файл переопределяет значения из первого. Типичный паттерн:
compose.yaml— база (одинаково в dev и prod)compose.override.yaml— dev-оверрайды (подхватывается автоматически)compose.prod.yaml— prod-оверрайды (только явный-f)
Граница с Kubernetes
Compose рассчитан на одну машину. Поднял стек локально или на одном сервере и пользуйся. Когда переезжаешь:
- Один сервер, ~5-10 сервисов — compose достаточно.
- Несколько серверов, отказоустойчивость, авто-масштабирование - Kubernetes (или Docker Swarm, но он почти умер).
Про поле deploy: ходит миф, будто оно живёт только в Swarm. Compose v2
часть его исполняет сам: deploy.replicas, deploy.resources.limits и
reservations, deploy.restart_policy. Игнорируются
только Swarm-специфичные ключи: placement, endpoint_mode,
mode: global.
services:
web:
image: myapp:1.0
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
Столько же копий можно поднять и без правки файла:
docker compose up -d --scale web=3
Ловушка тут другая. Если у сервиса зафиксирован container_name или
опубликован статичный порт (- "8080:80"), несколько копий не
поднимутся: имя и порт заняты первой. Для масштабирования убирай
container_name, а порт публикуй диапазоном или не публикуй вовсе,
пуская трафик через reverse proxy.
Compose можно сконвертировать в kubernetes-манифесты через kompose.
Это отправная точка, а не финальный результат: kompose часто генерит
устаревшие apiVersion, переезд всё равно сопровождается переписыванием.
Что важно запомнить
docker compose up -d — одна команда вместо десятка docker run.
yaml в репозитории = воспроизводимый стек.
depends_on без condition: service_healthy ждёт только запуска, не
готовности. Для базы добавляй healthcheck.
down -v сносит volumes. В проде не запускай. Для prod-reset volumes
делаются вручную с явным docker volume rm.
deploy.replicas и deploy.resources работают в обычном compose,
Swarm для них не нужен. Быстрее всего копии поднимает
docker compose up -d --scale web=3, но сначала убери у сервиса
container_name и статичный проброс порта.
В следующем уроке — короткий квиз по всему, что прошли.
Самопроверка
Впишите команду / ключевую строку. Регистр и пробелы не важны.
Дрилл · вопросы как на собесе
Проверь себя без подсказок
Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.
Как ограничить ресурсы контейнера (CPU, RAM, IO, network)?
DOC-023Что такое Docker-compose?
DOC-012Веб-сервер в контейнере отдаёт 502 — где искать?
DOC-031Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс