Главная / База знаний / Docker Compose: запуск многоконтейнерных приложений
инструкция · 29 октября 2026

Docker Compose: запуск многоконтейнерных приложений

Разбираем структуру docker-compose.yml — сервисы, сети, тома, переменные окружения и healthcheck — на практическом примере связки веб-приложения, базы данных и Redis, поднимаемых одной командой.

Зачем нужен Docker Compose, если есть Docker

Реальные веб-приложения редко ограничиваются одним-единственным контейнером — типичный проект состоит как минимум из самого приложения, базы данных и часто отдельного сервиса кэширования вроде Redis, а нередко ещё и очереди задач, поискового движка или обратного прокси. Запуск и согласованная настройка сети между таким набором контейнеров вручную через отдельные команды docker run для каждого из них быстро становится громоздким и подверженным ошибкам.

Docker Compose решает эту задачу декларативно: вся конфигурация многоконтейнерного приложения — какие сервисы нужны, из каких образов их собирать или откуда скачивать, какие переменные окружения передавать, как сервисы должны видеть друг друга по сети, какие данные должны переживать перезапуск контейнера — описывается в одном файле docker-compose.yml, а поднимается и останавливается всё это одной короткой командой.

Docker Compose превращает инфраструктуру локального окружения разработки (и нередко — небольшого production-сервера) в код: конфигурация хранится вместе с проектом в системе контроля версий и воспроизводится одинаково на любой машине с установленным Docker.

Практическая ценность декларативного описания инфраструктуры

Эта статья разбирает структуру файла docker-compose.yml — секции services, networks и volumes, работу с переменными окружения и файлами .env, механизм depends_on в связке с healthcheck, основные команды управления стеком контейнеров и завершается реалистичным примером связки веб-приложения, базы данных PostgreSQL и Redis.

Структура docker-compose.yml: services, networks, volumes

Файл docker-compose.yml организован вокруг трёх основных верхнеуровневых секций. Секция services перечисляет все контейнеры стека — для каждого указывается образ (или инструкция по сборке из Dockerfile), переменные окружения, проброс портов и подключаемые тома.

Минимальный docker-compose.yml с двумя сервисами и одним именованным томом
services:
  web:
    build: ./app
    ports:
      - "8080:80"
    environment:
      - APP_ENV=production
    depends_on:
      - db
  db:
    image: postgres:16
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Секция volumes на верхнем уровне файла объявляет именованные тома — управляемые самим Docker области постоянного хранения данных, независимые от жизненного цикла конкретного контейнера. В отличие от данных, хранящихся прямо в файловой системе контейнера, содержимое именованного тома переживает удаление и пересоздание контейнера, что критично для баз данных и любых других сервисов, чьи данные нельзя терять при обновлении образа.

Секция networks, если указана явно, позволяет тонко настроить, как именно сервисы видят друг друга по сети, — по умолчанию Docker Compose и без явного объявления сетей автоматически создаёт для всего стека одну общую сеть, внутри которой каждый сервис доступен остальным по своему имени как по обычному сетевому имени хоста, без необходимости знать реальный IP-адрес контейнера, который в любом случае может измениться при пересоздании.

Явное разделение сети на публичную (frontend) и внутреннюю (backend) для изоляции базы данных
networks:
  frontend:
  backend:

services:
  web:
    networks:
      - frontend
      - backend
  db:
    networks:
      - backend

Явное разделение на несколько сетей практически полезно для изоляции: сервис базы данных, подключённый только к внутренней сети backend, физически недостижим из сервисов, подключённых лишь к frontend, — это дополнительный уровень защиты, не позволяющий скомпрометированному публичному сервису напрямую обратиться к базе данных, минуя приложение, которое его использует.

Переменные окружения и файл .env

Секция environment внутри описания сервиса передаёт переменные окружения непосредственно внутрь контейнера — это стандартный способ настройки приложения без изменения самого образа под каждое конкретное окружение, будь то разработка, staging или production.

Передача переменных окружения приложению с подстановкой значения из внешнего .env-файла
services:
  web:
    build: ./app
    environment:
      - DATABASE_URL=postgres://app:${DB_PASSWORD}@db:5432/appdb
      - REDIS_URL=redis://cache:6379/0

Хранить секретные значения вроде паролей базы данных прямо в тексте docker-compose.yml — плохая практика, особенно если этот файл хранится в общем репозитории проекта вместе с остальным кодом. Docker Compose автоматически подхватывает файл .env, расположенный рядом с docker-compose.yml, и подставляет его значения в файл через синтаксис ${ИМЯ_ПЕРЕМЕННОЙ}, что позволяет держать сам docker-compose.yml универсальным и безопасным для хранения в системе контроля версий, исключив только конкретный .env через .gitignore.

Файл .env с реальными значениями, отдельный от основной конфигурации
# .env (не должен попадать в git)
DB_PASSWORD=СложныйПарольБазыДанных
DB_NAME=appdb
DB_USER=app

Альтернативный способ передачи переменных, разделяемых между несколькими сервисами, — секция env_file, указывающая путь к отдельному файлу с переменными для конкретного сервиса, что удобно, когда набор переменных достаточно большой или должен использоваться сразу несколькими сервисами стека без дублирования каждой переменной вручную в секции environment каждого из них.

depends_on и healthcheck: правильный порядок запуска

Директива depends_on в описании сервиса указывает Docker Compose, в каком порядке запускать контейнеры, — сервис, зависящий от другого, стартует только после того, как контейнер зависимости уже запущен. Важная тонкость: «запущен» здесь означает лишь то, что процесс контейнера начал выполняться, а не то, что сервис внутри него уже полностью готов принимать запросы.

Ожидание полной готовности базы данных перед стартом приложения через healthcheck
services:
  web:
    build: ./app
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 5

Для базы данных типична ситуация, когда контейнер уже запущен и виден в списке процессов, но сам процесс СУБД внутри него ещё несколько секунд инициализирует данные и не готов принимать соединения, — приложение, стартовавшее сразу после простого depends_on без учёта готовности, в этот момент получит ошибку подключения. Директива healthcheck определяет команду, периодичность её выполнения и число попыток, по результатам которой Docker решает, считается ли сервис действительно готовым (healthy), а условие condition: service_healthy в depends_on заставляет зависимый сервис дождаться именно этого состояния, а не просто факта запуска контейнера.

Healthcheck полезен не только для управления порядком старта, но и сам по себе — команда docker compose ps показывает текущее состояние здоровья каждого сервиса, что упрощает диагностику: если сервис явно помечен как unhealthy, проблему стоит искать именно в нём, не тратя время на проверку остальных, формально работающих контейнеров стека.

Основные команды: up, down, logs, exec

Команда docker compose up поднимает весь описанный в файле стек контейнеров — при первом запуске она также соберёт образы из указанных Dockerfile и скачает недостающие готовые образы из реестра, а флаг -d переводит все контейнеры в фоновый режим, освобождая терминал.

Запуск стека в фоне, принудительная пересборка образов перед запуском, список текущего состояния сервисов
docker compose up -d
docker compose up --build -d
docker compose ps

Флаг --build принудительно пересобирает образы из Dockerfile перед запуском, даже если ранее собранный образ уже существует и формально не устарел, — это нужно после изменения самого Dockerfile или кода приложения, копируемого внутрь образа на этапе сборки, поскольку без этого флага Docker Compose может использовать закэшированный, уже устаревший образ.

Остановка и удаление контейнеров и сетей; дополнительный флаг -v также удаляет именованные тома с данными
docker compose down
docker compose down -v

Команда docker compose down останавливает и удаляет контейнеры и созданные для стека сети, но по умолчанию сохраняет именованные тома нетронутыми — данные внутри них переживают такую остановку и станут снова доступны при следующем docker compose up. Флаг -v дополнительно удаляет и сами тома вместе со всеми хранившимися в них данными — это разрушительная операция, которую стоит выполнять осознанно, обычно только для полностью тестовых окружений.

Просмотр логов конкретного сервиса в реальном времени и выполнение команд внутри уже запущенного контейнера
docker compose logs -f web
docker compose exec web bash
docker compose exec db psql -U app -d appdb

docker compose exec выполняет произвольную команду внутри уже работающего контейнера конкретного сервиса — это удобно для интерактивной отладки: зайти в контейнер приложения интерактивным bash-сеансом или подключиться напрямую к базе данных внутри её контейнера через psql или аналогичный клиент, минуя необходимость пробрасывать порт наружу только ради разовой проверки.

Полный практический пример: веб-приложение, PostgreSQL и Redis

Соберём вместе разобранные выше элементы в реалистичный пример: веб-приложение на PHP или Node.js, база данных PostgreSQL для хранения основных данных и Redis для кэша и сессий, — типичный набор для среднего размера веб-проекта.

Полная конфигурация из трёх сервисов с healthcheck, переменными окружения и постоянным томом для базы данных
services:
  web:
    build: ./app
    ports:
      - "8080:80"
    environment:
      - DATABASE_URL=postgres://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME}
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 5s
      timeout: 3s
      retries: 5
    restart: unless-stopped

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    restart: unless-stopped

volumes:
  db_data:

Обратите внимание, что сервис cache (Redis) не имеет собственного именованного тома — в этой конфигурации Redis используется исключительно как кэш, данные которого не критичны для сохранности и в случае потери просто будут заново получены из основной базы данных при следующем обращении, поэтому персистентность для него намеренно не настраивается, в отличие от обязательного тома db_data для PostgreSQL.

Директива restart: unless-stopped на каждом сервисе указывает Docker автоматически перезапускать контейнер при его неожиданном падении или при перезагрузке самого сервера, но не перезапускать контейнеры, остановленные явной командой администратора, — разумное значение по умолчанию для production-стека, где сервисы должны быть устойчивы к случайным сбоям, но не должны самостоятельно подниматься вопреки намеренной остановке.

Масштабирование и работа с несколькими экземплярами сервиса

Для сервисов, не хранящих состояние локально (типичный случай — сам веб-сервер приложения при вынесенных во внешние хранилища сессиях и кэше), Docker Compose позволяет запустить сразу несколько экземпляров одного и того же сервиса командой с флагом --scale, не меняя сам файл конфигурации.

Запуск трёх параллельных экземпляров сервиса web из одного и того же описания
docker compose up -d --scale web=3

Важная практическая деталь: при использовании --scale для сервиса, у которого в конфигурации явно прописан проброс конкретного порта на хост (как ports: - "8080:80" в примере выше), несколько экземпляров не смогут одновременно занять один и тот же порт хоста, и Docker Compose выдаст ошибку конфликта портов. Для реального масштабирования в такой схеме перед несколькими экземплярами сервиса обычно ставят отдельный балансировщик нагрузки — например, Nginx, который сам слушает единственный внешний порт и распределяет запросы между внутренними адресами всех экземпляров сервиса по имени в общей docker-сети.

Для более сложных production-сценариев с автоматическим масштабированием под нагрузкой, распределением контейнеров между несколькими физическими серверами и встроенным механизмом обнаружения отказов сама модель docker compose --scale на одном сервере становится недостаточной, и стоит рассматривать полноценные оркестраторы вроде Docker Swarm или Kubernetes — но для одиночного сервера или проекта с предсказуемой, не сильно колеблющейся нагрузкой возможностей docker compose обычно достаточно без этой дополнительной сложности.

Типичные ошибки при работе с Docker Compose

Хранение реальных паролей и других секретов прямо в тексте docker-compose.yml, коммитящегося в общий репозиторий проекта, вместо вынесения их в отдельный .env-файл, исключённый из системы контроля версий, — это прямая утечка учётных данных всем, у кого есть доступ к репозиторию, включая историю коммитов даже после последующего удаления секрета из актуальной версии файла.

Использование только depends_on без healthcheck для сервисов с заметным временем инициализации вроде баз данных — приложение стартует раньше, чем СУБД реально готова принимать соединения, что на медленном сервере или при первом запуске с инициализацией пустой базы данных приводит к ошибке подключения именно в самый первый момент запуска стека.

Отсутствие именованных томов для сервисов с данными, которые нельзя терять, — без явного тома данные базы данных хранятся в слое самого контейнера и полностью теряются при его пересоздании, например, после обновления образа на новую версию.

Забытый флаг --build после изменения Dockerfile или кода приложения — docker compose up без этого флага может продолжить использовать ранее собранный, устаревший образ, создавая впечатление, что внесённые изменения в код почему-то не применяются на запущенном стенде.

Случайное использование docker compose down -v на production-окружении вместо тестового — этот флаг безвозвратно удаляет данные всех именованных томов стека, и без отдельного резервного копирования этих данных восстановить их после такой команды невозможно.

Итог: инфраструктура как код для многоконтейнерных приложений

Docker Compose превращает запуск и настройку многоконтейнерного приложения из набора разрозненных ручных команд и заметок в единый декларативный файл, воспроизводимый одинаково на любой машине с установленным Docker — от ноутбука разработчика до production-сервера, что заметно снижает классическую проблему «у меня локально работает, а на сервере нет» из-за незаметных расхождений в окружении.

Ключевые практические привычки, определяющие надёжность стека в реальной эксплуатации, — вынесение секретов в отдельный .env, healthcheck для сервисов с заметным временем инициализации в связке с condition: service_healthy, именованные тома для любых данных, которые нельзя терять, и осознанная политика restart для устойчивости к случайным сбоям. Если нужна помощь с проектированием docker-compose.yml под ваш конкретный стек, опишите задачу в заявке внизу страницы — поможем собрать конфигурацию под ваше приложение.

Освоив базовую структуру на примере из нескольких сервисов, дальнейшее расширение стека — добавление ещё одного сервиса вроде очереди задач или поискового движка, вынесение части конфигурации в отдельные файлы для разных окружений через механизм override — сводится к постепенному наращиванию уже понятной декларативной структуры, а не к изучению всего процесса запуска инфраструктуры заново.

почему мы

Почему стоит выбрать нас

Быстрый запуск

Подберём конфигурацию и развернём проект в день обращения.

Надёжность

NVMe-диски, защита от DDoS и резервные копии по расписанию.

Поддержка 24/7

Дежурные инженеры на связи в любое время суток.

Настройка под ключ

Установим CMS, настроим веб-сервер, SSL и почту за вас.

Перенос без простоя

Аккуратно перенесём сайт и базу данных на новый сервер.

Прозрачные цены

Актуальные тарифы и честный подбор без навязывания.

частые вопросы

Вопросы и ответы

Чем docker compose отличается от обычного docker run?

docker compose описывает всю многоконтейнерную конфигурацию — сервисы, сети, тома, переменные окружения и зависимости между контейнерами — в одном декларативном файле docker-compose.yml, тогда как docker run требует вручную указывать все эти параметры отдельной длинной командой для каждого контейнера и вручную создавать общие сети между ними.

Нужно ли устанавливать Docker Compose отдельно от Docker?

В современных версиях Docker Compose встроен в сам Docker как подкоманда docker compose (без дефиса) и устанавливается вместе с Docker Engine; отдельная классическая утилита docker-compose (через дефис) — это более старая, самостоятельная реализация, которую в новых проектах уже не рекомендуется использовать.

Что произойдёт с данными в контейнере после docker compose down?

Данные, хранящиеся внутри именованных томов (volumes), сохраняются и переживают команду down — она останавливает и удаляет контейнеры и сети, но не удаляет тома, если явно не указан дополнительный флаг -v; данные, записанные без использования тома прямо в слой контейнера, теряются безвозвратно.

Как передать секретные данные вроде пароля базы данных, не храня их прямо в docker-compose.yml?

Через отдельный файл .env, подключаемый Docker Compose автоматически, если он лежит рядом с docker-compose.yml, — сам файл .env исключается из системы контроля версий (добавляется в .gitignore), в отличие от docker-compose.yml, который обычно хранится в репозитории проекта вместе с кодом.

Что делает depends_on и решает ли он проблему готовности сервиса?

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

Можно ли использовать docker compose в production, а не только для разработки?

Да, для одиночного сервера или небольшого проекта docker compose вполне подходит и для production, особенно в сочетании с restart-политиками и healthcheck; для распределённой инфраструктуры с несколькими серверами и автоматическим масштабированием обычно переходят на оркестраторы вроде Kubernetes или Docker Swarm.

Как посмотреть логи конкретного сервиса среди нескольких запущенных контейнеров?

Командой docker compose logs с именем сервиса, как оно указано в docker-compose.yml, — например, docker compose logs -f web покажет и продолжит показывать в реальном времени только логи сервиса web, не смешивая их с выводом остальных контейнеров стека.

Как оплачивать услуги?

Оплата помесячная, для облачных серверов доступна почасовая тарификация. Принимаются карты, банковские переводы и электронные кошельки.

Есть ли круглосуточная поддержка?

Да, дежурные инженеры на связи 24/7.

Выдаёте ли закрывающие документы?

Да, предоставим необходимые документы для оплаты.

Как оставить заявку?

Заполните форму на странице или нажмите «Заказать» — мы свяжемся и поможем с подбором.

заявка

Оставьте заявку

Ответим и поможем с подбором и настройкой.