Перейти к содержанию

Compose-паттерны для DE

Compose-паттерны для дата-инженера

Docker Compose — стандартный инструмент для локальной разработки и лёгкого продакшена. В DE Compose поднимает целый стек: PostgreSQL, Airflow, dbt, Kafka, Redis — одной командой.


Profiles — условный запуск сервисов

Не все сервисы нужны всегда. Profiles позволяют группировать сервисы.

YAML
services:
  db:
    image: postgres:15-alpine
    # Без profile → запускается всегда

  backend:
    image: myapp:latest
    depends_on: [db]

  airflow-webserver:
    image: apache/airflow:2.8.0
    profiles: [airflow]          # Только при --profile airflow

  airflow-scheduler:
    image: apache/airflow:2.8.0
    profiles: [airflow]

  kafka:
    image: confluentinc/cp-kafka:7.5.0
    profiles: [kafka]

  jupyter:
    image: jupyter/pyspark-notebook:latest
    profiles: [dev]              # Только для разработки
Bash
# Базовый стек
docker compose up -d

# С Airflow
docker compose --profile airflow up -d

# Полный стек
docker compose --profile airflow --profile kafka --profile dev up -d

Типичный DE-стек

YAML
# docker-compose.yml
services:
  db:
    image: postgres:15-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: etl_kitchen
      POSTGRES_USER: etl_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U etl_user -d etl_kitchen"]
      interval: 10s
      timeout: 5s
      retries: 5
    deploy:
      resources:
        limits:
          memory: 1G
          cpus: "1.0"
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s

  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      DATABASE_URL: postgresql://etl_user:${DB_PASSWORD}@db:5432/etl_kitchen
      REDIS_URL: redis://redis:6379/0
    ports:
      - "8000:8000"

volumes:
  db_data:

depends_on с healthcheck

YAML
services:
  backend:
    depends_on:
      db:
        condition: service_healthy      # Ждать пока pg_isready
      redis:
        condition: service_healthy
      kafka:
        condition: service_started      # Просто запущен (нет healthcheck)

Без condition: service_healthy контейнер стартует, но PostgreSQL ещё не готов → приложение падает с connection refused.


Override-файлы

YAML
# docker-compose.yml — базовый (продакшн)
services:
  backend:
    image: myregistry/backend:latest

# docker-compose.override.yml — автоматически подхватывается!
services:
  backend:
    build: ./backend           # Локальная сборка вместо pull
    volumes:
      - ./backend:/app         # Live-reload
    environment:
      DEBUG: "true"
Bash
# Разработка (подхватит override автоматически)
docker compose up

# Продакшн (только базовый)
docker compose -f docker-compose.yml up -d

# Явный набор файлов
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

watch — автоперезагрузка (Compose 2.22+)

YAML
services:
  backend:
    build: ./backend
    develop:
      watch:
        - action: sync          # Синхронизировать файлы
          path: ./backend/app
          target: /app/app

        - action: rebuild        # Пересобрать образ
          path: ./backend/requirements.txt

        - action: sync+restart   # Синхронизировать + рестарт
          path: ./backend/config.yml
          target: /app/config.yml
Bash
docker compose watch
# Изменил app/main.py → автоматически синхронизируется в контейнер
# Изменил requirements.txt → автоматически rebuild

Resource limits

YAML
services:
  db:
    deploy:
      resources:
        limits:
          memory: 2G
          cpus: "2.0"
        reservations:
          memory: 512M
          cpus: "0.5"

  backend:
    deploy:
      resources:
        limits:
          memory: 512M

Без limits контейнер съест весь RAM

PostgreSQL без ограничений может потребить всю память хоста, вызвав OOM-killer. Всегда ставь limits.memory.


Networking

YAML
services:
  backend:
    networks:
      - frontend
      - backend

  db:
    networks:
      - backend          # НЕ доступна из frontend

  nginx:
    networks:
      - frontend

networks:
  frontend:
  backend:
    internal: true       # Нет доступа в интернет

Правила:

  • БД — только в backend сети (не видна снаружи)
  • Приложение — в обеих сетях (принимает запросы, обращается к БД)
  • Nginx/proxy — только в frontend

Секреты (Docker Secrets)

YAML
services:
  db:
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt    # Локально
  # Или в Docker Swarm:
  # external: true

Для Compose без Swarm — проще через .env:

Bash
# .env (НЕ коммитить в git!)
DB_PASSWORD=strong_password_here
YAML
# docker-compose.yml
services:
  db:
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}

Полезные команды

Bash
# Запустить в фоне
docker compose up -d

# Пересобрать образы
docker compose up -d --build

# Логи конкретного сервиса
docker compose logs -f backend

# Выполнить команду в работающем контейнере
docker compose exec db psql -U etl_user -d etl_kitchen

# Остановить и удалить (с volumes)
docker compose down -v

# Показать ресурсы
docker compose top
docker stats

Проверь себя


Источники