Flyway для автоматизации миграций БД: настройка и внедрение в CI/CD

Ручные миграции схемы рано или поздно расходятся между контурами, и релиз начинает зависеть от памяти разработчика. Мы настраиваем автоматизацию миграций баз данных под ключ: единый порядок изменений, проверки на каждом шаге, предсказуемые развёртывания. Время на подготовку релиза сокращается в разы, а расхождения схем уходят из списка причин отката.
Часто задаваемые вопросы

Ручные миграции ломают релизы: где рассыпается настройка Flyway

Пока изменения схемы применяются руками, порядок и состав миграций живёт в голове релиз-инженера, а не в репозитории. На стендах накатывают разный набор файлов: где-то пропустили индекс, где-то применили чужую правку «на будущее» — и контуры тихо расходятся. Расхождение схемы вскрывается уже в бою, когда запрос из свежего кода падает на отсутствующей колонке.

Хуже, когда миграция применяется частично. Скрипт из нескольких изменений без транзакционной обёртки падает на середине: половина правок уже в базе, половина нет, а служебная таблица о таком состоянии ничего не знает. Откат кода схему не возвращает, повторный прогон упирается в «объект уже существует», и дальше всё восстанавливается вручную по логам и резервной копии.

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

Разбираем, как это закрывается при настройке Flyway: версионированные файлы из репозитория, контрольные суммы применённых изменений, отдельная учётная запись с ограниченными правами и прогон миграций в конвейере до старта новой версии приложения.

Что даёт управляемый порядок миграций схемы

Управляемый порядок миграций нужен не ради аккуратности в репозитории, а чтобы состояние схемы не зависело от ручных правок на стендах. Когда изменения живут отдельными пронумерованными файлами, база собирается воспроизводимо, а выкат перестаёт быть событием с неизвестной длительностью. Эффекты видны в измеримых величинах.

  • Единый контур. Тестовая, предпродуктивная и продуктивная базы проходят одну последовательность миграций — расхождение всплывает на сборке, а не в момент релиза.
  • Версионирование схемы. У миграции есть номер и контрольная сумма, в базе — журнал применённого. Инструмент вроде Flyway не накатит файл, изменённый после применения: правка задним числом не проходит незамеченной.
  • Предсказуемый выкат. Инкрементальное изменение накатывается за секунды и не зависит от объёма накопленных данных — окно работ планируется заранее.
  • Откат без восстановления из копии. Парные миграции и схема расширения-сжатия оставляют предыдущий релиз приложения рабочим: возврат — это операция, а не аварийное восстановление.
  • Простой из-за миграций уходит. Блокирующие перестроения выносятся в отдельный шаг и идут без остановки записи — незапланированных пауз не остаётся.

Итог: одинаковый набор объектов на всех контурах, время выката в известном интервале и снятый класс отказов, который раньше давали ручные правки схемы.

Варианты настройки Flyway: сравнение режимов работы

Одно и то же описание миграций Flyway применяется по-разному: схему можно менять автоматически при старте приложения, отдельным шагом конвейера перед выкатом или вручную по команде инженера. Режим задаёт не синтаксис миграций, а момент применения, права в базе и то, насколько быстро команда замечает рассинхрон схемы и кода.

Режим Когда уместен Ограничения
Автоматические миграции при старте Локальные и тестовые стенды, одиночный инстанс, частые итерации При нескольких репликах миграция стартует параллельно — нужна блокировка, иначе гонка; момент применения не контролируется
Отдельный шаг конвейера до выката Продуктивные среды, несколько реплик, требуется предсказуемый порядок Нужен отдельный доступ к базе и запас времени под долгие изменения схемы
Миграции по требованию Регулируемые контуры, аудит изменений, критичные таблицы Человеческий фактор: схема отстаёт от выката, ошибка приводит к простою

Как выбирать режим под окружение

Описание миграций остаётся единым для всех контуров, различается только конфигурация окружений: на стендах — автонакат, в продуктиве — отдельный шаг под учётной записью с правами лишь на изменение схемы. Проверка соответствия версии схемы выносится на старт приложения: если миграции не применены, сервис не поднимается. Это убирает класс инцидентов, когда новый код работает со старой схемой, а разрушающие операции вроде очистки схемы в продуктиве отключаются на уровне настроек.

Этапы внедрения: от аудита схемы до передачи регламентов

Порядок работ строим так, чтобы каждый следующий шаг опирался на проверенный предыдущий. Ошибка в версионировании должна всплыть на копии, а не на рабочем контуре, — тогда это час отката вместо ночного восстановления из резервной копии.

  1. Аудит схемы. Собираем структуру всех контуров, сравниваем между собой и с историей изменений в системе контроля версий. Находим расхождения, правки, накатанные вручную, и объекты, которых нет ни в одном скрипте.
  2. Схема версионирования. Договариваемся о нумерации миграций, правилах именования и разделении одноразовых и повторяемых изменений. Фиксируем, кто и как добавляет следующую миграцию.
  3. Перенос истории. Приводим действующую базу к опорному состоянию: помечаем текущую структуру исходной точкой, чтобы прошлые изменения не накатывались заново.
  4. Проверка на копии. Прогоняем весь набор на полной копии рабочего контура — сначала с нуля, затем поверх текущего состояния. Считаем время и ловим конфликты.
  5. Точки контроля. Миграции идут отдельным шагом до старта приложения, с блокировкой выката при ошибке. Совпадение структуры с ожидаемой — условие прохождения дальше.
  6. Регламент выката. Отдельно описываем изменения, требующие остановки сервиса: подготовка, окно, порядок отката, ответственные.
  7. Передача. Отдаём конфигурации, схемы, инструкции и разбор типовых сбоев — команда ведёт миграции дальше сама.

Что остаётся в репозитории и у команды после внедрения

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

  • Репозиторий миграций — плоские версионированные файлы с прямым и обратным сценарием, одна логическая правка на файл. Уже применённые файлы не редактируются: любое изменение схемы — новый файл, иначе контрольные суммы разойдутся между контурами.
  • Политика ревью — обязательный просмотр скрипта вторым инженером, правила именования и порядок выкладки. Отдельно фиксируем запрет на ручные правки схемы: любые изменения проходят только через репозиторий.
  • Настройки окружений — профили подключения для разработки, теста и промышленного контура, отдельные учётные записи с минимально нужными правами. Блокировки и таймауты заданы явно, чтобы долгая миграция не роняла сервис.
  • Регламент отката — что делаем при неудачной миграции: точка восстановления, порядок компенсирующих скриптов, кто принимает решение об остановке. Целевое время возврата к рабочей версии фиксируем и проверяем на учениях.
  • Документация схемы — актуальная модель данных, собираемая из самого хранилища после каждой выкладки, с описанием ключевых сущностей и связей. Живая схема вместо устаревшей презентации полугодовой давности.
  • Инструкции для дежурной смены — где смотреть журнал миграций, какие ошибки означают остановку конвейера, как перевести выкладку в ручной режим. Плюс чек-лист приёмки релиза на 5–7 пунктов.

Комплект остаётся в вашем репозитории и вашей системе управления задачами — им можно пользоваться без нас.

Кейс: как схема на нескольких контурах перестала расходиться

Проект — сервис с тремя контурами: разработка, приёмка и продуктив. Миграции там катили руками: скрипты лежали в репозитории, инженер запускал их по очереди и следил за выводом. К моменту разбора схемы разошлись больше чем на 40 объектов — индексы, ограничения, значения по умолчанию и типы отдельных полей.

Цена расхождения проявилась на приёмке: проверки шли по структуре, которой в продуктиве не было, и часть дефектов доезжала до пользователей. Сам выкат занимал 40–60 минут ручной работы и требовал окна, а откат превращался в разбор журналов и правки по месту.

Схему перевели на Flyway: каждый скрипт получил номер версии и контрольную сумму, состояние фиксируется в служебной таблице. Миграции встроили в конвейер сборки — они применяются на каждом контуре автоматически, а попытка применить уже накатанный или изменённый скрипт останавливает сборку до разбора.

Что стало после внедрения

Выкат схемы сократился до 4–6 минут и перестал требовать отдельного окна. Расхождений между контурами — ноль: структура на приёмке и в продуктиве собирается из одной цепочки версий. Время восстановления при неудачной миграции — около 10 минут: обратный сценарий плюс возврат предыдущего артефакта. Ушёл целый класс отказов, когда на контур попадал не тот скрипт или один и тот же применялся дважды.

Что делать, если часть миграций уже применена вручную

Схема развивалась прямыми правками: колонку добавили через консоль, индекс построили вручную, часть объектов уже давно в продакшене. Таблицы истории применённых миграций при этом нет, и первый запуск Flyway видит пустой журнал — он пытается накатить всё с начала и падает на уже существующих таблицах. Порядок восстанавливают через базовую линию, а не через ручной пересбор журнала.

Базовая линия — это зафиксированное текущее состояние схемы, от которого начинается управляемая история. Выставляют baselineVersion на версию, с которой дальше идут миграции, и включают baselineOnMigrate: при первом запуске создаётся одна запись о базовой линии, а существующие объекты остаются нетронутыми. Всё, что делалось руками до неё, считается частью стартовой точки.

Одной базовой линии мало. Ручные правки накатывались без контроля, поэтому объекты могут расходиться с тем, что описано в миграциях — вплоть до типов колонок и ограничений. Прогоняют validate и смотрят расхождения, затем repair пересобирает контрольные суммы и убирает записи о неудавшихся попытках.

Дальше восстанавливают порядок: изменения идут только файлами миграций, а прямая правка продакшена запрещена или откатывается отдельной миграцией. Полезно сверить схему тестового и рабочего контуров — так базовая линия не закрепит незамеченное расхождение, которое всплывёт через несколько релизов.

Если схема разошлась слишком сильно, честнее поставить базовую линию на версию ниже текущей и описать остаток отдельным скриптом приведения. Решение принимают по объёму расхождений, а не по привычке: иногда дешевле один раз выровнять схему, чем тянуть журнал, который никогда не сходился.

Частые технические сомнения по миграциям баз данных

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

Сервис стартует в нескольких экземплярах — миграция применится дважды?

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

Что останется в базе, если миграция упадёт на середине?

Зависит от того, поддерживает ли СУБД транзакционные изменения структуры. Где поддерживает — миграция откатывается целиком, и повторный запуск идёт с чистого состояния. Где нет — часть объектов уже создана, и настройка включает разбор такого состояния: сверяем фактическую схему, помечаем неудачную версию и повторяем с корректной точки. Крупные преобразования поэтому дробим на мелкие шаги.

Как удаляют столбцы и согласуют опасные изменения?

Удаление столбца или таблицы — двухфазная операция: сначала убираем обращения в коде и выкатываем релиз, следующим изменением удаляем объект. Так исчезает риск, что работающий экземпляр обратится к отсутствующему полю. Долгие операции, удерживающие блокировку таблицы, выносим в отдельное окно и ограничиваем время ожидания блокировки, чтобы не собрать очередь запросов. Сами правки схемы проходят общее согласование в том же порядке, что и код.

Обсудим задачу и вернёмся с оценкой и планом

Чтобы вернуться с оценкой и планом работ, а не с общими формулировками, достаточно короткого среза вашего контура миграций. Ниже — входные данные, по которым мы увидим объём и риски, не заходя на ваши стенды.

  • СУБД и её версия на проде и на тестовых стендах, плюс дамп структуры схемы без самих данных.
  • Текущие скрипты изменений: как именуются, где лежат, есть ли уже применённые вручную и не отмеченные в служебной таблице Flyway.
  • Как изменения попадают в прод сейчас: кто и какой командой накатывает, в какое окно, что делают при ошибке на середине.
  • Репозиторий и сборка: где хранятся миграции, чем собирается приложение, есть ли отдельный конвейер выката.
  • Окружения и доступы: сколько стендов, чем различаются наборы данных, какие учётные записи можно выдать автоматике.
  • Требования к откату и простою: допустимое время недоступности и что считается корректным откатом — обратный скрипт или восстановление из копии.

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

Следующий шаг — короткий разговор по делу. Опишите задачу: достаточно пары абзацев о текущем состоянии и о том, что мешает, — вернёмся с оценкой и планом.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139