Flyway: версионные и repeatable миграции, запуск в Docker

↑ 5.1 Миграции: EF Core, Flyway, goose · ← Предыдущая · → Следующая

Желательно~6 мин чтенияУровень: middle

Зачем это на собесе

Flyway — самый простой и популярный инструмент SQL-миграций; часто встречается в Java/Kotlin и в контейнерных пайплайнах любого стека.

Принцип

Flyway применяет SQL-файлы в порядке версий и хранит историю в таблице flyway_schema_history (версия, описание, checksum, время, успех).

Типы миграций

ТипИмя файлаПоведение
VersionedV1__create_tables.sql, V2.1__add_index.sqlвыполняется один раз, в порядке версий
RepeatableR__views.sqlвыполняется заново при изменении checksum (после всех versioned); для представлений, функций, процедур
UndoU2__...откат (платная версия)
BaselineB5__...для существующей БД
CallbacksbeforeMigrate.sql, afterMigrate.sqlхуки

Формат имени: {префикс}{версия}__{описание}.sql (двойное подчёркивание).

-- V3__orders_status.sql
ALTER TABLE orders ADD COLUMN status text NOT NULL DEFAULT 'new';
CREATE INDEX idx_orders_status ON orders (status);
-- R__v_active_customers.sql  (пересоздаётся при изменении)
CREATE OR REPLACE VIEW v_active_customers AS
SELECT id, email FROM customers WHERE deleted_at IS NULL;

Запуск в Docker

docker run --rm --network app \
  -v "$PWD/db/migrations:/flyway/sql:ro" \
  flyway/flyway:11 \
  -url=jdbc:postgresql://postgres:5432/app \
  -user=app_migrator -password="$DB_PASSWORD" \
  -connectRetries=30 \
  migrate

В docker-compose:

services:
  postgres:
    image: postgres:17
    healthcheck: { test: ["CMD-SHELL", "pg_isready -U app"], interval: 5s, retries: 10 }
 
  migrate:
    image: flyway/flyway:11
    command: -url=jdbc:postgresql://postgres:5432/app -user=app -password=${DB_PASSWORD} -connectRetries=30 migrate
    volumes: [ "./db/migrations:/flyway/sql:ro" ]
    depends_on:
      postgres: { condition: service_healthy }
 
  api:
    build: ./src/Api
    depends_on:
      migrate: { condition: service_completed_successfully }

В Kubernetes: init-контейнер или Job (Helm pre-upgrade hook) до запуска новых подов; следите, чтобы выполнялась ровно одна миграция.

Основные команды

КомандаЧто делает
migrateприменить ожидающие миграции
infoстатус: применённые, ожидающие, ошибочные
validateпроверить checksum и наличие файлов
baselineпометить текущее состояние БД как версию (для существующих БД)
repairпочинить таблицу истории (после сбоя)
cleanудалить все объекты (запрещать на проде: cleanDisabled=true)

Конфигурация

[flyway]
url = "jdbc:postgresql://localhost:5432/app"
locations = ["filesystem:db/migrations"]
validateMigrationNaming = true
outOfOrder = false                # false по умолчанию
baselineOnMigrate = false
cleanDisabled = true
placeholders.schema = "public"    # ${schema} в SQL

Практики

  • версия по времени (V20260930_1200__...) уменьшает конфликты в ветках, либо последовательные номера при строгом порядке;
  • checksum: изменение применённого файла даёт ошибку валидации (защита);
  • outOfOrder — применить «опоздавшую» версию меньше текущей (осторожно);
  • отдельные пользователь migrator (DDL) и app (DML);
  • PostgreSQL: Flyway оборачивает миграцию в транзакцию, для CREATE INDEX CONCURRENTLY используйте -- flyway:executeInTransaction=false (конфиг в файле .conf рядом или executeInTransaction=false);
  • advisory lock: Flyway блокирует БД на время миграции, параллельные запуски безопасны;
  • тестирование миграций на чистой БД в CI (migrate → тесты) и на «грязной» копии;
  • для .NET есть обёртки (FluentMigrator, DbUp, Evolve), но CLI/Docker Flyway одинаково работает с любым стеком.

Flyway против Liquibase

FlywayLiquibase
ФорматSQL (и Java)XML/YAML/JSON/SQL changelog
Кривая обучениянизкаявыше
Откатплатная Undorollback-блоки, богаче
Независимость от СУБДменьшевыше (абстракция)
Контрольchecksumchangeset с id/author

Вопросы с ответами