🧩 Docker Compose

Полный справочник: файл compose.yaml (сервисы, сети, тома, переменные, healthcheck, profiles, ресурсы), команды, окружения dev/prod, паттерны и отладка.

Шпаргалки · Инфраструктура · #docker #compose #containers #devops

Идея

Compose описывает несколько контейнеров приложения одним YAML-файлом и управляет ими командами: сервисы, сети, тома, переменные, порядок запуска. Подходит для локальной разработки, тестов, CI и небольших серверов. Для кластеров смотрите Swarm и Kubernetes.

Файл называется compose.yaml (или compose.yml, docker-compose.yml). Команда docker compose (плагин v2); старая docker-compose (v1) устарела. Ключ version: больше не нужен.

Команды

docker compose up                       docker compose up -d                   docker compose up -d --build
docker compose up -d --force-recreate   docker compose up --no-deps -d web      # пересоздать один сервис
docker compose down                     docker compose down -v --rmi local      # с томами и образами
docker compose ps [-a]                  docker compose top                      docker compose images
docker compose logs -f --tail 100 web   docker compose exec web sh              docker compose run --rm web npm test
docker compose build [--no-cache] web   docker compose pull                     docker compose push
docker compose start|stop|restart web   docker compose pause|unpause web        docker compose kill web
docker compose config                   # итоговый файл после подстановок (проверка)
docker compose --profile debug up       docker compose -p myproj up             # имя проекта
docker compose watch                    # автообновление при изменении файлов (develop.watch)
docker compose cp web:/app/log.txt .    docker compose events                   docker compose port web 80

Полный пример

name: shop

services:
  web:
    build:
      context: ./web
      dockerfile: Dockerfile
      target: prod
      args: { NODE_ENV: production }
    image: ghcr.io/me/shop-web:${TAG:-latest}
    ports: ["8080:3000"]                 # "127.0.0.1:8080:3000" — только localhost
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
      REDIS_URL: redis://cache:6379
    env_file: [.env]
    depends_on:
      db: { condition: service_healthy }
      cache: { condition: service_started }
    restart: unless-stopped
    networks: [front, back]
    volumes:
      - ./web/uploads:/app/uploads
      - logs:/var/log/app
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
      interval: 10s
      timeout: 3s
      retries: 5
      start_period: 20s
    deploy:
      resources: { limits: { cpus: "1.0", memory: 512M } }
    develop:
      watch:
        - { action: sync, path: ./web/src, target: /app/src }
        - { action: rebuild, path: ./web/package.json }

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: app
    volumes:
      - dbdata:/var/lib/postgresql/data
      - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      retries: 10
    networks: [back]

  cache:
    image: redis:7-alpine
    command: ["redis-server", "--appendonly", "yes"]
    volumes: [cachedata:/data]
    networks: [back]

  adminer:
    image: adminer
    profiles: ["debug"]
    ports: ["8081:8080"]
    networks: [back]

networks:
  front:
  back:
    internal: true                        # без выхода наружу

volumes:
  dbdata:
  cachedata:
  logs:

secrets:
  db_password: { file: ./secrets/db_password.txt }

Основные ключи сервиса

Ключ Назначение
image / build готовый образ или сборка из Dockerfile
ports "хост:контейнер" публикация наружу
expose порт только для других сервисов сети
environment, env_file переменные окружения
volumes тома (имя:/путь) и bind mount (./папка:/путь[:ro])
networks, network_mode сети
depends_on порядок и условие запуска (service_started, service_healthy, service_completed_successfully)
command, entrypoint, working_dir, user запуск
restart no, always, on-failure, unless-stopped
healthcheck проверка здоровья
deploy.resources лимиты CPU и памяти
profiles необязательные группы сервисов
secrets, configs секреты и конфиги как файлы
extra_hosts, dns, hostname, container_name сетевые мелочи
cap_drop, read_only, security_opt, tmpfs усиление безопасности
scale / deploy.replicas число копий сервиса
labels, logging, ulimits, sysctls, init, stop_grace_period прочее

Сети и имена

Compose создаёт сеть проекта, и сервисы видят друг друга по имени сервиса (db, cache). Наружу открывайте порты только у тех сервисов, к которым нужен доступ с хоста. depends_on сам по себе ждёт только запуск контейнера: для готовности используйте condition: service_healthy и healthcheck.

Переменные

  • ${VAR}, ${VAR:-значение по умолчанию}, ${VAR:?ошибка, если не задана} подставляются из окружения оболочки и файла .env рядом с compose.yaml.
  • environment задаёт переменные внутри контейнера, env_file читает файл целиком.
  • Порядок приоритета: значения оболочки, затем --env-file, затем .env.
  • Не коммитьте .env с секретами: храните .env.example.
  • Секреты лучше как файлы: secrets: и /run/secrets/<имя>, а в приложении читайте *_FILE.

Несколько файлов и окружения

docker compose -f compose.yaml -f compose.dev.yaml up -d          # поверх базового
docker compose -f compose.yaml -f compose.prod.yaml config         # проверить итог

compose.override.yaml подхватывается автоматически: хранит dev-настройки (bind mount, отладочные порты). Расширение: extends, include, якоря YAML:

x-logging: &logging { driver: json-file, options: { max-size: "10m", max-file: "3" } }
services:
  web: { logging: *logging }
  api: { logging: *logging }

Типовые связки

Задача Состав
Веб + БД web, postgres (volume), adminer (profile debug)
Реверс-прокси caddy или nginx / traefik + приложение во внутренней сети
Очереди rabbitmq (management) или kafka + zookeeper/KRaft
Мониторинг prometheus + grafana + node-exporter + cadvisor
Логи loki + promtail + grafana
Тесты в CI docker compose up -d --wait затем тесты, down -v

--wait ждёт, пока сервисы с healthcheck станут здоровыми.

Отладка

Симптом Что проверить
Сервис не видит БД по localhost используйте имя сервиса (db), не localhost
Приложение стартует раньше БД healthcheck + depends_on: condition: service_healthy, повторные подключения в коде
Правки конфигурации не применились docker compose up -d пересоздаёт при изменении; образы пересобирайте --build
Данные пропали down -v удаляет тома; используйте именованные тома
Порт занят поменяйте левую часть ports или остановите конфликтующий процесс
Права на bind mount UID / GID, user:, chown
Странное поведение переменных docker compose config показывает итоговые значения
Много места docker system df, docker compose down --rmi local

Production

Compose годится для одного сервера: фиксируйте версии образов, restart: unless-stopped, лимиты ресурсов, healthcheck, вращение логов, резервные копии томов, HTTPS на прокси, секреты вне образов. Для нескольких серверов, самовосстановления и обновлений без простоя переходите на Docker Swarm или Kubernetes (инструмент kompose помогает конвертировать).