С чего начать Первые шаги трек · 15 ступеней
Linux Labs

docker compose — стек контейнеров одним файлом

13 мин Docker Compose 2.40 · Docker 29.1 · Ubuntu 24.04

docker compose описывает стек контейнеров с сетью, томами и переменными в compose.yaml и поднимает его одной командой.

Шпаргалка

8 команд Версия для печати
  • sudo docker compose up -d поднять всё из compose.yaml
  • sudo docker compose ps контейнеры проекта и здоровье
  • sudo docker compose logs -f backend логи одного сервиса
  • sudo docker compose exec proxy sh оболочка в сервисе
  • sudo docker compose config -q проверить файл
  • sudo docker compose restart proxy перезапустить сервис
  • sudo docker compose down удалить контейнеры и сеть
  • sudo docker compose down -v … и тома вместе с данными

Обзор

docker compose — плагин Docker для стека из нескольких контейнеров. Сервисы, их образы, порты, тома, переменные и порядок запуска описаны в одном файле compose.yaml. docker compose up -d создаёт по нему сеть, тома и контейнеры, down убирает их. Всё, что делает compose, можно сделать и руками командами docker — файл избавляет от длинных docker run и порядка запуска в голове.

На машине тренажёра — Docker Compose 2.40, команда пишется через пробел: docker compose. Старой программы docker-compose через дефис нет. Как и остальные команды Docker, compose идёт через sudo.

Compose ищет compose.yaml (или docker-compose.yml) в текущем каталоге. Другой файл — -f stack.yaml.

Файл compose.yaml

Стек из двух сервисов: backend отдаёт страницу из тома, proxy — nginx перед ним, единственный с портом наружу.

yaml
services:
  backend:
    image: busybox
    command:
      - sh
      - -c
      - >-
        echo "<h1>$$GREETING</h1>" > /www/index.html &&
        exec httpd -f -p 8000 -h /www
    environment:
      GREETING: ${GREETING:-hello}
    volumes:
      - data:/www
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "/dev/null",
             "http://127.0.0.1:8000/"]
      interval: 5s
      timeout: 3s
      retries: 3
  proxy:
    image: nginx:alpine
    ports:
      - "8090:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      backend:
        condition: service_healthy
    restart: unless-stopped
volumes:
  data:

Рядом лежит nginx.conf с proxy_pass http://backend:8000; — nginx ходит к соседу по имени сервиса.

Ключ сервиса Что задаёт То же в docker run
image образ имя образа
build каталог с Dockerfile — собрать образ docker build
command команда вместо CMD образа слова после образа
environment переменные окружения -e
ports "хост:контейнер" -p
volumes том:/путь или ./каталог:/путь -v
depends_on кого запускать раньше —
healthcheck проверка здоровья --health-cmd
restart политика перезапуска --restart

Ключ volumes верхнего уровня объявляет именованные тома, networks — дополнительные сети. Синтаксис — YAML: отступы пробелами, табуляция запрещена. Порт пиши в кавычках: "8090:80".

Том, созданный заранее (docker volume create keep), подключают как внешний — compose его не создаёт и не удаляет:

yaml
volumes:
  data:
    external: true
    name: keep

Внешнего тома нет — up падает: external volume "keep" not found. Без external: true compose создаёт свой пустой том <проект>_data, даже если рядом лежит keep с данными.

Без ключа networks все сервисы проекта в одной сети. Свои сети объявляют в networks: верхнего уровня и перечисляют у сервиса: networks: [front, back]. Имя сервиса видно только в общих сетях: web из сети front не находит db из back (server can't find db), а app, подключённый к обеим, видит обоих.

Проект: имена контейнеров, сети и томов

Файл описывает проект. Имя проекта — имя каталога, где лежит compose.yaml; от него строятся имена всего, что создаёт compose:

text
student@ubuntu:~/stack$ sudo docker compose up -d
 Network stack_default  Created
 Volume stack_data  Created
 Container stack-backend-1  Created
 Container stack-proxy-1  Created
 Container stack-backend-1  Started
 Container stack-backend-1  Waiting
 Container stack-backend-1  Healthy
 Container stack-proxy-1  Started
Что Имя
сеть <проект>_default — stack_default
том data <проект>_data — stack_data
контейнер сервиса <проект>-<сервис>-1 — stack-backend-1

Все сервисы проекта в одной сети, и каждый виден соседям по имени сервиса:

text
student@ubuntu:~/stack$ sudo docker compose exec proxy nslookup backend
Server:         127.0.0.11
…
Name:   backend
Address: 172.18.0.2

Команды compose работают с сервисами по их именам из файла: logs backend, exec proxy, restart proxy. Их нужно запускать из каталога проекта — или с -f и -p.

Переменные

${GREETING:-hello} в файле compose подставляет сам, до запуска контейнеров: значение переменной окружения или hello, если её нет. Переменные берутся из файла .env рядом с compose.yaml:

text
student@ubuntu:~/stack$ echo GREETING=privet > .env
student@ubuntu:~/stack$ sudo docker compose up -d
 Container stack-backend-1  Recreate
 Container stack-backend-1  Recreated
 Container stack-proxy-1  Running
…
student@ubuntu:~/stack$ curl -s localhost:8090/
<h1>privet</h1>

up -d пересоздал только backend: у него поменялось окружение. proxy не менялся и продолжил работать.

Переменная оболочки перед sudo до compose не доходит: sudo чистит окружение, и GREETING=privet sudo docker compose up -d ничего не меняет. Пиши значение в .env.

$$ — буквальный знак доллара: $$GREETING в command compose не трогает, его раскроет оболочка внутри контейнера. Что получилось после подстановки, показывает docker compose config.

Порядок запуска и healthcheck

depends_on: [backend] только задаёт порядок: proxy стартует после того, как контейнер backend запущен, — готов он отвечать или нет. Ждать готовности умеет condition: service_healthy — тогда compose ждёт статуса healthy от проверки здоровья backend.

healthcheck.test — команда внутри контейнера: код 0 — здоров. Docker выполняет её каждые interval, ждёт не дольше timeout, после retries неудач подряд ставит unhealthy. Статус виден в ps:

text
student@ubuntu:~/stack$ sudo docker compose ps
NAME              …   SERVICE   …   STATUS
stack-backend-1   …   backend   …   Up 6 seconds (healthy)
stack-proxy-1     …   proxy     …   Up Less than a second

У proxy в столбце PORTS — 0.0.0.0:8090->80/tcp, [::]:8090->80/tcp.

Команда проверки должна быть в образе: в busybox и alpine есть wget, curl нет.

Команды стека

Команда Что делает
up -d создаёт недостающее и пересоздаёт сервисы, чьё описание изменилось (Recreate), остальные не трогает (Running)
restart backend перезапускает тот же контейнер: окружение и ключи прежние
stop, start останавливает и запускает, не удаляя контейнеры
ps статус контейнеров: Up … (healthy), Restarting (1) …, Exited (137)
logs backend вывод сервиса; без имени — всех сервисов
down удаляет контейнеры и сеть проекта; именованные тома остаются
down -v то же вместе с томами проекта

Правку compose.yaml или .env применяет только up -d. restart перезапускает процесс в старом контейнере: файлы с хоста он прочитает заново, а переменные останутся прежними.

text
student@ubuntu:~/nets$ echo GREETING=privet > .env
student@ubuntu:~/nets$ sudo docker compose restart app
student@ubuntu:~/nets$ sudo docker compose exec app env | grep GREETING
GREETING=hello
student@ubuntu:~/nets$ sudo docker compose up -d
 Container nets-app-1  Recreate
…
student@ubuntu:~/nets$ sudo docker compose exec app env | grep GREETING
GREETING=privet

Ключи

20

Основные подкоманды и ключи — в таблице ниже. Полный список — docker compose --help и docker compose <команда> --help.

Ключ Что делает Пример
up Создать и запустить всё из compose.yaml; изменённые сервисы пересоздаются, остальные не трогает. docker compose up -d
-d --detach Запустить в фоне и вернуть приглашение; без него up держит терминал и показывает логи. docker compose up -d
ps Контейнеры проекта — статус, здоровье, порты; с -a и остановленные. docker compose ps -a
logs Вывод сервисов с именем сервиса в начале строки; -f — следить, --tail — последние строки. docker compose logs -f --tail 20 backend
exec Команда в работающем контейнере сервиса; сервис называют именем из compose.yaml. docker compose exec proxy nslookup backend
config Проверить файл и показать итоговую конфигурацию с подставленными переменными. docker compose config
down Остановить и удалить контейнеры и сеть проекта; именованные тома остаются. docker compose down
--build Пересобрать образы сервисов с ключом build перед запуском. docker compose up -d --build
--wait Дождаться, пока сервисы будут running или healthy; не дождался — код не 0. docker compose up -d --wait
--format json Объект JSON на строку для каждого контейнера — для скриптов и jq. docker compose ps --format json
-q --quiet Только проверка — без вывода, код 0, если файл верен. docker compose config -q
restart Перезапустить контейнеры сервиса без пересоздания; правки compose.yaml так не применяются. docker compose restart proxy
stop Остановить сервисы, не удаляя контейнеры; вернуть — start или up -d. docker compose stop backend
-v --volumes Удалить и тома проекта — данные в них пропадут. опасно docker compose down -v
build Собрать образы сервисов, у которых есть ключ build. docker compose build
-f --file FILE Взять другой файл вместо compose.yaml в текущем каталоге. docker compose -f stack.yaml up -d
-T Без терминала — для скриптов и конвейеров. docker compose exec -T backend cat /etc/hosts
--services Только имена сервисов, по одному на строку. docker compose config --services
-p --project-name NAME Имя проекта вместо имени каталога — префикс контейнеров, сети и томов. docker compose -p demo up -d
--env-file FILE Файл переменных для подстановки вместо .env рядом с compose.yaml. docker compose --env-file prod.env up -d

Ничего не найдено. Попробуй запрос короче.

Рецепты

4

Проверить файл перед запуском

bash
sudo docker compose config -q && echo OK   # только проверка
sudo docker compose config                 # итог с переменными
sudo docker compose config --services      # имена сервисов

Состояние стека для скрипта

bash
sudo docker compose ps --format json \
  | jq -r '"\(.Service) \(.State) \(.Health)"'

--format json печатает объект JSON на строку для каждого контейнера — jq разбирает их по одному.

Остановить один сервис

bash
sudo docker compose stop backend       # контейнер остаётся
sudo docker compose ps -a              # backend — Exited
sudo docker compose up -d              # поднять обратно

Логи всех сервисов сразу

text
student@ubuntu:~/stack$ sudo docker compose logs --tail 2
proxy-1  | 2026/10/20 14:39:21 [notice] 1#1: start worker process 21
proxy-1  | 172.18.0.1 - - [20/Oct/2026:14:39:22 +0000] "GET / HTTP/1.1"…

Перед строкой — имя сервиса. Один сервис — logs backend, следить — logs -f.

Неполадки

11

no configuration file provided: not found

В текущем каталоге нет compose.yaml. Перейди в каталог проекта или укажи файл: docker compose -f /srv/stack/compose.yaml ps.

additional properties '…' not allowed

text
validating /home/student/stack/compose.yaml: services.backend
additional properties 'enviroment' not allowed

Ключ с опечаткой или не на своём уровне отступа. Путь до ошибки — services.backend; сверь имя ключа с таблицей выше.

yaml: line 3: found character that cannot start any token

В строке 3 табуляция или другой символ, с которого YAML не начинает значение. Отступы в YAML — только пробелами. Место ошибки покажет и инструмент сайта «YAML ⇄ JSON» в разделе «Инструменты».

service "backend" refers to undefined volume

Сервис подключает именованный том, которого нет в volumes: верхнего уровня. Объяви его там же или пиши путь bind mount с ./ или /.

external volume "…" not found

Том с external: true должен существовать до up; сеть проекта compose к этому моменту уже создал. Сверь имя в name: со списком docker volume ls. Тома нет — создай его (docker volume create keep) или верни данные из резервной копии.

dependency failed to start: container … is unhealthy

backend не прошёл проверку здоровья, и proxy с condition: service_healthy остался в статусе Created. Посмотри, что отвечает проверка: docker compose ps -a (статус unhealthy) и docker inspect -f '{{json .State.Health}}' <контейнер> — там вывод последних попыток. Частые причины: не тот порт в test, в образе нет wget, сервис стартует дольше, чем interval × retries.

The "X" variable is not set

The "MODE" variable is not set. Defaulting to a blank string. — переменной нет ни в окружении, ни в .env, и compose подставил пустую строку. Задай её в .env или значение по умолчанию: ${MODE:-prod}.

the attribute version is obsolete

Строка version: "3.8" в начале файла устарела, compose её пропускает. Удали её — предупреждение уйдёт.

Сервис в цикле перезапусков

docker compose ps показывает Restarting: главный процесс падает, а restart: поднимает его снова. Причина — в docker compose logs <сервис>: неверная переменная, нет файла, занят порт. Исправь compose.yaml или .env и выполни up -d.

Pulling … failed to resolve reference

text
 backend Pulling
 backend Error failed to resolve reference "docker.io/library/busybox…

Образа сервиса нет на машине, и compose пошёл за ним в реестр. Без сети загрузи образ из файла (docker load -i) и сверь имя и тег в image: с docker images.

service "proxy" is not running

exec работает только в запущенном сервисе. docker compose ps -a — что с ним; поднять — docker compose up -d.

Опасно

2

docker compose down -v

down удаляет контейнеры и сеть, тома оставляет. -v удаляет и тома проекта: база, загрузки, всё, что сервисы хранили в volumes:, пропадёт безвозвратно. Внешние тома (external: true) -v не трогает.

Другое имя проекта — другие тома

Имя тома строится из имени проекта: stack_data. Скопировал compose.yaml в другой каталог или запустил с -p — compose создаст новый пустой том <новое имя>_data, и сервис стартует без данных. Старые данные целы в старом томе: docker volume ls.

Термины

2
сервис compose compose service
Запись в разделе services файла compose.yaml: образ, команда, порты и тома контейнера. Имя сервиса — его имя в DNS сети проекта.
проверка здоровья (healthcheck)
Команда, которую Docker регулярно выполняет внутри контейнера: код 0 — healthy, после нескольких неудач подряд — unhealthy. Статус виден в docker ps. Ещё встречается в: Docker

См. также

  • docker — контейнеры, тома, сети и inspect без compose.
  • container-images — откуда берутся образы сервисов.
  • dockerfile — собрать свой образ для build:.
  • env-vars — переменные окружения в сервисах.
  • nginx — прокси перед сервисами стека.
  • curl — проверить ответ стека с хоста.
  • jq — разобрать ps --format json.
Загрузка…