Docker Compose: приложение, база и Redis одной командой

Боты, ИИ и автоматизация
Docker Compose: приложение, база и Redis одной командой

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, безлимитный трафик и выдача сервера за минуту.

Читайте также