Docker Compose¶
Docker Compose — інструмент для запуску та керування багатьма контейнерами як єдиним застосунком. Замість десятка docker run команд — один файл docker-compose.yml.
Навіщо Compose?¶
Уявіть типовий веб-застосунок:
Без Compose
docker run -d --name db -e POSTGRES_PASSWORD=secret postgres:15
docker run -d --name redis redis:7-alpine
docker run -d --name app --link db --link redis -p 8000:8000 myapp
docker run -d --name nginx --link app -p 80:80 nginx
# А тепер перезапустіть все... чи оновіть... чи перенесіть на інший сервер 😫
З Compose
docker compose up -d # Запустити все
docker compose down # Зупинити все
docker compose logs # Логи всіх сервісів
# Один файл — вся конфігурація ✨
Структура docker-compose.yml¶
# docker-compose.yml
services: # Список сервісів (контейнерів)
web: # Ім'я сервісу (буде ім'ям контейнера)
image: nginx # Образ для запуску
ports:
- "80:80" # Маппінг портів
db:
image: postgres:15
environment: # Змінні середовища
POSTGRES_PASSWORD: secret
volumes: # Томи для даних
- db_data:/var/lib/postgresql/data
volumes: # Оголошення іменованих томів
db_data:
Основні директиви¶
services¶
Кожен сервіс — це окремий контейнер:
services:
frontend:
image: nginx:alpine
backend:
build: ./backend # Побудувати з Dockerfile
database:
image: postgres:15
image vs build¶
services:
# Використати готовий образ
redis:
image: redis:7-alpine
# Побудувати з Dockerfile
app:
build: . # Dockerfile в поточній директорії
# Побудувати з кастомними параметрами
api:
build:
context: ./api
dockerfile: Dockerfile.prod
ports¶
services:
web:
ports:
- "80:80" # host:container
- "443:443"
- "127.0.0.1:8080:8080" # тільки localhost
environment¶
services:
db:
environment:
# Прямі значення
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
# Зі змінних оточення хоста
API_KEY: ${API_KEY}
# Зі значенням за замовчуванням
DEBUG: ${DEBUG:-false}
Або з файлу:
services:
app:
env_file:
- .env
- .env.local
volumes¶
services:
db:
volumes:
# Іменований том (рекомендовано для даних)
- db_data:/var/lib/postgresql/data
# Bind mount (для розробки)
- ./src:/app/src
# Read-only
- ./config:/etc/app/config:ro
volumes:
db_data: # Оголошення тому
┌────────────────────────────────────────────────────────┐
│ ТИПИ VOLUMES │
├────────────────────────────────────────────────────────┤
│ │
│ Named Volume (db_data:/path) │
│ ├── Керується Docker │
│ ├── Зберігається в /var/lib/docker/volumes/ │
│ └── Рекомендовано для production даних │
│ │
│ Bind Mount (./host/path:/container/path) │
│ ├── Пряме монтування директорії хоста │
│ ├── Зміни видно одразу │
│ └── Рекомендовано для розробки │
│ │
└────────────────────────────────────────────────────────┘
networks¶
services:
frontend:
networks:
- frontend_net
backend:
networks:
- frontend_net
- backend_net
db:
networks:
- backend_net
networks:
frontend_net:
backend_net:
По замовчуванню Compose створює одну мережу для всіх сервісів проєкту.
depends_on¶
services:
app:
depends_on:
- db
- redis
# app запуститься після db та redis
db:
image: postgres:15
redis:
image: redis:7
Важливо: depends_on чекає тільки запуску контейнера, а не готовності сервісу! Для перевірки готовності використовуйте healthcheck:
services:
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
app:
depends_on:
db:
condition: service_healthy
restart¶
services:
web:
restart: unless-stopped # Рекомендовано для production
worker:
restart: always # Завжди перезапускати
task:
restart: "no" # Не перезапускати (за замовчуванням)
cron:
restart: on-failure # Тільки при помилці
Команди¶
Запуск¶
# Запустити всі сервіси
docker compose up
# У фоновому режимі
docker compose up -d
# Перебудувати образи та запустити
docker compose up -d --build
# Запустити конкретні сервіси
docker compose up -d web db
Зупинка¶
# Зупинити та видалити контейнери
docker compose down
# Зупинити, видалити контейнери ТА томи
docker compose down -v
# Тільки зупинити (без видалення)
docker compose stop
Логи¶
# Логи всіх сервісів
docker compose logs
# В реальному часі
docker compose logs -f
# Конкретного сервісу
docker compose logs -f web
# Останні 100 рядків
docker compose logs --tail 100 web
Статус¶
# Список запущених контейнерів
docker compose ps
# Всі (включно з зупиненими)
docker compose ps -a
Виконання команд¶
# Виконати команду в сервісі
docker compose exec web bash
# Одноразово запустити команду
docker compose run --rm web python manage.py migrate
Практичний приклад: WordPress + MySQL¶
Створимо повноцінний WordPress з базою даних.
Структура проєкту¶
wordpress-site/
├── docker-compose.yml
├── .env
└── data/ # Буде створено автоматично
├── mysql/
└── wordpress/
docker-compose.yml¶
services:
db:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
wordpress:
image: wordpress:latest
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress_data:/var/www/html
volumes:
mysql_data:
wordpress_data:
.env¶
MYSQL_ROOT_PASSWORD=supersecretroot123
MYSQL_PASSWORD=wordpresspass456
Запуск¶
# Створити директорію та файли
mkdir wordpress-site && cd wordpress-site
# Створити docker-compose.yml та .env як вище
# Запустити
docker compose up -d
# Перевірити
docker compose ps
docker compose logs -f
# Відкрити http://localhost:8080
Керування¶
# Бекап бази даних
docker compose exec db mysqldump -u root -p wordpress > backup.sql
# Зайти в MySQL
docker compose exec db mysql -u root -p
# Оновити WordPress
docker compose pull wordpress
docker compose up -d
Мережі в Compose¶
┌─────────────────────────────────────────────────────────────────┐
│ Docker Compose Network │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ wordpress │ ──────── │ db │ │
│ │ │ "db" │ (mysql) │ │
│ │ port:8080 │ │ port:3306 │ │
│ └─────────────┘ └─────────────┘ │
│ │ │ │
│ │ │ │
│ └── DNS: "wordpress" ────┴── DNS: "db" │
│ │
│ Контейнери бачать один одного за іменем сервісу! │
└─────────────────────────────────────────────────────────────────┘
В Compose сервіси автоматично можуть звертатись один до одного за іменем:
- wordpress може підключитись до db:3306
- Не потрібно вказувати IP адреси
Типові помилки¶
Порт вже зайнятий¶
# Помилка
Error: bind: address already in use
# Знайти що займає порт
lsof -i :8080
# Змінити порт в docker-compose.yml
ports:
- "8081:80" # Використати інший порт
База даних не готова¶
# Проблема: застосунок стартує раніше за БД
# Рішення: healthcheck + condition
services:
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
retries: 5
app:
depends_on:
db:
condition: service_healthy
Файли не синхронізуються¶
# Для розробки на Linux/Mac — працює одразу
volumes:
- ./src:/app/src
# На Windows можуть бути проблеми з правами
# Рішення: використовувати WSL2
Втрата даних після down¶
# Проблема
docker compose down -v # -v видаляє томи!
# Рішення: використовувати іменовані томи та не вказувати -v
docker compose down # Безпечно — томи залишаються
Поради¶
Development vs Production¶
# docker-compose.yml — базова конфігурація
services:
app:
image: myapp
# docker-compose.override.yml — для розробки (автоматично зчитується)
services:
app:
build: .
volumes:
- ./src:/app/src
environment:
DEBUG: "true"
# docker-compose.prod.yml — для production
services:
app:
restart: unless-stopped
environment:
DEBUG: "false"
# Розробка (використовує override автоматично)
docker compose up
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
.dockerignore¶
Щоб не копіювати зайве при build:
# .dockerignore
.git
.env
*.md
__pycache__
node_modules
.vscode
Див. також¶
- Що таке Docker? — основи контейнеризації
- Docker команди — шпаргалка
- Бази даних — робота з PostgreSQL
Шлях: infrastructure/docker-compose-intro.md