Compose описывает всё приложение одним файлом: какие контейнеры запустить, как они связаны, где хранят данные и что делать при падении. Файл лежит рядом с проектом, его удобно держать в git.
Структура проекта
$ mkdir -p /opt/myapp && cd /opt/myapp$ touch compose.yaml .envПример: веб-приложение и PostgreSQL. Приложение стартует, когда база станет здоровой, данные базы лежат в именованном томе.
services: db: image: postgres:16 restart: unless-stopped environment: POSTGRES_DB: app POSTGRES_USER: app POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d app"] interval: 10s timeout: 5s retries: 5 web: image: ghcr.io/example/myapp:1.4.2 restart: unless-stopped env_file: .env environment: DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app ports: - "127.0.0.1:3000:3000" depends_on: db: condition: service_healthyvolumes: db-data:DB_PASSWORD=замените-на-длинный-случайный-пароль$ openssl rand -hex 24$ chmod 600 .envЗапуск и управление
$ docker compose up -d$ docker compose ps$ docker compose logs -f web$ docker compose exec db psql -U app app$ docker compose downСервисы видят друг друга по имени: приложение подключается к базе по адресу db:5432. Публиковать порт базы наружу для этого не нужно.
Перезапуск после сбоев и перезагрузки
restart: unless-stopped поднимает контейнер после падения и после перезагрузки сервера, если вы не остановили его вручную. Служба docker включается в автозапуск при установке — проверьте: systemctl is-enabled docker.
Обновление образов
$ cd /opt/myapp$ docker compose pull$ docker compose up -d$ docker image prune -fup -d пересоздаст только те контейнеры, у которых изменился образ или настройки. Тома при этом сохраняются.
Проверьте результат
$ docker compose ps$ curl -I http://127.0.0.1:3000У базы в колонке STATUS должно быть (healthy), приложение должно отвечать на локальном порту.
Частые ошибки
- docker compose down -v удаляет тома вместе с данными базы. Без -v тома остаются.
- Смена POSTGRES_PASSWORD в .env не меняет пароль существующей базы: переменная читается только при первой инициализации тома.
- Команда docker-compose (через дефис) — устаревшая отдельная программа. Используйте docker compose из плагина.