Короткий ответ

Стек проекта app в /opt/app не поднялся — это почти всегда файл Compose, имя проекта, сеть или depends_on, а не «Docker сломался». Сначала docker compose config (рендер без up), docker info (демон жив), затем конфликт портов и сетей. depends_on без healthcheck не ждёт готовности Postgres, только старт контейнера. Не запускайте down -v «чтобы пересоздать»: -v снимет named volume app_data.

Плагин Compose v2: команда docker compose, не устаревший docker-compose из pip, если вы на Ubuntu 22.04/24.04 с docker-ce.

Симптомы и как отличить

  • docker compose up -d печатает yaml: line 17: did not find expected key;
  • Error response from daemon: network app_backend not found;
  • service "web" depends on undefined service "redis";
  • Bind for 0.0.0.0:8080 failed: port is already allocated;
  • часть сервисов Up, db нет — смотрите не «сеть Docker», а один сервис.
ОшибкаНе тоКуда
Cannot connect to daemoncompose файлdaemon
контейнеры Up, ping по имени нетup «успешен»сети сервисов
listen есть, с LAN нетpublishпорт
volume ... not a directorymountsvolume

Возможные причины

  1. Табы/CRLF/дубли ключа ports: в YAML.
  2. Смешали version: "3.8" с атрибутами Compose Specification (develop:, include:), плагин v2 их не понял или наоборот.
  3. Внешняя сеть external: true, которую забыли docker network create.
  4. depends_on на сервис из другого файла, не попавшего в -f.
  5. Порт хоста занят nginx/другим стеком.
  6. Профили profiles: — сервис не в default, up его молча не стартует.
  7. Редко: name: контейнера захардкожен и уже занят чужим проектом.

Диагностика

1. Демон и версия клиента

docker info >/dev/null && echo daemon_ok
docker compose version
cd /opt/app && ls -l compose.yaml docker-compose.yml compose.yml 2>/dev/null

Два файла compose.yaml и docker-compose.yml в одном каталоге — источник сюрпризов. Compose v2 мержит по своим правилам; лучше один файл.

2. Рендер конфига

cd /opt/app
docker compose config >/tmp/app.compose.rendered.yaml
echo $?
docker compose config --services
docker compose config --volumes
docker compose config --networks

Ошибка unmarshal на этом шаге. Смотрите номер строки в рендере, затем в исходнике.

3. Сети и проект

docker compose ls
docker network ls | grep app
docker compose ps -a

Ожидаемая user-defined сеть часто app_default. Если YAML требует app_backend как external — её должно быть видно в network ls до up.

4. depends_on и профили

docker compose config | grep -n -A6 'depends_on'
docker compose --profile '*' config --services

Сервис только с profiles: [batch] не войдёт в обычный up -d.

5. Порт хоста

sudo ss -tlnp | grep -E ':8080|:80 '
docker compose config | grep -A4 'ports:'

Решение

Сценарий A. YAML не парсится

Правите отступ (два пробела), кавычки в environment. Проверка:

python3 -c 'import yaml,sys; yaml.safe_load(open("compose.yaml"))'
docker compose config >/dev/null

Не «конвертируйте» файл через онлайн-YAML с чужой машины с секретами.

Сценарий B. network not found

Если сеть должна быть внутренней:

networks:
  backend:

Без external: true. Compose создаст app_backend.

Если сеть общая на хосте:

docker network create app_backend
docker compose up -d

Документируйте create в runbook, не в чате.

Сценарий C. depends_on врёт о порядке

services:
  db:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 20
  web:
    depends_on:
      db:
        condition: service_healthy

Без healthcheck depends_on: [db] только ждёт start, не accept на 5432. Приложение web падает — это уже мгновенный exit, не «compose сломался».

Сценарий D. port already allocated

Найдите владельца 8080, не меняйте вслепую на 8081 в проде без DNS/proxy.

sudo ss -tlnp | grep 8080

Либо остановите чужой стек, либо поправьте publish. Тема публикации: порт недоступен.

Сценарий E. Несколько -f

docker compose -f /opt/app/compose.yaml -f /opt/app/compose.prod.yaml config

Всегда одни и те же -f в systemd unit и в руках админа. Иначе «у меня работает».

Как проверить, что проблема устранена

cd /opt/app
docker compose up -d
docker compose ps
docker compose top
docker network inspect app_default --format '{{len .Containers}}'

Все нужные сервисы running (или healthy). Число контейнеров на сети проекта совпадает с ожиданием. DNS-имя db резолвится из web — см. Docker DNS.

Если не помогло

  • up ок, браузер нет — это порт/firewall, не YAML.
  • service "web" depends on undefined service "db" после split файлов — не тот -f.
  • Orphans: docker compose up -d --remove-orphans удалит контейнеры этого проекта, которых нет в текущем файле. Не путать с чужими стеками, если имя проекта общее.
  • include: в спецификации — проверьте версию docker compose version; старый плагин не поймёт.
  • Build context ENOENT — путь относительно файла compose, не cwd.

Профилактика

  • Один compose.yaml, overlays явно -f.
  • COMPOSE_PROJECT_NAME=app в /opt/app/.env (не секреты туда).
  • CI: docker compose config -q.
  • Запрет down -v в шпаргалках без подтверждения тома app_data.
  • Healthcheck + condition: service_healthy для БД.

FAQ

docker compose vs docker-compose

На Ubuntu с docker-ce 27.x используйте плагин v2. Бинарь docker-compose 1.29 иначе парсит condition: и секреты иначе. Сверьте docker compose version.

Нужен ли version: "3.9"?

Для Compose Specification поле version игнорируется. Не чините им сети.

Почему сеть называется app_default, а в YAML default?

Префикс проекта. В контейнере DNS-имя сервиса web, не app-web-1 (это hostname контейнера). Путаница даёт «не видят друг друга».

Можно ли network_mode: host чтобы «точно поднялось»?

Сломаете DNS сервисов и publish. Не обход для YAML.

up --force-recreate удалит app_data?

Нет, named volume живёт отдельно от контейнера. Удаляет -v у down/rm.