Как подключить базу данных к приложению в Docker-контейнере?

Ответ

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

Основные шаги реализации:

  1. Создание контейнера с БД: Запускается отдельный контейнер для базы данных (например, PostgreSQL). Это позволяет изолировать БД от приложения и управлять ею независимо.

    docker run --name my-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres

    Для управления несколькими сервисами (приложение + БД) рекомендуется использовать docker-compose.

  2. Подключение приложения к БД: Приложение подключается к контейнеру БД, используя его имя как хост в рамках Docker-сети.

    • Использование docker-compose.yml (рекомендуемый подход):
      version: '3.8'
      services:
      app:
      build: .
      environment:
      DB_HOST: postgres # Имя сервиса БД в compose
      DB_NAME: mydatabase
      DB_USER: postgres
      DB_PASSWORD: mysecretpassword
      depends_on:
      - postgres # Гарантирует запуск БД перед приложением
      postgres:
      image: postgres:13
      environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mysecretpassword
      volumes:
      - pg_data:/var/lib/postgresql/data # Сохранение данных БД
      volumes:
      pg_data:

      Переменные окружения (environment) используются для передачи учетных данных и адреса БД в приложение, что является гибким и безопасным способом конфигурации.

  3. Важные аспекты и лучшие практики:

    • Volumes: Используйте Docker Volumes для персистентного хранения данных БД. Это гарантирует, что данные не будут потеряны при удалении или пересоздании контейнера БД.
      
      volumes:
    • pg_data:/var/lib/postgresql/data
    • Сети (Networks): Docker автоматически создает сеть для сервисов в docker-compose. Для ручного управления или более сложных сценариев можно создавать пользовательские сети для изоляции и маршрутизации трафика.
    • Healthchecks: Настройте проверки здоровья (healthcheck) для контейнера БД, чтобы приложение не пыталось подключиться к еще не готовой базе данных.
      healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

Пример подключения на Python с psycopg2:

import psycopg2
import os

try:
    conn = psycopg2.connect(
        host=os.getenv("DB_HOST", "localhost"),
        database=os.getenv("DB_NAME", "mydatabase"),
        user=os.getenv("DB_USER", "postgres"),
        password=os.getenv("DB_PASSWORD", "mysecretpassword")
    )
    print("Успешное подключение к БД!")
    conn.close()
except Exception as e:
    print(f"Ошибка подключения к БД: {e}")

Для продакшена также критически важны настройка репликации, регулярные бэкапы и мониторинг состояния базы данных.

Ответ 18+ 🔞

А, ну вот, классика жанра — запихнуть базу в докер и думать, что всё само заработает. Слушай, история стара как мир, но каждый раз кто-то наступает на те же грабли, блядь.

Так, по пунктам, но без занудства.

Первое — запускаем саму базу. Это ж святое. Берёшь образ постгреса и впердоливаешь его в контейнер. Главное — пароль не забудь, а то будет как в том анекдоте: «а доступ-то закрыт, ёпта!»

docker run --name my-postgres -e POSTGRES_PASSWORD=mysecretpassword -d postgres

Но это так, разминка для одиночек. Если у тебя приложение тоже в контейнере, то делать так — это как пытаться достучаться до соседа через стену голосом. Можно, но идиотизм. Поэтому все нормальные люди используют docker-compose. Это чтобы твоё приложение и база друг друга видели и не устраивали истерику «хост не найден, блядь».

Вот смотри, как это выглядит в деле (docker-compose.yml):

version: '3.8'
services:
  app:
    build: .
    environment:
      DB_HOST: postgres # Смотри-ка, просто имя сервиса! Никаких localhost:54321!
      DB_NAME: mydatabase
      DB_USER: postgres
      DB_PASSWORD: mysecretpassword
    depends_on:
      - postgres # Чтоб приложение не стартануло раньше базы, как та муда на самокате
  postgres:
    image: postgres:13
    environment:
      POSTGRES_DB: mydatabase
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: mysecretpassword
    volumes:
      - pg_data:/var/lib/postgresql/data # А это чтобы данные не испарились, как твоя зарплата в пятницу
volumes:
  pg_data:

Видишь? DB_HOST: postgres. Всё. Докер сам их в одну сеть запихнет, они там друг друга найдут по имени. Красота, а не жизнь.

А теперь про данные — это важно, ёпта! Если не повесить volume, то после перезапуска контейнера база станет чистой, как слеза младенца. И ты будешь сидеть с круглыми глазами: «А где мои таблицы, сука?». Поэтому volumes — это наше всё. Как записная книжка, которую не стирают.

Ещё можно healthcheck добавить, чтобы приложение терпеливо ждало, пока база не скажет «я готова, в рот меня чих-пых!», а не ломилось в закрытую дверь.

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U postgres"]
  interval: 5s
  timeout: 5s
  retries: 5

Ну и как это всё в коде выглядит (Python, например):

import psycopg2
import os

try:
    conn = psycopg2.connect(
        host=os.getenv("DB_HOST", "localhost"),
        database=os.getenv("DB_NAME", "mydatabase"),
        user=os.getenv("DB_USER", "postgres"),
        password=os.getenv("DB_PASSWORD", "mysecretpassword")
    )
    print("Успешное подключение к БД!")
    conn.close()
except Exception as e:
    print(f"Ошибка подключения к БД: {e}")

Смысл в чём? Берём настройки из переменных окружения. В компоузе мы их задали — они тут и всплывут. Никаких паролей в коде, никаких костылей. Всё чисто, как у хорошего человека.

А дальше — да, в продакшене надо ещё репликацию, бэкапы и мониторинг городить. Но это уже совсем другая история, с приключениями и нервными срывами. Для начала просто добейся, чтобы одно приложение в контейнере поговорило с другой базой в контейнере. Если получится — считай, полдела сделано. А нет — ну, бывает, первый блин всегда комом, иногда даже еб*ным.