Що таке Docker Compose
У реальному світі застосунок рідко складається з одного контейнера: бекенду на Java потрібні база даних PostgreSQL, кеш Redis, брокер повідомлень Kafka та панель моніторингу.
🟢 Junior Level
30-секундна відповідь
Docker Compose — це декларативний інструмент для оркестрації та одночасного запуску багатоконтейнерних застосунків (Multi-Container Applications) на одному сервері за допомогою одного файлу конфігурації compose.yaml (або docker-compose.yml).
У реальному світі застосунок рідко складається з одного контейнера: бекенду на Java потрібні база даних PostgreSQL, кеш Redis, брокер повідомлень Kafka та панель моніторингу.
- Замість того щоб вручну виконувати десятки довгих команд
docker runіз налаштуванням портів, томів та мереж, ви описуєте всю систему у YAML-файлі. - Команда
docker compose up -dоднією операцією створює віртуальну мережу, виділяє томи та підіймає всі взаємопов’язані сервіси в правильному порядку.
Наочна аналогія з життя
- Docker CLI (
docker run) — це керування окремими музикантами: ви підходите до барабанщика, гітариста та піаніста і кожному окремо кажете, коли починати грати. - Docker Compose — це диригент оркестру: за єдиною партитурою (
compose.yaml) він помахом палички запускає весь оркестр синхронно, стежить за тим, щоб музиканти чули один одного (мережа) і щоб піаніно було налаштоване до початку симфонії (depends_on).
Наочний приклад для Spring Boot 3 та PostgreSQL
# compose.yaml (у сучасних версіях поле 'version' застаріло і не потрібне)
services:
app:
build: .
ports:
- "8080:8080"
environment:
# Сервіси звертаються один до одного за ім'ям сервісу 'postgres-db':
- SPRING_DATASOURCE_URL=jdbc:postgresql://postgres-db:5432/orders_db
- SPRING_DATASOURCE_USERNAME=postgres
- SPRING_DATASOURCE_PASSWORD=secret
depends_on:
postgres-db:
condition: service_healthy # Чекаємо на реальну готовність БД!
postgres-db:
image: postgres:16-alpine
environment:
- POSTGRES_DB=orders_db
- POSTGRES_PASSWORD=secret
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata: # Іменований том для збереження даних БД
# Запуск усієї інфраструктури у фоновому режимі:
docker compose up -d
# Перегляд логів бекенду в реальному часі:
docker compose logs -f app
# Повна зупинка всіх сервісів та видалення мереж:
docker compose down
🟡 Middle Level
Внутрішня мережа та вбудований DNS (Embedded DNS)
Коли Docker Compose підіймає сервіси:
- Він автоматично створює ізольовану віртуальну мережу типу bridge (за замовчуванням
project_default). - Усередині цієї мережі активується вбудований DNS-сервер Docker (доступний за службовою адресою
127.0.0.11). - Імена сервісів у YAML стають доменними іменами: Java-застосунку не потрібно знати IP-адресу бази даних; виклик
postgres-db:5432автоматично резолвиться в поточну внутрішню IP-адресу контейнера бази даних.
ports vs expose
ports: ["8080:8080"]: прокидає порт контейнера на фізичний мережевий інтерфейс хост-машини (Host Port Binding). Сервіс стає доступним ззовні контейнерної мережі (наприклад, у браузері розробника за адресоюhttp://localhost:8080).expose: ["5432"]: відкриває порт тільки для інших контейнерів усередині спільної Docker-мережі, не публікуючи його на хості. Це безпечний вибір для баз даних та внутрішніх брокерів, що захищає їх від зовнішніх атак.
Пастка depends_on та правильний Healthcheck
Розробники-початківці часто стикаються з помилкою:
# ❌ НЕПРАВИЛЬНО: Застосунок впаде під час старту!
services:
app:
depends_on:
- postgres-db
- Чому це ламається: за замовчуванням
depends_onгарантує тільки факт запуску процесу контейнера БД. - Але СУБД PostgreSQL після старту виконує ініціалізацію файлів та створення баз даних, що займає 3–10 секунд.
- Застосунок Spring Boot стартує швидше, намагається встановити з’єднання з базою, отримує
Connection refusedі падає зApplication failed to start. - Рішення: використовувати
condition: service_healthyу поєднанні з директивоюhealthcheck: test: ["CMD-SHELL", "pg_isready"].
🔴 Senior Level
Інтеграція Spring Boot 3.1+ з Docker Compose (Auto-Configuration)
У Spring Boot 3.1 з’явилася нативна інтеграція з Docker Compose (spring-boot-docker-compose):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
- Автоматичний запуск: під час виконання команди
mvn spring-boot:runв IDE Spring Boot сам знаходить файлcompose.yamlу корені проєкту та виконуєdocker compose up. - Динамічна ін’єкція Connection Details: Spring Boot самостійно парсить відкриті порти Postgres, Redis або Kafka і динамічно інжектує JDBC URL, username та password в
ApplicationContextбез необхідності ручного налаштуванняapplication.yml! - Автоматична зупинка: під час зупинки застосунку в IDE Spring Boot автоматично гасить контейнери.
Мережева сегментація безпеки (Zero Trust Networks)
У Production-середовищі монолітна спільна мережа є ризиком безпеки. Compose дозволяє розділити топологію:
services:
api-gateway:
image: nginx:alpine
ports: ["80:80"]
networks: [frontend-net]
order-service:
image: order-service:1.0
networks: [frontend-net, backend-net]
postgres-db:
image: postgres:16-alpine
networks: [backend-net] # БД фізично ізольована від Nginx!
networks:
frontend-net:
backend-net:
Зловмисник, що скомпрометував вебсервер Nginx, фізично не зможе надіслати пакети в порт 5432 бази даних PostgreSQL.
Горизонтальне масштабування (--scale) та колізія портів
Команда docker compose up --scale order-service=3 дозволяє запустити 3 репліки сервісу.
- Пастка: якщо в
compose.yamlоголошено статичний мапінгports: ["8080:8080"], запуск масштабування впаде з помилкоюBind for 0.0.0.0:8080 failed: port is already allocated. - Рішення для масштабування: вказувати тільки порт контейнера без прив’язки до порту хоста (
ports: ["8080"]) для випадкового виділення порту, або використовувати тільки внутрішню мережу з балансувальником навантаження (Nginx/Traefik).
4 Tricky Questions
1. Чому команда docker compose up --scale service=3 падає з помилкою, якщо у сервісу вказано мапінг ports: ["8080:8080"], і як налаштувати балансування?
Відповідь:
Мережевий стек операційної системи хоста не дозволяє двом різним процесам зайняти один і той самий TCP-порт (8080) на одному мережевому інтерфейсі (помилка Address already in use).
Щоб масштабувати сервіс:
- Прибрати мапінг портів на хост або вказати діапазон:
ports: ["8080-8082:8080"](або динамічний порт"8080"). - Запустити перед масштабованими сервісами легковажний зворотний проксі (Nginx або Traefik), підключений до тієї ж мережі. Проксі приймає трафік на зовнішній порт
80і балансує вхідні запити між трьома контейнерами за їхнім внутрішнім DNS-ім’ям сервісу (Docker DNS автоматично розподіляє запити методом Round-Robin).
2. У чому фундаментальна різниця між командами docker compose down та docker compose down -v? До якої катастрофи може призвести випадкове додавання прапорця -v?
Відповідь:
docker compose down: зупиняє та видаляє запущені контейнери і створені віртуальні мережі, але залишає недоторканими іменовані томи (Volumes). Дані бази даних на диску зберігаються в повній безпеці.docker compose down -v(або--volumes): разом із контейнерами безповоротно видаляє всі іменовані томи, оголошені в секціїvolumes:! Якщо виконати цю команду на сервері з робочою базою даних, весь каталог/var/lib/postgresql/dataбуде миттєво стертий з диска без можливості відновлення.
3. Чому Java-застосунок, запущений локально в IDE на хост-машині (не в Docker), не може підключитися до БД за адресою jdbc:postgresql://postgres-db:5432/mydb, оголошеною в compose.yaml?
Відповідь:
Доменне ім’я сервісу postgres-db реєструється тільки у внутрішньому DNS-сервері Docker (127.0.0.11), що працює виключно всередині створеної віртуальної мережі bridge.
Операційна система хоста використовує свій власний системний DNS (роутер або провайдер) і не має доступу до DNS-таблиць Docker.
Щоб локальний застосунок з IDE підключився до БД:
- У секції
postgres-dbмає бути прокинутий порт на хост:ports: ["5432:5432"]. - У локальному
application.ymlадреса має вказувати на хост:jdbc:postgresql://localhost:5432/mydb.
4. Що таке файли оверрайдів (docker-compose.override.yml), і як вони об’єднуються з основним файлом конфігурації?
Відповідь:
За замовчуванням під час запуску docker compose up рушій автоматично шукає два файли: основний compose.yaml та файл перевизначень docker-compose.override.yml, виконуючи їхнє глибоке злиття (Deep Merge):
- Конфігурації об’єднуються: якщо в основному файлі вказано
image, а в override вказаноports: ["5432:5432"]та локальнийbuild: ., то підсумковий сервіс об’єднає обидві директиви. - Списки (наприклад,
ports,environment) конкатенуються. - Це дозволяє тримати в репозиторії чистий базовий
compose.yamlдля тестових стендів, а розробникам локально створювати.override.yml(доданий у.gitignore) для прокидання локальних портів налагодження та підключення вихідних кодів через volume.
🎯 Шпаргалка для інтерв’ю
Головне про Docker Compose
- Що це: інструмент оркестрації багатоконтейнерних систем на одному хості.
- Конфігурація: файл
compose.yaml(секції:services,networks,volumes). - Мережева взаємодія: вбудований DNS (
127.0.0.11); контейнери спілкуються за ім’ям сервісу. - Синхронізація старту: використовувати
depends_onу зв’язці зcondition: service_healthy. - Spring Boot 3.1+: бібліотека
spring-boot-docker-composeавтоматично підіймає інфраструктуру під час старту застосунку. - Зберігання даних: дані БД зберігати суворо в іменованих
volumes:. - Обмеження: призначений для одного хоста; не замінює Kubernetes у production (немає multi-node, немає HPA, немає rolling update).
Docker Compose vs Kubernetes
| Критерій | Docker Compose | Kubernetes |
| :— | :— | :— |
| Середовище застосування | Локальна розробка, прості VPS | Великий продакшен, хмари |
| Кількість вузлів | Суворо 1 хост-сервер | Кластер із сотень серверів |
| Автомасштабування| ❌ Немає | 🟢 Є (Horizontal Pod Autoscaler) |
| Self-Healing | ❌ Обмежений (restart: always) | 🟢 Автоперезапуск та міграція подів |
| Складність порогу входу | 🟢 Низька (кілька годин) | 🔴 Висока (тижні навчання) |
Червоні прапорці на співбесіді (Чого говорити не можна)
- ❌ «depends_on гарантує, що БД повністю готова до прийому запитів» — він чекає тільки старту контейнера; потрібен
service_healthy. - ❌ «Docker Compose використовується для керування кластером із 10 серверів у продакшені» — Compose працює тільки на одній машині.
- ❌ «Щоб видалити контейнери, я завжди пишу docker compose down -v» — прапорець
-vзнищує всі дані баз даних у volumes!