Production-ready шаблон docker-compose для тестового стенда

Готовый docker-compose для тестового стенда: приложение, PostgreSQL, Redis, Nginx, мониторинг. Healthcheck-и, изоляция, CI-ready. Запуск одной командой.

2026.04.19                  


Production-ready шаблон docker-compose для тестового стенда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) apppython:3.11-slim, command: uvicorn main:app --host 0.0.0.0 --port 8000
Node.js (Nest/Express) appnode: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