Що таке docker-compose?
Docker Compose це стандартний спосіб описати і запускати multi-container Docker-застосунки. Замість того, щоб писати довгий docker run на кожен сервіс плюс docker network create плюс управління volume, ти описуєш увесь стек у YAML-файлі і піднімаєш його однією командою.
Теорія
TL;DR
- YAML-файл (дефолтне ім'я:
compose.yamlабо legacydocker-compose.yml) описує сервіси, мережі і volume твого застосунку. - Одна команда піднімає все (
docker compose up), одна знімає (docker compose down). - Кожен сервіс стає container; Compose створює приватну bridge-мережу, тож сервіси знаходять один одного по імені (
db,api). - Стандарт для локальної розробки і single-host деплоїв. Для multi-host прода зазвичай береш Swarm або Kubernetes.
docker compose(v2, Go-плагін) актуальний.docker-compose(v1, Python) deprecated з 2023.
Швидкий приклад
# compose.yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
depends_on:
- api
api:
build: ./api
environment:
DATABASE_URL: postgres://postgres:devpass@db:5432/app
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpass
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
volumes:
pgdata:$ docker compose up -d
[+] Running 4/4
✔ Network myapp_default Created
✔ Container myapp-db-1 Healthy
✔ Container myapp-api-1 Started
✔ Container myapp-web-1 StartedОдна команда, три сервіси, мережа і volume. Відтворювано на будь-якій машині з Docker.
Основні блоки compose-файлу
services: # один блок на container
<name>:
image: ... # АБО build: ./path (зібрати з Dockerfile)
container_name: ... # опц., фіксоване ім'я; інакше <project>-<service>-<index>
command: ["..."] # override CMD
entrypoint: ["..."] # override ENTRYPOINT
ports: ["8080:80"] # публікація портів HOST:CONTAINER
expose: ["5000"] # тільки внутрішньо, без публікації
environment: # env-змінні (map або list)
KEY: value
env_file: .env # env-змінні з файлу
volumes: # mount (named volume або bind mount)
- data:/var/lib/...
- ./conf:/etc/conf:ro
networks: [frontend, backend]
depends_on: # порядок старту + health gate
<other-service>:
condition: service_healthy
restart: unless-stopped
healthcheck: { test: [...], interval: 30s }
deploy: # ліміти ресурсів, replica (працює у Compose з v2)
resources:
limits: { cpus: "0.5", memory: 512M }
networks: # named мережі (дефолт: одна bridge на project)
frontend:
backend:
volumes: # named volume
data:Більшість реальних застосунків використовує підмножину. 80% це services з image/build, ports, environment, volumes, depends_on.
Команди життєвого циклу
docker compose up # старт (foreground, стрімить логи)
docker compose up -d # старт detached
docker compose down # stop і видалити container + мережу
docker compose down -v # ще й видалити volume (ДЕСТРУКТИВНО)
docker compose ps # список сервісів цього project
docker compose logs -f # tail логи з усіх сервісів
docker compose logs api # тільки один сервіс
docker compose exec api sh # shell у запущений сервіс
docker compose run --rm api npm test # одноразова команда у новому container
docker compose build # перезбірка image для сервісів з build:
docker compose pull # тягти image для сервісів з image:
docker compose restart api # рестарт одного сервісу
docker compose stop / start # без видалення
docker compose config # валідувати і вивести resolved configProject-ім'я приходить з імені директорії за замовчуванням. Override через флаг -p або env-змінну COMPOSE_PROJECT_NAME.
Як сервіси знаходять одне одного
Compose створює дефолтну bridge-мережу на project. Всі сервіси приєднуються автоматично. Всередині цієї мережі імена сервісів резолвляться через embedded DNS Docker:
services:
web:
image: myapp
environment:
DB_HOST: db # ← просто "db", не localhost і не IP
db:
image: postgres:16З container web ping db працює. Hostname db резолвиться у IP db-container. Без localhost, без host.docker.internal, без ручної мережі.
v1 vs v2 (і чому це важливо у 2026)
docker-compose(v1) був Python-інструментом, окремим від Docker daemon. З дефісом. Deprecated з липня 2023.docker compose(v2) Go-плагін, вбудований у сучасний Docker. Пробіл, не дефіс. Поточний стандарт.
Якщо бачиш docker-compose у старих туторіалах, команди майже ідентичні, але сьогодні маєш запускати docker compose. Більшість дистрибутивів за замовчуванням постачають v2; v1 більше не підтримується.
Типові помилки
Плутати down зі stop
docker compose stop # зупиняє container; усе ще існує
docker compose down # зупиняє І видаляє container + project-мережу
docker compose down -v # ще й стирає volume (data loss!)Новачки роблять down -v недбало і втрачають свою dev-базу.
Використовувати localhost для зв'язку між сервісами
# НЕПРАВИЛЬНО: всередині container `api` localhost це сам container api
DATABASE_URL: postgres://postgres@localhost:5432/app
# ПРАВИЛЬНО: бери ім'я сервісу
DATABASE_URL: postgres://postgres@db:5432/appКожен container має свій loopback. Трафік між сервісами іде по імені, ніколи не localhost.
Забути condition: service_healthy у depends_on
# НЕПРАВИЛЬНО: api стартує коли db-container стартує, НЕ коли db готовий приймати запити
depends_on: [db]
# ПРАВИЛЬНО: api стартує лише після того, як healthcheck db пройшов
depends_on:
db:
condition: service_healthyПроста list-форма лише впорядковує старти container. Map-форма з condition реально чекає readiness, припускаючи, що залежність має healthcheck.
Bind-mount node_modules на Mac/Windows
# Повільно на Docker Desktop через cross-VM sync
volumes:
- .:/app
# Швидше: тримай node_modules у named volume, поза bind-sync
volumes:
- .:/app
- api_node_modules:/app/node_modulesКласичний local-dev gotcha, що 2-секундні install-и перетворює на 60-секундні чекання.
Реальне застосування
- Локальні dev-середовища: домінантний use case.
git clone && docker compose upстандартний onboarding. - CI/CD тестові фікстури: піднімаємо Postgres + Redis + mock-залежності застосунку одним кроком, проганяємо інтеграційні тести, знімаємо.
- Single-host production: малі сервіси, side-проекти, внутрішні інструменти. Compose +
restart: unless-stopped+ reverse proxy це цілком ОК стек для low-traffic застосунків. - Demo і tutorial репо: кожен інструмент, що хоче, щоб ти його спробував локально, постачає Compose-файл. Тепер дефолтне очікування.
Питання для поглиблення
Q: Яка різниця між docker compose up і docker compose run?
A: up стартує сервіс як частину running-стеку (довгоживучий, приєднаний до мережі, порти опубліковані). run створює одноразовий новий container на основі того ж service-config, зазвичай для one-shot задач (docker compose run api npm test). run НЕ публікує порти за замовчуванням, поки не додаси --service-ports.
Q: Чи можна мати кілька Compose-файлів для одного project?
A: Так: docker compose -f compose.yaml -f compose.dev.yaml up. Пізніші файли перекривають раніші. Поширений патерн: базовий compose.yaml з прод-shaped config, compose.override.yaml (авто-завантажується) або compose.dev.yaml з dev-доповненнями (bind mount, відкриті dev-порти, hot reload).
Q: Що таке Compose profile?
A: Спосіб позначити сервіси як opt-in. profiles: [debug] у сервісі означає, що він стартує лише при docker compose --profile debug up. Корисно для debug-container, інтеграційних тестів або опційних monitoring-sidecar, які не завжди хочеш мати запущеними.
Q: Коли Compose недостатньо?
A: Multi-host деплой, авто-failover, rolling update, автомасштабування, Compose це single-host і нічого з цього не робить. Коли потрібно, переходь на Docker Swarm (ще простіший за K8s) або Kubernetes (індустрійний дефолт для multi-host).
Q: (Senior) Як організувати Compose-проект для prod, staging і dev з мінімумом дублювання?
A: Базовий compose.yaml з усіма сервісами і shared-config (image, volume, healthcheck). Тоді compose.dev.yaml (bind mount, відкриті dev-інструменти), compose.staging.yaml (інші домени, без debug, менші ресурс-ліміти), compose.prod.yaml (resource caps, restart-політики, без відкритих dev-портів). Використовуй docker compose -f compose.yaml -f compose.<env>.yaml up. Усе secret поза YAML, бери env_file, що вказує на environment-specific dotenv-файли, які не комітяться.
Приклади
Три-сервісний застосунок (web + api + db)
# compose.yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on: [api]
api:
build: ./api
environment:
DATABASE_URL: postgres://postgres:devpass@db:5432/app
NODE_ENV: production
depends_on:
db:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpass
POSTGRES_DB: app
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
volumes:
pgdata:$ docker compose up -d --build # збірка image api, старт усього
$ docker compose logs -f api # tail логи api
$ docker compose exec api sh # shell у api
$ docker compose down # stop, лишити volumeПатерн dev-override
# compose.override.yaml (авто-завантажується якщо є)
services:
api:
build:
target: dev # multi-stage Dockerfile зі стейджем 'dev'
volumes:
- ./api/src:/app/src # live source mount для hot reload
environment:
NODE_ENV: development
command: npm run dev # override прод CMD
ports:
- "9229:9229" # node debug-порт$ docker compose up -d # авто-merge compose.yaml + compose.override.yamlProd-shaped база плюс dev-override дає ті самі сервіси з dev-доповненнями зверху.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів