docker compose (файл)
Формат compose.yaml — сервисы, образы, порты, переменные, тома, сети, depends_on и healthcheck
Compose-файл (compose.yaml или docker-compose.yml) описывает несколько контейнеров, которые запускаются вместе: из какого образа, какие порты открыть, какие переменные и тома подключить, в каком порядке стартовать. docker compose up читает файл и поднимает всё описанное.
В песочнице Docker не установлен. Здесь можно писать и проверять сам файл: yamlschema compose файл сверяет его со схемой Compose Specification и печатает ошибки.
Синтаксис
services:
имя_сервиса:
image: образ:тег
ключ: значение
volumes:
имя_тома:
networks:
имя_сети:
Все сервисы файла по умолчанию попадают в общую сеть, и имя сервиса служит DNS-именем: сервис app достучится до сервиса db по адресу db. Ключ version: в начале файла устарел и игнорируется.
Верхний уровень
| Ключ | Что задаёт |
|---|---|
services | контейнеры — основная часть файла |
volumes | именованные тома (данные переживают пересоздание контейнеров) |
networks | сети; без них создаётся одна сеть default |
secrets / configs | файлы, которые монтируются в контейнеры (/run/secrets/имя) |
name | имя проекта (префикс контейнеров, томов, сетей) |
Ключи сервиса
Образ и запуск
| Ключ | Что задаёт |
|---|---|
image | образ, например postgres:16 |
build | собрать образ: build: . или context, dockerfile, args, target |
command | заменить команду образа (CMD); строкой или списком |
entrypoint | заменить ENTRYPOINT образа |
container_name | фиксированное имя контейнера (тогда сервис нельзя масштабировать) |
user, working_dir | пользователь и рабочий каталог процесса |
restart | no (по умолчанию), always, on-failure, unless-stopped |
profiles | сервис стартует, только если профиль включён: --profile имя |
init | запустить маленький init-процесс, который собирает зомби и передаёт сигналы |
Сеть и порты
| Ключ | Что задаёт |
|---|---|
ports | проброс на хост: "8080:80", "127.0.0.1:8080:80" (только локально), "53:53/udp" |
expose | порт виден другим сервисам, но не хосту (служит документацией) |
networks | к каким сетям подключить сервис |
extra_hosts | дополнительные записи в /etc/hosts контейнера |
Переменные и данные
| Ключ | Что задаёт |
|---|---|
environment | переменные: словарём KEY: value или списком - KEY=value |
env_file | файл (или список файлов) со строками KEY=value |
volumes | имя_тома:/путь — том; ./каталог:/путь — каталог хоста; :ro — только чтение |
tmpfs | каталоги в памяти |
secrets | какие секреты верхнего уровня подключить |
Порядок и здоровье
| Ключ | Что задаёт |
|---|---|
depends_on: [db] | короткая форма: стартовать после контейнера db |
depends_on: {db: {condition: …}} | длинная форма с условием (см. ниже) |
healthcheck.test | команда проверки: ["CMD", "прог", "арг"] или ["CMD-SHELL", "строка для sh"] |
healthcheck.interval / timeout / retries | как часто проверять / сколько ждать ответа / сколько неудач подряд считать «нездоров» |
healthcheck.start_period | время на запуск, когда неудачи ещё не считаются |
deploy.resources.limits | ограничения cpus и memory |
logging | драйвер логов и его параметры (max-size) |
Условия в depends_on:
condition | Ждать, пока зависимость… |
|---|---|
service_started | запустится (то же, что короткая форма) |
service_healthy | станет healthy — нужен healthcheck у зависимости |
service_completed_successfully | завершится с кодом 0 (миграции, подготовка данных) |
Подстановка переменных
В значениях можно ссылаться на переменные окружения и файла .env рядом с compose-файлом: ${TAG}, ${TAG:-latest} — значение по умолчанию, ${TAG:?нужно задать TAG} — ошибка, если переменной нет. $$ — буквальный $.
Команды (где установлен Docker)
| Команда | Что делает |
|---|---|
docker compose up -d | создать и запустить всё в фоне; --build — пересобрать образы |
docker compose down | остановить и удалить контейнеры и сети; -v — и тома |
docker compose ps | состояние сервисов |
docker compose logs -f сервис | логи, с ожиданием новых |
docker compose exec сервис sh | оболочка в работающем контейнере |
docker compose run --rm сервис команда | одноразовый контейнер сервиса |
docker compose config | итоговый файл после подстановки переменных и проверки |
docker compose restart / stop / pull / build | перезапуск / остановка / скачать / собрать образы |
Примеры
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: example
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
web:
image: nginx:${NGINX_TAG:-1.27}
ports:
- "8080:80"
volumes:
- ./site:/usr/share/nginx/html:ro
environment:
- BACKEND_HOST=db
depends_on:
db:
condition: service_healthy
restart: unless-stopped
volumes:
db-data:
# проверить файл по схеме (в песочнице)
yamlschema compose compose.yaml && echo OK
# опечатка в ключе даёт понятную ошибку, например:
# compose.yaml: services/web: Unevaluated properties are not allowed ('enviroment' was unexpected)
# посмотреть структуру файла: имена сервисов и их порты
yq '.services | keys' compose.yaml
yq '.services.web.ports' compose.yaml
# там, где есть Docker:
# docker compose config # итоговый файл после подстановки переменных
# docker compose up -d # поднять в фоне
# docker compose logs web # логи одного сервиса
# docker compose down # остановить и удалить контейнеры
Подводные камни
depends_onв короткой форме ждёт только старта контейнера, а не готовности программы внутри. База может ещё инициализироваться, когда приложение уже пытается подключиться. Чтобы ждать готовности, нуженhealthcheckу зависимости иcondition: service_healthyу зависимого сервиса.depends_onвлияет только на запуск через compose. Если зависимость упадёт позже, зависимый сервис об этом не узнает: приложение само должно уметь переподключаться.- Порты бери в кавычки. Некоторые YAML 1.1-парсеры читают
22:22как число в шестидесятеричной записи (1342). Строка"22:22"однозначна. - Порядок в
ports—хост:контейнер."8080:80"открывает порт 8080 на хосте и ведёт его на 80 внутри контейнера, не наоборот. Без адреса порт слушается на всех интерфейсах хоста. - Именованный том нужно объявить в верхнеуровневом
volumes:. Путь, начинающийся с./или/, — это каталог хоста, а не том. - Внутри сети используй имя сервиса и порт контейнера (
db:5432), а неlocalhostи не порт хоста:localhostв контейнере — это сам контейнер. environmentважнееenv_file. Если переменная задана в обоих местах, победитenvironment.CMDиCMD-SHELLразличаются.["CMD", "pg_isready -U postgres"]ищет программу с пробелами в имени. Строку с аргументами передавай черезCMD-SHELLили разбивай на элементы списка.- Схема ловит опечатки в ключах, но не смысл.
yamlschemaне проверит, объявлен ли том, допустимо ли значениеrestart, существует ли образ и свободен ли порт.