Приведи пример решения проблемы при развертывании базы данных в контейнере

«Приведи пример решения проблемы при развертывании базы данных в контейнере» — вопрос из категории Базы данных, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Частая проблема при запуске БД в Docker — потеря данных при пересоздании контейнера и проблемы с производительностью I/O. Сталкивался с этим при развертывании PostgreSQL.

Проблема: После docker-compose down и docker-compose up данные в базе обнулялись, так как том для данных не был настроен.

Решение: Использование Docker Volumes для сохранения данных и настройка производительности.

1. Корректный docker-compose.yml для PostgreSQL:

version: '3.8'
services:
  postgres:
    image: postgres:15-alpine
    container_name: app_postgres
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: app_user
      POSTGRES_PASSWORD: ${DB_PASSWORD} # Переменная из .env
    ports:
      - "5432:5432"
    volumes:
      # Постоянный том для данных
      - postgres_data:/var/lib/postgresql/data
      # Монтирование кастомных конфигов для тонкой настройки
      - ./postgresql.conf:/etc/postgresql/postgresql.conf:ro
      - ./init-scripts:/docker-entrypoint-initdb.d/
    # Ограничение ресурсов и настройки производительности
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G
    sysctls:
      - kernel.shmmax=1073741824 # Увеличение shared memory для работы с большими буферами
    command: >
      postgres -c config_file=/etc/postgresql/postgresql.conf
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app_user -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data: # Именованный том, которым управляет Docker
    driver: local

2. Действия при проблеме "Database is uninitialized and superuser password is not specified": Эта ошибка возникает, если том уже содержит данные, но переменные окружения отличаются. Решение:

# 1. Останавливаем контейнер
docker-compose down

# 2. Делаем бэкап тома (на всякий случай)
docker run --rm -v app_postgres_data:/source -v $(pwd)/backup:/backup alpine tar czf /backup/postgres_backup.tar.gz -C /source .

# 3. Удаляем старый том (ВНИМАНИЕ: данные будут потеряны!)
docker volume rm app_postgres_data

# 4. Перезапускаем с чистыми данными
docker-compose up -d

3. Для продакшена: Я никогда не запускаю stateful-сервисы (БД) в Docker на продакшене напрямую. Вместо этого использую:

  • Управляемые облачные сервисы (AWS RDS, Yandex Managed PostgreSQL).
  • Операторы для Kubernetes (например, Zalando Postgres Operator), которые управляют репликацией, бэкапами и failover'ом.
  • Если и запускаю в K8s, то только с StatefulSet и PersistentVolume, привязанным к сетевому хранилищу.