Docker Compose — это инструмент, который превращает запуск многослойного проекта в одну команду. Вместо того чтобы вручную поднимать контейнеры на сервере, связывать их сетью и помнить десяток флагов docker run, вы описываете всё в одном YAML-файле: приложение, базу данных, Redis, тома и переменные окружения. Дальше — docker compose up -d, и стек работает. В этой статье разберём Docker Compose на практике: установим его на Ubuntu 24.04, напишем рабочий docker-compose.yml с тремя сервисами (web + PostgreSQL + Redis) и пройдёмся по командам, которые понадобятся каждый день.
Зачем нужен Docker Compose, если есть docker run
Типичное веб-приложение — это не один процесс. Как минимум: сам код, база данных и кеш. Запускать это через docker run можно, но неудобно: три длинные команды, ручное создание сети, порядок запуска в голове, а после перезагрузки сервера — всё заново.
Compose решает эти проблемы декларативно:
- Один файл — вся инфраструктура. Конфигурация лежит в git рядом с кодом, любой член команды поднимет копию окружения за минуту.
- Автоматическая сеть. Контейнеры видят друг друга по именам сервисов: приложение обращается к базе просто по хосту
db, к кешу — по хостуredis. - Управление зависимостями. Через
depends_onи healthcheck приложение стартует только после того, как база готова принимать соединения. - Идемпотентность. Повторный
docker compose up -dпересоздаёт только изменившиеся контейнеры.
Важный момент с названием: docker-compose (через дефис) — это устаревшая первая версия на Python. Актуальная — Compose v2, плагин к Docker CLI, который вызывается через пробел: docker compose. Именно её мы и ставим.
Установка Docker и Compose v2 на Ubuntu 24.04
Если Docker на сервере ещё нет, начните с базовой статьи Docker на VPS: установка и первые контейнеры. Краткая версия — ставим из официального репозитория Docker, потому что в нём всегда свежие версии и плагин Compose идёт в комплекте:
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Проверяем, что всё встало:
docker --version
docker compose version
Чтобы не писать sudo перед каждой командой, добавьте себя в группу docker и перезайдите в сессию:
sudo usermod -aG docker $USER
Работать лучше не под root — если ещё не завели отдельного пользователя, вот инструкция: создание пользователя с sudo.
Пишем docker-compose.yml: web + PostgreSQL + Redis
Создаём каталог проекта и два файла — docker-compose.yml и .env для секретов:
mkdir -p ~/myapp && cd ~/myapp
touch docker-compose.yml .env
В .env кладём пароль базы (файл добавьте в .gitignore):
POSTGRES_PASSWORD=надёжный_пароль_здесь
А вот полный docker-compose.yml для связки «приложение + база + кеш». Поле version в современном Compose Specification больше не нужно — начинаем сразу с services:
services:
web:
build: .
ports:
- "8000:8000"
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/app
REDIS_URL: redis://redis:6379/0
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redisdata:/data
restart: unless-stopped
volumes:
pgdata:
redisdata:
Разберём ключевые решения в этом файле:
build: .— образ приложения собирается изDockerfileв текущем каталоге. Для готового образа вместо этого пишутimage: имя:тег.ports: "8000:8000"— наружу опубликован только web. База и Redis доступны лишь внутри сети Compose — снаружи до них не достучаться, и это правильно с точки зрения безопасности.depends_onсcondition: service_healthy— приложение не стартует, пока healthcheck PostgreSQL (pg_isready) не подтвердит готовность базы. Это избавляет от классической ошибки «connection refused» при первом запуске.- Именованные тома
pgdataиredisdata— данные живут отдельно от контейнеров и переживают любые пересоздания. restart: unless-stopped— после перезагрузки VPS весь стек поднимется сам, без systemd-юнитов.- Лимит
--maxmemory 256mbу Redis защищает от ситуации, когда кеш съедает всю память сервера. Подробнее о настройке кеша — в статье Redis: кеширование, которое ускоряет сайт в разы.
Запуск одной командой
Всё готово — запускаем:
docker compose up -d
Флаг -d (detached) отправляет стек в фон. Compose сам соберёт образ приложения, скачает postgres:16-alpine и redis:7-alpine, создаст сеть и тома, запустит контейнеры в правильном порядке. Проверяем состояние:
docker compose ps
В колонке STATUS у db должно быть Up (healthy), у остальных — Up. Смотрим логи всех сервисов в реальном времени:
docker compose logs -f
Или только одного сервиса: docker compose logs -f web. На NVMe-дисках скачивание и распаковка образов занимают секунды: на VPS Cheap-Host (тариф Pro — 12 vCPU, 16 ГБ RAM, NVMe за 750 ₽/мес) холодный старт этого стека с нуля укладывается примерно в минуту вместе с загрузкой образов.
Команды Compose на каждый день
Небольшая шпаргалка — эти команды выполняются из каталога с docker-compose.yml:
| Команда | Что делает |
|---|---|
docker compose up -d | Запустить/обновить стек в фоне |
docker compose ps | Статус контейнеров проекта |
docker compose logs -f web | Логи сервиса web в реальном времени |
docker compose exec db psql -U app | Открыть psql внутри контейнера базы |
docker compose restart web | Перезапустить один сервис |
docker compose pull | Скачать свежие версии образов |
docker compose build --no-cache web | Пересобрать образ приложения с нуля |
docker compose down | Остановить и удалить контейнеры (тома сохраняются) |
docker compose down -v | То же + удалить тома. Осторожно: сотрёт данные базы |
Типовой сценарий обновления приложения после git pull:
git pull
docker compose build web
docker compose up -d
Compose пересоздаст только контейнер web — база и Redis продолжат работать без перерыва.
Три практических совета для продакшена
1. Ограничивайте ресурсы контейнеров
Чтобы один сервис не задушил остальные, задайте лимиты прямо в Compose-файле:
web:
deploy:
resources:
limits:
cpus: "2"
memory: 1g
2. Бэкапьте тома, а не контейнеры
Контейнеры одноразовые, ценность — в томах. Дамп базы снимается одной командой:
docker compose exec db pg_dump -U app app | gzip > backup_$(date +%F).sql.gz
Добавьте её в cron и храните копии вне сервера — как это организовать, читайте в статье о резервном копировании VPS по стратегии 3-2-1.
3. Следите за диском
Старые образы и кеши сборки накапливаются. Раз в неделю чистите неиспользуемое: docker system prune -f. Занятое место покажет docker system df.
Какой VPS нужен под Docker Compose
Контейнеры на сервере требуют честных выделенных ресурсов: оверселлинг и медленный диск превращают сборку образов в мучение. Ориентиры такие:
- Пет-проект, один стек — от 2 vCPU и 4 ГБ RAM;
- Рабочий проект web + база + Redis — от 4 vCPU и 8 ГБ RAM;
- Несколько проектов или ресурсоёмкие сборки — 8+ vCPU и 16 ГБ RAM.
Под эти задачи хорошо подходит тариф Pro у Cheap-Host: 12 vCPU, 16 ГБ RAM и 128 ГБ NVMe за 750 ₽/мес, с KVM-виртуализацией (то есть полноценным ядром Linux — Docker работает без ограничений), полным root-доступом и безлимитным трафиком. Сервер выдаётся за 45–60 секунд, а если проект вырастет — CPU, RAM и диск можно расширить без потери данных.
FAQ
Чем docker compose отличается от docker-compose с дефисом?
docker-compose — устаревшая версия v1 на Python, отдельная утилита. docker compose (через пробел) — актуальная v2, плагин к Docker CLI на Go. Он быстрее, поддерживает современный формат Compose Specification и ставится пакетом docker-compose-plugin. Новые проекты ведите только на v2.
Пропадут ли данные базы после docker compose down?
Нет, если данные лежат в именованном томе. docker compose down удаляет контейнеры и сеть, но тома сохраняет. Данные сотрёт только явный docker compose down -v — в продакшене этот флаг под запретом.
Сколько ресурсов нужно VPS для стека web + PostgreSQL + Redis?
Минимум — 2 vCPU и 4 ГБ RAM для небольшого проекта. Комфортно — уровень тарифа Pro (12 vCPU, 16 ГБ RAM, NVMe). Запас по памяти важен: PostgreSQL и Redis используют её под кеш, а сборки образов дают пиковую нагрузку.
Как обновить контейнеры до новых версий образов?
docker compose pull, затем docker compose up -d. Compose пересоздаст только контейнеры с обновлёнными образами. Старые образы удалит docker image prune -f.
Можно ли держать несколько Compose-проектов на одном VPS?
Да. Каждый проект живёт в своём каталоге, получает отдельную сеть и не мешает соседям. Следите за опубликованными наружу портами и суммарным потреблением RAM.
Вывод
Docker Compose убирает рутину из работы с контейнерами: один YAML-файл описывает весь проект, одна команда его запускает, а restart: unless-stopped и именованные тома делают стек устойчивым к перезагрузкам. Начните с шаблона из этой статьи — он рабочий и покрывает 90% типовых задач, — а дальше наращивайте: healthcheck для web, лимиты ресурсов, бэкапы по расписанию. Если для этой задачи вам нужен сервер — у Cheap-Host тариф Pro от 750 ₽/мес: 12 vCPU, 16 ГБ RAM, NVMe, KVM, безлимитный трафик и выдача сервера за минуту.