Настройка Liquibase с PostgreSQL в Docker: Пошаговое руководство | AdminWiki

Liquibase, PostgreSQL и Docker: Полное руководство по настройке и миграциям

18 декабря 2025 10 мин. чтения #devops #docker #liquibase #postgresql #миграции баз данных #настройка

Представь, что твоя команда разрабатывает приложение, и с каждой новой фичей нужно менять структуру базы данных. Кто-то забывает применить миграцию, кто-то запускает её в неправильном порядке, и в итоге — продакшен падает. Знакомая ситуация? Именно для решения таких проблем существует Liquibase — инструмент для контроля версий и управления миграциями БД. А если добавить сюда PostgreSQL в Docker-контейнере, получится идеально воспроизводимая и изолированная среда для разработки. Давай разберем, как это всё настроить с нуля.

Что такое Liquibase и зачем он нужен с PostgreSQL в Docker?

Liquibase — это система контроля версий для твоей базы данных. Вместо ручного выполнения SQL-скриптов ты описываешь изменения (создание таблиц, добавление колонок, индексы) в декларативных файлах (XML, YAML, JSON или SQL). Liquibase отслеживает, какие изменения уже применены к БД, в специальной таблице databasechangelog, и применяет только новые. Это даёт:

  • Воспроизводимость: Любой разработчик может развернуть идентичную схему БД.
  • Безопасность: Исключаются человеческие ошибки при ручном запуске скриптов.
  • Историю изменений: Полный аудит того, что и когда было изменено в схеме данных.
  • Интеграцию с CI/CD: Миграции можно автоматически применять при деплое.

Использование PostgreSQL в Docker делает эту связку ещё мощнее: ты получаешь легковесный, изолированный и мгновенно запускаемый экземпляр базы данных, идентичный продакшену. Настройка связки liquibase postgresql docker — ключевой навык для современного DevOps-инженера.

Предварительная настройка окружения

Перед началом убедись, что у тебя установлены:

  • Docker и Docker Compose (желательно последних версий).
  • Java Runtime Environment (JRE) версии 11 или выше, так как Liquibase — Java-приложение.
  • Текстовый редактор или IDE (VS Code, IntelliJ IDEA).

Шаг 1: Запуск PostgreSQL в Docker

Создай директорию для проекта, например, liquibase-demo. В ней создай файл docker-compose.yml для запуска контейнера с PostgreSQL.

docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: liquibase_postgres
    environment:
      POSTGRES_DB: myappdb
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mysecretpassword
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d myappdb"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
Важно: Мы используем образ postgres:15-alpine — он легковесный. Параметры POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD задают начальную базу, пользователя и пароль. Healthcheck гарантирует, что контейнер будет считаться готовым только когда БД действительно примет подключения.

Запусти контейнер командой:

bash
docker-compose up -d

Проверь, что контейнер работает: docker ps. Ты также можешь подключиться к БД через psql: docker exec -it liquibase_postgres psql -U myuser -d myappdb.

Шаг 2: Установка и базовая настройка Liquibase

Есть несколько способов использовать Liquibase:

  1. CLI (JAR-файл): Скачай jar-архив с официального сайта.
  2. Docker-образ Liquibase: Удобно для CI/CD. Мы будем использовать этот способ, чтобы не устанавливать Java локально.
  3. Плагин для Maven/Gradle: Для Java-проектов.

Для нашего руководства создадим простую структуру проекта и используем Docker-образ Liquibase. Создай следующие директории и файлы:

bash
mkdir -p liquibase/changelog
cd liquibase

Теперь создай главный конфигурационный файл Liquibase — liquibase.properties. В нём укажи параметры подключения к нашему PostgreSQL в Docker.

liquibase/liquibase.properties
# Настройки подключения к PostgreSQL
url: jdbc:postgresql://localhost:5432/myappdb
driver: org.postgresql.Driver
username: myuser
password: mysecretpassword

# Логирование и управление
changeLogFile: changelog/db.changelog-master.yaml
liquibase.hub.mode: off
logLevel: info
Внимание! В реальных проектах никогда не храни пароли от БД прямо в properties-файле, особенно в репозитории. Используй переменные окружения, secrets-менеджеры (HashiCorp Vault, AWS Secrets Manager) или передавай параметры через командную строку.

Шаг 3: Создание мастер-файла изменений (Changelog)

Liquibase работает с мастер-файлом (чаще всего в формате YAML или XML), который ссылается на все остальные файлы изменений. Создай файл changelog/db.changelog-master.yaml.

liquibase/changelog/db.changelog-master.yaml
databaseChangeLog:
  - includeAll:
      path: changelog/versions/
      relativeToChangelogFile: true

Эта конфигурация говорит Liquibase включить все файлы изменений из директории changelog/versions/. Теперь создай саму директорию: mkdir -p changelog/versions.

Шаг 4: Написание первой миграции

Давай создадим нашу первую таблицу — например, для пользователей. Создай файл changelog/versions/001-create-user-table.yaml.

liquibase/changelog/versions/001-create-user-table.yaml
databaseChangeLog:
  - changeSet:
      id: 001-create-user-table
      author: your_name
      changes:
        - createTable:
            tableName: app_user
            columns:
              - column:
                  name: id
                  type: BIGINT
                  constraints:
                    primaryKey: true
                    nullable: false
                  autoIncrement: true
              - column:
                  name: username
                  type: VARCHAR(50)
                  constraints:
                    unique: true
                    nullable: false
              - column:
                  name: email
                  type: VARCHAR(100)
                  constraints:
                    nullable: false
              - column:
                  name: created_at
                  type: TIMESTAMP
                  defaultValueComputed: CURRENT_TIMESTAMP

Каждый changeSet — это атомарное изменение. У него должен быть уникальный id и author. Liquibase по этим полям отслеживает, было ли изменение уже применено.

Шаг 5: Запуск миграций с помощью Docker-образа Liquibase

Теперь самое интересное — применение миграций. Мы не будем устанавливать Liquibase локально, а используем официальный Docker-образ. Из корня проекта (где лежит docker-compose.yml) выполни команду:

bash
docker run --rm \
  --network="host" \
  -v "$(pwd)/liquibase:/liquibase/changelog" \
  -v "$(pwd)/liquibase/liquibase.properties:/liquibase/liquibase.properties" \
  liquibase/liquibase:latest \
  --defaultsFile=/liquibase/liquibase.properties \
  update

Разберем команду:

  • --network="host" — позволяет контейнеру Liquibase видеть PostgreSQL, запущенный на localhost.
  • -v "$(pwd)/liquibase:/liquibase/changelog" — монтирует директорию с changelog-файлами внутрь контейнера.
  • -v ".../liquibase.properties" — монтирует файл с настройками.
  • liquibase/liquibase:latest — используем последний официальный образ.
  • update — команда Liquibase для применения всех непримененных изменений.
Если ты видишь в выводе "Liquibase command 'update' was executed successfully." — поздравляю! Твоя первая миграция применена. Проверь, создалась ли таблица: docker exec -it liquibase_postgres psql -U myuser -d myappdb -c "\\dt app_user". Также проверь таблицу databasechangelog: docker exec -it liquibase_postgres psql -U myuser -d myappdb -c "SELECT * FROM databasechangelog;".

Продвинутая настройка и лучшие практики

Использование переменных окружения для безопасности

Давай улучшим наш liquibase.properties, убрав из него чувствительные данные. Перепишем его так:

liquibase/liquibase.properties (без пароля)
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
driver: org.postgresql.Driver
username: ${DB_USER}
password: ${DB_PASSWORD}
changeLogFile: changelog/db.changelog-master.yaml

Теперь при запуске Docker-контейнера Liquibase передавай переменные окружения:

bash
docker run --rm \
  --network="host" \
  -e DB_HOST=localhost \
  -e DB_PORT=5432 \
  -e DB_NAME=myappdb \
  -e DB_USER=myuser \
  -e DB_PASSWORD=mysecretpassword \
  -v "$(pwd)/liquibase:/liquibase/changelog" \
  -v "$(pwd)/liquibase/liquibase.properties:/liquibase/liquibase.properties" \
  liquibase/liquibase:latest \
  --defaultsFile=/liquibase/liquibase.properties \
  update

Интеграция в Docker Compose

Чтобы автоматически применять миграции при запуске инфраструктуры, можно добавить сервис Liquibase в тот же docker-compose.yml. Это отличная практика для локальной разработки.

docker-compose.yml (расширенный)
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: liquibase_postgres
    environment:
      POSTGRES_DB: myappdb
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mysecretpassword
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U myuser -d myappdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  liquibase-migrate:
    image: liquibase/liquibase:latest
    container_name: liquibase_runner
    depends_on:
      postgres:
        condition: service_healthy # Ждем, пока БД станет здоровой
    volumes:
      - ./liquibase:/liquibase/changelog
      - ./liquibase/liquibase.properties:/liquibase/liquibase.properties
    environment:
      DB_HOST: postgres # Используем имя сервиса как хост
      DB_PORT: 5432
      DB_NAME: myappdb
      DB_USER: myuser
      DB_PASSWORD: mysecretpassword
    command: --defaultsFile=/liquibase/liquibase.properties update

volumes:
  postgres_data:

Теперь после команды docker-compose up -d сначала запустится и "прогреется" PostgreSQL, а затем автоматически выполнятся все миграции Liquibase. Для повторного запуска миграций (если changelog не менялся) используй: docker-compose run --rm liquibase-migrate.

Сравнение способов запуска Liquibase

Способ Плюсы Минусы Использование
Docker-образ Не требует установки Java, идеален для CI/CD, изоляция. Нужно монтировать volumes, может быть медленнее при частых запусках. Продакшен, CI/CD пайплайны, локальная разработка (как в нашем гайде).
Локальный CLI (JAR) Быстрый запуск, полный контроль. Требует установки Java, меньше переносимости. Локальная разработка, если Docker не используется.
Плагин Maven/Gradle Интеграция в процесс сборки Java-проекта. Привязан к экосистеме Java. Java/Spring Boot проекты.

Часто задаваемые вопросы (FAQ)

Как откатить (rollback) изменения, если что-то пошло не так?

Liquibase поддерживает откаты. Для этого в changeSet можно определить тег rollback. Например, для нашей таблицы можно добавить rollback: "DROP TABLE app_user;". Чтобы откатить изменения до определённого тега, используй команду: docker run ... liquibase/liquibase rollback --tag="v1.0". Всегда тестируй откаты на стейджинге!

Можно ли использовать "чистый" SQL вместо YAML/XML в Liquibase?

Да, можно. Liquibase отлично работает с SQL-файлами. Просто укажи в мастер-файле include на конкретный SQL-файл. Это полезно для сложных миграций, которые проще написать на SQL. Однако, используя декларативные форматы (YAML/XML), ты получаешь лучшую переносимость между разными СУБД и встроенную поддержку откатов.

Как организовать работу с Liquibase в команде?

  • Храни все changelog-файлы в системе контроля версий (Git).
  • Используй понятную нумерацию или дату в именах файлов (например, 20240515-01-add-user-table.yaml).
  • Никогда не изменяй changeSet после того, как он был применён к какой-либо БД (особенно продакшену). Если нужно исправить ошибку, создай новый changeSet.
  • В CI/CD пайплайне добавляй шаг проверки (validate) и обновления (update) перед деплоем приложения.

Почему Liquibase не подключается к PostgreSQL в Docker с ошибкой "Connection refused"?

Самая частая причина — неправильные настройки сети. Убедись, что:

  1. Контейнер с PostgreSQL запущен (docker ps).
  2. Ты используешь правильный хост. При запуске из другого контейнера (как в docker-compose) хост — это имя сервиса (postgres). При запуске из хостовой системы с --network="host" хост — localhost.
  3. Порт 5432 проброшен на хост (ports: - "5432:5432").

Заключение

Настройка связки Liquibase, PostgreSQL и Docker — это не просто техническая задача, а инвестиция в стабильность и предсказуемость твоего проекта. Ты создал изолированную среду для БД, настроил систему контроля версий для схемы данных и автоматизировал применение миграций. Теперь ты можешь уверенно вносить изменения в базу, зная, что каждый член команды и каждый стенд будут иметь идентичную структуру. Дальнейшие шаги — это интеграция в CI/CD, работа с несколькими окружениями (dev, staging, prod) и, возможно, освоение таких команд Liquibase, как diff (для сравнения схем) и snapshot (для создания снимка состояния БД). Удачи в освоении инструментов!

Поделиться:
Сохранить гайд? В закладки браузера