docker run.
Това е начин да опиша цялото приложение като конфигурация: services, networks, volumes и настройки.
Целта е stack-ът да бъде възпроизводим и предвидим.
1. Защо ми трябва Docker Compose?
Един container е лесен за управление. Проблемът започва, когато приложението има web server, database, cache, worker и още няколко services. Тогава ръчното стартиране с поредица от docker run команди бързо се превръща в рецепта за грешки.
Compose решава това, като описва желаното състояние на целия stack в YAML файл. Вместо да помня десетки команди, поддържам една декларативна конфигурация.
описание на stack-а
контейнери
връзка и постоянни данни
2. Compose файлът
Съвременният Docker Compose използва Compose Specification. Обикновено файлът се нарича compose.yaml или compose.yml. Не добавям старото version:, когато няма конкретна причина да го правя.
services:
web:
image: nginx:alpine
ports:
- "8080:80"Тук имам един service с име web. Compose създава container от посочения image и публикува порт 8080 на host към порт 80 в container.
3. Services — сърцето на Compose
Всеки запис под services: описва отделен service. Например web и database могат да бъдат управлявани като един stack.
services:
web:
image: nginx:alpine
ports:
- "8080:80"
db:
image: mariadb:11
environment:
MARIADB_DATABASE: app
MARIADB_USER: app
MARIADB_PASSWORD: change-me
MARIADB_ROOT_PASSWORD: change-me-too4. Networking между services
Compose създава network за проекта, ако не съм задал друга конфигурация. Services в една Compose network се намират по service name.
services:
app:
image: myapp:latest
db:
image: mariadb:11Приложението се свързва с database-а чрез hostname db, а не чрез IP адрес на container-а. Това е важно, защото IP адресите могат да се променят при recreate.
5. Volumes — данните трябва да преживяват container-а
Container-ът е заменим. Данните не трябва да бъдат. За database използвам volume или друг подходящ persistent storage.
services:
db:
image: mariadb:11
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:6. Environment Variables и .env
За настройки, които се променят между среди, използвам environment variables. Това позволява Compose файлът да остане един и същ.
DB_NAME=app
DB_USER=app
DB_PASSWORD=change-me
DB_ROOT_PASSWORD=change-me-tooservices:
db:
image: mariadb:11
environment:
MARIADB_DATABASE: ${DB_NAME}
MARIADB_USER: ${DB_USER}
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}7. Основните Compose команди
# Стартиране на stack-а във фонов режим
docker compose up -d
# Състояние на services
docker compose ps
# Логове
docker compose logs
# Логове само за конкретен service
docker compose logs -f web
# Спиране
docker compose stop
# Стартиране отново
docker compose start
# Спиране и премахване на containers и networks
docker compose downРазликата между stop и down е важна. stop спира containers. down премахва създадените от Compose containers и networks. Named volumes не се премахват от обикновеното down.
8. Какво става при промяна?
Когато променя image, ports, environment или друга част от конфигурацията, Compose може да пресъздаде container-а.
# Прилагане на промените
docker compose up -d
# При необходимост — принудително пресъздаване
docker compose up -d --force-recreateТова е още една причина данните да бъдат във Volumes, а не само във writable layer-а на container-а.
9. depends_on и Healthcheck
Фактът, че database container-ът е стартиран, не означава непременно, че database server-ът вече приема connections. При реални приложения това често е източник на проблеми.
services:
db:
image: mariadb:11
healthcheck:
test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
app:
image: myapp:latest
depends_on:
db:
condition: service_healthyТака зависимостта е свързана с реалното здравословно състояние на service-а, а не само с факта, че container-ът съществува.
10. Profiles
Не всеки service трябва да работи постоянно. Profiles са удобни за инструменти, тестове и административни services.
services:
app:
image: myapp:latest
adminer:
image: adminer:latest
profiles:
- tools# Само основният stack
docker compose up -d
# С включен profile
docker compose --profile tools up -d11. Как подреждам Compose проекта
Не оставям конфигурацията, данните и backup-ите в една и съща бъркотия. Подреждам проекта така, че след време да мога да разбера какво съм направил.
my-stack/
├── compose.yaml
├── .env
├── .gitignore
├── config/
│ └── app.conf
├── data/
└── backup/Това е пример, не задължителна схема. Конкретната структура зависи от приложението и начина, по който съхранявам данните.
12. Compose в Production
| Област | Какво проверявам |
|---|---|
| Images | Използвам контролирани версии и не разчитам сляпо на latest. |
| Data | Критичните данни са в подходящо persistent storage. |
| Backup | Има отделен backup процес и периодично проверявам restore. |
| Secrets | Паролите не се разнасят в repository и публични конфигурации. |
| Networking | Публикувам само портовете, които действително трябва да са достъпни. |
| Updates | Имам предвидим начин за обновяване и възстановяване. |
13. Един реален малък Stack
Следващият пример събира основните идеи в една конфигурация: web service, database, отделни networks и persistent volume.
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
networks:
- frontend
volumes:
- ./html:/usr/share/nginx/html:ro
db:
image: mariadb:11
environment:
MARIADB_DATABASE: app
MARIADB_USER: app
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- db_data:/var/lib/mysql
networks:
- backend
networks:
frontend:
backend:
volumes:
db_data:В реална application архитектура бих поставил application service между web и database. Идеята е database-ът да не бъде директно изложен към Internet.
14. Диагностика
Когато stack-ът не работи, не започвам с произволни рестартирания. Първо проверявам състоянието, конфигурацията и логовете.
# Състояние
docker compose ps
# Последните логове
docker compose logs --tail=100
# Логове на конкретен service
docker compose logs --tail=100 -f app
# Проверка на обработената конфигурация
docker compose config
# Networks
docker network ls
# Volumes
docker volume lsОсобено полезна е docker compose config. Тя ми показва как Compose интерпретира конфигурацията и environment variables, преди да започна да гадая.
15. Заключение
Docker Compose е моментът, в който Docker започва да се превръща от набор контейнери в управляема инфраструктура. Services, networks, volumes и configuration вече са описани на едно място.
За мен най-важното предимство не е удобството на една команда. То е предвидимостта. Знам какво трябва да има, как трябва да бъде свързано и какво трябва да остане след пресъздаване на containers.