← Назад к вопросам

Как разместить БД в контейнере не нарушив ее целостность?

2.0 Middle🔥 171 комментариев
#DevOps и инфраструктура#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Размещение БД в Docker контейнере: сохранение целостности данных

Это важный вопрос для backend-разработчика, так как неправильное использование Docker может привести к потере данных. При остановке или удалении контейнера все данные, которые хранились внутри образа, теряются.

Проблема: данные в контейнере удаляются

# Запускаем PostgreSQL в контейнере
docker run -e POSTGRES_PASSWORD=secret postgres:15

# Добавляем данные в БД
# ...

# Останавливаем контейнер
docker stop <container-id>

# Удаляем контейнер
docker rm <container-id>

# Все данные ПОТЕРЯНЫ!

Вся информация, которая была в БД, стерта. Это происходит потому что контейнер хранит данные в своей файловой системе, которая удаляется вместе с контейнером.

Решение 1: Docker Volumes (рекомендуется)

Volumeы — это способ персистентного хранения данных, отделенного от контейнера.

Использование с Docker CLI:

# Создаем volume
docker volume create pg-data

# Запускаем контейнер с volume
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=secret \
  -v pg-data:/var/lib/postgresql/data \
  postgres:15

# Теперь данные сохраняются в volume
# Даже если удалить контейнер, volume остается
docker stop postgres
docker rm postgres

# Запускаем новый контейнер с тем же volume
docker run -d \
  --name postgres-new \
  -e POSTGRES_PASSWORD=secret \
  -v pg-data:/var/lib/postgresql/data \
  postgres:15

# ВСЕ ДАННЫЕ ВОССТАНОВЛЕНЫ!

Docker Compose (предпочтительный способ):

version: '3.8'

services:
  db:
    image: postgres:15
    container_name: myapp-db
    environment:
      POSTGRES_USER: app_user
      POSTGRES_PASSWORD: app_password
      POSTGRES_DB: app_db
    volumes:
      # Сохраняем данные БД
      - pg-data:/var/lib/postgresql/data
      # Опционально: инициализационные SQL скрипты
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app_user"]
      interval: 10s
      timeout: 5s
      retries: 5

  app:
    build: .
    depends_on:
      db:
        condition: service_healthy
    environment:
      DATABASE_URL: postgresql://app_user:app_password@db:5432/app_db
    ports:
      - "3000:3000"

volumes:
  pg-data:
    driver: local

Использование:

# Запустить
docker-compose up -d

# Остановить (данные в volume сохраняются)
docker-compose down

# Запустить заново (данные восстановлены)
docker-compose up -d

# Только удалить контейнеры, не трогая volume
docker-compose down

# Удалить всё, включая volume (будут ПОТЕРЯНЫ ДАННЫЕ!)
docker-compose down -v

Решение 2: Bind Mounts (для development)

Монтирование локальной директории хоста в контейнер.

# Создаем директорию на хосте
mkdir -p ./postgres-data

# Монтируем её в контейнер
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=secret \
  -v $(pwd)/postgres-data:/var/lib/postgresql/data \
  postgres:15

# Данные хранятся в ./postgres-data на хосте
# Видны через вашу файловую систему
ls -la ./postgres-data/

Docker Compose с bind mount:

version: '3.8'

services:
  db:
    image: postgres:15
    volumes:
      - ./postgres-data:/var/lib/postgresql/data

Преимущества:

  • Видите файлы на хосте
  • Легко резервировать
  • Удобно для development

Недостатки:

  • Медленнее чем volumes
  • Проблемы с правами доступа (ownership)
  • Не рекомендуется для production

Решение 3: Управление правами доступа

Важный аспект при использовании volumes — права доступа файлов.

version: '3.8'

services:
  db:
    image: postgres:15
    volumes:
      - pg-data:/var/lib/postgresql/data
    # Указываем пользователя контейнера
    user: "postgres:postgres"
    # Или явно
    user: "999:999"

volumes:
  pg-data:
    driver: local
    driver_opts:
      # Опции для локального драйвера
      type: none
      o: bind
      device: ./postgres-data

Практический пример: Node.js app + PostgreSQL

# docker-compose.yml
version: '3.8'

services:
  # PostgreSQL с persistent volume
  postgres:
    image: postgres:15-alpine
    container_name: myapp-postgres
    environment:
      POSTGRES_USER: ${DB_USER:-app}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
      POSTGRES_DB: ${DB_NAME:-myapp}
    volumes:
      # Основное хранилище данных
      - postgres-data:/var/lib/postgresql/data
      # Скрипты инициализации
      - ./migrations/init.sql:/docker-entrypoint-initdb.d/01-init.sql
      - ./migrations/seed.sql:/docker-entrypoint-initdb.d/02-seed.sql
    ports:
      - "${DB_PORT:-5432}:5432"
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USER:-app} -d ${DB_NAME:-myapp}
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - myapp-network

  # Redis для кэша
  redis:
    image: redis:7-alpine
    container_name: myapp-redis
    volumes:
      - redis-data:/data
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - myapp-network

  # Node.js приложение
  app:
    build: .
    container_name: myapp
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      NODE_ENV: development
      DATABASE_URL: postgresql://${DB_USER:-app}:${DB_PASSWORD:-secret}@postgres:5432/${DB_NAME:-myapp}
      REDIS_URL: redis://redis:6379
      PORT: 3000
    volumes:
      # Hot reload для development
      - ./src:/app/src
      - /app/node_modules
    ports:
      - "3000:3000"
    networks:
      - myapp-network
    restart: unless-stopped

volumes:
  postgres-data:
    driver: local
  redis-data:
    driver: local

networks:
  myapp-network:
    driver: bridge

Резервирование и восстановление

Backup PostgreSQL:

# Из контейнера
docker exec myapp-postgres pg_dump -U app -d myapp > backup.sql

# Или через volume
docker run --rm -v pg-data:/data -v $(pwd):/backup \
  postgres:15 \
  pg_dump -U app -d myapp -f /backup/dump.sql

Restore:

# Из файла в контейнер
docker exec -i myapp-postgres psql -U app -d myapp < backup.sql

Backup volume:

# Создать archive volume
docker run --rm -v pg-data:/data -v $(pwd):/backup \
  alpine tar czf /backup/pg-data-backup.tar.gz -C /data .

# Restore volume из archive
docker run --rm -v pg-data:/data -v $(pwd):/backup \
  alpine tar xzf /backup/pg-data-backup.tar.gz -C /data

Проверка целостности данных

# Проверить данные в volume
docker volume inspect pg-data

# Просмотреть актуальное состояние
docker ps -a
docker volume ls

# Подключиться к БД
docker exec -it myapp-postgres psql -U app -d myapp

# Выполнить SQL
# SELECT COUNT(*) FROM users;
# \dt  (list tables)
# \q   (quit)

Best Practices

  1. Всегда используй volumes для БД — никогда не храни БД данные без volume

  2. Используй Docker Compose для управления несколькими контейнерами

  3. Именуй volumes явно:

volumes:
  postgres-data:
    driver: local
  1. Определи healthchecks:
healthcheck:
  test: ["CMD", "pg_isready", "-U", "app"]
  interval: 10s
  timeout: 5s
  retries: 5
  1. Регулярно создавай backups:
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
docker exec myapp-postgres pg_dump -U app -d myapp > backups/dump_$DATE.sql
  1. Для production используй managed databases (AWS RDS, Google Cloud SQL) вместо Docker

  2. Никогда не используй docker rm -v без backup

Заключение

Для сохранения целостности данных БД в Docker:

  1. Используй volumes — основной способ
  2. Docker Compose для управления
  3. Healthchecks для надежности
  4. Regular backups для безопасности
  5. Production: managed database services вместо Docker

Это критично для любого backend приложения, так как потеря данных может быть катастрофической.

Как разместить БД в контейнере не нарушив ее целостность? | PrepBro