Урок 7 из 8 · 25 мин · обновлено
Docker Compose: несколько контейнеров одним файлом
Как описать сайт, базу данных и веб-интерфейс в одном файле compose.yaml и запускать их одной командой: сервисы, порты, тома, сборка своего образа, файл .env для паролей и команды up, ps, logs и down.
Зачем Compose
В прошлом уроке стенд из базы и Adminer потребовал нескольких длинных команд: создать сеть, запустить базу с томом и паролем, запустить Adminer с портом. Через неделю их не вспомнить, а коллеге придётся пересылать инструкцию.
Docker Compose описывает все контейнеры проекта в одном файле compose.yaml. Весь стенд поднимается одной командой — у вас, у коллеги и на сервере одинаково. Compose входит в Docker Desktop. На Linux его ставят пакетом docker-compose-plugin из того же репозитория, что и Docker Engine.
Проверьте:
docker compose version
Команда пишется через пробел: docker compose. Старый вариант через дефис docker-compose — это прежняя, отдельная программа, сейчас её не используют.
Первый compose.yaml
Вернитесь в папку my-site из урока 4 — там уже лежат index.html и Dockerfile. Создайте рядом файл compose.yaml:
services:
web:
build: .
ports:
- "8080:80"
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
volumes:
- pgdata:/var/lib/postgresql/data
adminer:
image: adminer
ports:
- "8081:8080"
depends_on:
- db
volumes:
pgdata:
В файле три сервиса — три контейнера:
web— ваш сайт:build: .собирает образ из Dockerfile в этой папке;db— PostgreSQL с паролем и томом, без портов наружу;adminer— веб-интерфейс к базе на порту 8081.
depends_on задаёт порядок: сначала запустить db, потом adminer. Внизу объявлен том pgdata.
В YAML важны отступы: вложенность показывают пробелами, табуляция не допускается. Самая частая ошибка в compose.yaml — съехавший отступ.
Запуск и остановка
docker compose up -d
Compose соберёт образ сайта, скачает недостающие образы, создаст сеть и том и запустит три контейнера. Откройте http://localhost:8080 — сайт, и http://localhost:8081 — Adminer. В Adminer укажите сервер db: сервисы одного файла сами попадают в общую сеть и находят друг друга по имени сервиса.
Остальные команды:
docker compose ps # контейнеры проекта
docker compose logs db # логи сервиса db
docker compose logs -f # логи всех сервисов в реальном времени
docker compose stop # остановить, не удаляя
docker compose down # остановить и удалить контейнеры и сеть
down не трогает тома: при следующем up данные базы на месте. Удалить вместе с томами — docker compose down -v. Это стирает данные, пользуйтесь осознанно.
Compose называет всё по имени папки проекта: контейнер my-site-db-1, том my-site_pgdata. Поэтому это новый том, а не pgdata из прошлых уроков — база в нём пустая.
Изменили код — пересоберите
Поменяйте текст в index.html и выполните:
docker compose up -d --build
--build пересобирает образы сервисов с build. Compose пересоздаст только контейнер web — база и Adminer продолжат работать.
Пароли — в .env
Файл compose.yaml обычно лежит в репозитории вместе с кодом. Пароль в нём увидит каждый, у кого есть доступ к репозиторию. Пароли выносят в файл .env рядом с compose.yaml:
POSTGRES_PASSWORD=secret
А в compose.yaml пишут ссылку на переменную:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
Compose сам прочитает .env и подставит значение. Добавьте .env в .gitignore, а в репозиторий положите пример .env.example с пустыми значениями — так коллеги поймут, какие переменные нужно задать.
Перезапуск после сбоя
Если программа упала или компьютер перезагрузился, контейнер останется остановленным. Чтобы Docker поднимал его сам, добавьте сервису политику перезапуска:
restart: unless-stopped
Контейнер будет перезапускаться всегда, кроме случаев, когда вы остановили его сами.
Попробуйте сами. Перенесите пароль базы из compose.yaml в .env, добавьте сервису db политику restart: unless-stopped и поднимите стенд. Создайте в Adminer таблицу, выполните docker compose down, затем снова up -d и убедитесь, что таблица на месте.
Решение
Файл .env:
POSTGRES_PASSWORD=secret
Сервис db в compose.yaml:
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
Команды:
docker compose up -d
# создали таблицу в Adminer: сервер db, пользователь postgres
docker compose down
docker compose up -d
Таблица на месте: down удалил контейнеры, но не том. Проверить, что Compose подставил пароль, можно командой docker compose config — она покажет итоговый файл со значениями.
Если сначала запустили базу с одним паролем, а потом поменяли его в .env, войти с новым паролем не получится. Пароль задаётся только при первом создании базы и хранится в томе. Для учебного стенда проще удалить том — docker compose down -v — и поднять заново.
Мини-тест: проверьте себя
Закрепите урок: несколько вопросов, разбор ответов — в конце.
-
Чем Docker Compose удобнее нескольких команд docker run?
Длинные команды с портами, томами и переменными легко забыть или набрать с ошибкой. Файл хранится вместе с проектом, и любой поднимет стенд одной командой.
-
Как сервис adminer найдёт базу из сервиса db в том же compose.yaml?
Compose создаёт для проекта общую сеть, и сервисы видят друг друга по именам из файла.
-
Что сделает docker compose down -v?
Без -v тома сохраняются, и при следующем up данные на месте. С -v Compose удаляет и тома — осторожно.
-
Где хранить пароль базы данных для compose.yaml?
compose.yaml обычно хранится в репозитории, и пароль увидят все. Compose подставляет значения из .env, а сам .env добавляют в .gitignore.