Production-ready шаблон docker-compose для тестового стенда
Готовый, production-ready шаблон docker-compose для тестового стенда, собранный по современным практикам (2024–2026). Конфигурация модульная, изолированная, детерминированная и готова к запуску в CI/CD или локально.
1. Базовый docker-compose.test.yml
name: test-stand # изолирует проект от других compose-окружений
services:
# 1. Веб-сервер
nginx:
image: nginx:1.25-alpine
ports:
- "8080:80"
volumes:
- ./nginx/test.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
app:
condition: service_healthy
networks: [test-net]
restart: unless-stopped
# 2. Тестируемое приложение
app:
build:
context: .
dockerfile: Dockerfile.test
env_file:
- .env.test
environment:
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}
- REDIS_URL=redis://redis:6379/0
depends_on:
postgres: {condition: service_healthy}
redis: {condition: service_healthy}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
timeout: 5s
retries: 3
networks: [test-net]
restart: unless-stopped
# 3. База данных
postgres:
image: postgres:15-alpine
env_file: .env.test
volumes:
- pg/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 5s
timeout: 5s
retries: 5
networks: [test-net]
restart: unless-stopped
# 4. Кеш / Очереди
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes: [redisdata:/data]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks: [test-net]
restart: unless-stopped
# 5. Логирование (опционально)
loki:
image: grafana/loki:2.9.0
ports: ["3100:3100"]
volumes: [loki/loki]
command: -config.file=/etc/loki/local-config.yaml
networks: [test-net]
# 6. Мониторинг (опционально)
grafana:
image: grafana/grafana:10.2.0
ports: ["3000:3000"]
env_file: .env.test
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
volumes: [grafana/var/lib/grafana]
depends_on: [loki]
networks: [test-net]
networks:
test-net:
driver: bridge
name: test-stand-net
volumes:
pg
redis
loki
grafana
2. Файл окружения .env.test
# .env.test (НЕ коммитьте в репозиторий!)
DB_USER=testuser
DB_PASSWORD=testpass123
DB_NAME=testdb
POSTGRES_USER=${DB_USER}
POSTGRES_PASSWORD=${DB_PASSWORD}
POSTGRES_DB=${DB_NAME}
GRAFANA_ADMIN_PASSWORD=admin
Docker Compose автоматически подхватывает
.env.test, если файл лежит рядом сdocker-compose.test.yml. В CI передавайте переменные черезenv_fileилиenvironment.
3. Ключевые особенности конфигурации
| Блок | Зачем | Рекомендация |
|---|---|---|
name: test-stand |
Изолирует сети, тома и контейнеры от других проектов | Обязательно для CI/CD и локальной параллельной работы |
condition: service_healthy |
Ждёт реальной готовности сервиса, а не только запуска контейнера | Заменяет устаревший depends_on без условия |
healthcheck |
Автоматическая проверка доступности | Настраивайте под ваш фреймворк (/health, pg_isready, redis-cli ping, curl) |
volumes + down -v |
Полный сброс состояния между прогонами | Для автотестов всегда используйте docker compose down -v |
networks: [test-net] |
Запрещает доступ к другим контейнерам на хосте | Обязательно для безопасности тестов |
Фиксированные теги (postgres:15-alpine) |
Гарантирует детерминированность сборок | Никогда не используйте latest в тестах |
4. Управление стендом
# Запуск (соберёт app и поднимет всё в фоне)
docker compose -f docker-compose.test.yml up -d --build
# Проверка статуса и healthcheck'ов
docker compose -f docker-compose.test.yml ps
# Логи приложения в реальном времени
docker compose -f docker-compose.test.yml logs -f app
# Подключение к контейнеру
docker compose -f docker-compose.test.yml exec app sh
# Полный снос стенда + удаление томов (чистое состояние для следующего прогона)
docker compose -f docker-compose.test.yml down -v
5. Адаптация под автотесты
Если стенд нужен только для запуска UI/E2E/интеграционных тестов, замените app на:
test-runner:
image: mcr.microsoft.com/playwright:v1.42.0-jammy
working_dir: /app
volumes:
- .:/app
environment:
- BASE_URL=http://nginx:80
- CI=true
depends_on:
app: {condition: service_healthy}
command: npx playwright test
networks: [test-net]
6. Интеграция в CI (GitHub Actions пример)
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-compose-action@v3
- name: Запуск тестового стенда
run: docker compose -f docker-compose.test.yml up -d --build
- name: Ожидание готовности
run: docker compose -f docker-compose.test.yml run --rm test-runner || true
- name: Логи при ошибке
if: failure()
run: docker compose -f docker-compose.test.yml logs
- name: Очистка
if: always()
run: docker compose -f docker-compose.test.yml down -v
7. Чек-лист перед коммитом
- Все образы зафиксированы по тегу (без
latest) - Настроены
healthcheckдля всех зависимостей .env.testдобавлен в.gitignore- В CI всегда вызывается
down -v - Сеть именована и не пересекается с production
- Нет хардкода паролей в YAML
nginx/test.confиdb/init/версиируются отдельно- Добавлен
.dockerignore(исключает.git,node_modules,venv,*.log)
8. Что можно добавить под ваш стек
| Ваш стек | Что заменить/добавить |
|---|---|
| Python (FastAPI/Django) | app → python:3.11-slim, command: uvicorn main:app --host 0.0.0.0 --port 8000 |
| Node.js (Nest/Express) | app → node:20-alpine, command: npm run start:test |
| MySQL вместо PostgreSQL | Заменить postgres на mysql:8, healthcheck: ["CMD", "mysqladmin", "ping", "-h", "localhost"] |
| MongoDB | mongo:6, healthcheck: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"] |
| Kafka | confluentinc/cp-kafka:7.5.0, zookeeper или kraft режим |
| Только API-тесты | Убрать nginx, пробросить порт app напрямую, добавить postman/newman или pytest |