Docker Compose с PostgreSQL: готовый docker-compose.yml

Категория: docker · Язык: YAML · Обновлено:

Готовый docker-compose.yml для PostgreSQL: данные хранятся в именованном томе, пароль берётся из файла .env, а healthcheck сообщает, когда база готова принимать подключения. Файл проверен на PostgreSQL 16.

docker-compose.yml

YAML
services:
  db:
    image: postgres:16
    container_name: app-postgres
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${POSTGRES_USER:-app}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Укажите POSTGRES_PASSWORD в файле .env}
      POSTGRES_DB: ${POSTGRES_DB:-app}
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./initdb:/docker-entrypoint-initdb.d:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  pgdata:

Файл .env рядом с docker-compose.yml

Bash
POSTGRES_USER=app
POSTGRES_PASSWORD=замените-на-длинный-случайный-пароль
POSTGRES_DB=app

Не добавляйте .env в git: внесите его в .gitignore.

Что делает каждая настройка

Настройка

Зачем нужна

image: postgres:16

Фиксирует мажорную версию. Тег latest может однажды обновить PostgreSQL до версии, несовместимой с вашими данными

POSTGRES_PASSWORD

Обязательная переменная: без неё контейнер не запустится

127.0.0.1:5432:5432

Порт доступен только с вашей машины, а не из сети

pgdata:/var/lib/postgresql/data

Именованный том: данные переживают пересоздание контейнера

./initdb:/docker-entrypoint-initdb.d

.sql и .sh файлы из этой папки выполняются при первом создании базы

healthcheck

Позволяет другим сервисам дождаться готовности базы

$${POSTGRES_USER}

Двойной $ передаёт переменную в контейнер, а не подставляет её на вашей машине

Запуск и работа с базой

Bash
docker compose up -d                          # запустить в фоне
docker compose ps                             # статус и health: healthy
docker compose logs -f db                     # логи
docker compose exec db psql -U app -d app     # консоль psql внутри контейнера
docker compose down                           # остановить, данные сохранятся

Подключение приложения

С хоста строка подключения выглядит так:

Bash
postgresql://app:ПАРОЛЬ@localhost:5432/app

Если приложение запущено в том же compose-файле, обращайтесь по имени сервиса, а не к localhost. Чтобы приложение стартовало после готовности базы, добавьте depends_on:

YAML
services:
  api:
    build: .
    environment:
      DATABASE_URL: postgresql://app:${POSTGRES_PASSWORD}@db:5432/app
    depends_on:
      db:
        condition: service_healthy

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

Bash
# сохранить дамп
docker compose exec -T db pg_dump -U app -d app > backup.sql

# восстановить в пустую базу
docker compose exec -T db psql -U app -d app < backup.sql

Частые проблемы

Скрипты из initdb не выполняются

Файлы из docker-entrypoint-initdb.d запускаются только при инициализации пустого каталога данных. Если том уже существует, они игнорируются. Для повторного запуска удалите том командой docker compose down -v, но помните, что данные будут потеряны.

Ошибка «password authentication failed»

Пароль из POSTGRES_PASSWORD применяется только при создании тома. Если вы изменили пароль в .env позже, он не обновится в существующей базе. Смените его командой ALTER USER app PASSWORD 'новый-пароль'; или пересоздайте том.

Порт 5432 уже занят

На машине уже запущен другой PostgreSQL. Измените внешний порт: "127.0.0.1:5433:5432", и подключайтесь к 5433.

Как обновиться на другую мажорную версию

Простая смена тега, например с 16 на 17, не сработает: формат данных различается между мажорными версиями. Сделайте pg_dump, запустите новую версию на пустом томе и восстановите дамп.