Ручные миграции ломают релизы: где рассыпается настройка Flyway
Пока изменения схемы применяются руками, порядок и состав миграций живёт в голове релиз-инженера, а не в репозитории. На стендах накатывают разный набор файлов: где-то пропустили индекс, где-то применили чужую правку «на будущее» — и контуры тихо расходятся. Расхождение схемы вскрывается уже в бою, когда запрос из свежего кода падает на отсутствующей колонке.
Хуже, когда миграция применяется частично. Скрипт из нескольких изменений без транзакционной обёртки падает на середине: половина правок уже в базе, половина нет, а служебная таблица о таком состоянии ничего не знает. Откат кода схему не возвращает, повторный прогон упирается в «объект уже существует», и дальше всё восстанавливается вручную по логам и резервной копии.
Следом приходит блокировка выката: релиз готов, но ждёт, пока изменения внесёт дежурный администратор, окно развёртывания растягивается, а совместимость версии приложения и версии схемы держится на договорённостях. Цена такой схемы — не скорость одного релиза, а потеря управляемости: ни откатить, ни воспроизвести на чистом стенде.
Разбираем, как это закрывается при настройке Flyway: версионированные файлы из репозитория, контрольные суммы применённых изменений, отдельная учётная запись с ограниченными правами и прогон миграций в конвейере до старта новой версии приложения.
Что даёт управляемый порядок миграций схемы
Управляемый порядок миграций нужен не ради аккуратности в репозитории, а чтобы состояние схемы не зависело от ручных правок на стендах. Когда изменения живут отдельными пронумерованными файлами, база собирается воспроизводимо, а выкат перестаёт быть событием с неизвестной длительностью. Эффекты видны в измеримых величинах.
- Единый контур. Тестовая, предпродуктивная и продуктивная базы проходят одну последовательность миграций — расхождение всплывает на сборке, а не в момент релиза.
- Версионирование схемы. У миграции есть номер и контрольная сумма, в базе — журнал применённого. Инструмент вроде Flyway не накатит файл, изменённый после применения: правка задним числом не проходит незамеченной.
- Предсказуемый выкат. Инкрементальное изменение накатывается за секунды и не зависит от объёма накопленных данных — окно работ планируется заранее.
- Откат без восстановления из копии. Парные миграции и схема расширения-сжатия оставляют предыдущий релиз приложения рабочим: возврат — это операция, а не аварийное восстановление.
- Простой из-за миграций уходит. Блокирующие перестроения выносятся в отдельный шаг и идут без остановки записи — незапланированных пауз не остаётся.
Итог: одинаковый набор объектов на всех контурах, время выката в известном интервале и снятый класс отказов, который раньше давали ручные правки схемы.
Варианты настройки Flyway: сравнение режимов работы
Одно и то же описание миграций Flyway применяется по-разному: схему можно менять автоматически при старте приложения, отдельным шагом конвейера перед выкатом или вручную по команде инженера. Режим задаёт не синтаксис миграций, а момент применения, права в базе и то, насколько быстро команда замечает рассинхрон схемы и кода.
| Режим | Когда уместен | Ограничения |
|---|---|---|
| Автоматические миграции при старте | Локальные и тестовые стенды, одиночный инстанс, частые итерации | При нескольких репликах миграция стартует параллельно — нужна блокировка, иначе гонка; момент применения не контролируется |
| Отдельный шаг конвейера до выката | Продуктивные среды, несколько реплик, требуется предсказуемый порядок | Нужен отдельный доступ к базе и запас времени под долгие изменения схемы |
| Миграции по требованию | Регулируемые контуры, аудит изменений, критичные таблицы | Человеческий фактор: схема отстаёт от выката, ошибка приводит к простою |
Как выбирать режим под окружение
Описание миграций остаётся единым для всех контуров, различается только конфигурация окружений: на стендах — автонакат, в продуктиве — отдельный шаг под учётной записью с правами лишь на изменение схемы. Проверка соответствия версии схемы выносится на старт приложения: если миграции не применены, сервис не поднимается. Это убирает класс инцидентов, когда новый код работает со старой схемой, а разрушающие операции вроде очистки схемы в продуктиве отключаются на уровне настроек.
Этапы внедрения: от аудита схемы до передачи регламентов
Порядок работ строим так, чтобы каждый следующий шаг опирался на проверенный предыдущий. Ошибка в версионировании должна всплыть на копии, а не на рабочем контуре, — тогда это час отката вместо ночного восстановления из резервной копии.
- Аудит схемы. Собираем структуру всех контуров, сравниваем между собой и с историей изменений в системе контроля версий. Находим расхождения, правки, накатанные вручную, и объекты, которых нет ни в одном скрипте.
- Схема версионирования. Договариваемся о нумерации миграций, правилах именования и разделении одноразовых и повторяемых изменений. Фиксируем, кто и как добавляет следующую миграцию.
- Перенос истории. Приводим действующую базу к опорному состоянию: помечаем текущую структуру исходной точкой, чтобы прошлые изменения не накатывались заново.
- Проверка на копии. Прогоняем весь набор на полной копии рабочего контура — сначала с нуля, затем поверх текущего состояния. Считаем время и ловим конфликты.
- Точки контроля. Миграции идут отдельным шагом до старта приложения, с блокировкой выката при ошибке. Совпадение структуры с ожидаемой — условие прохождения дальше.
- Регламент выката. Отдельно описываем изменения, требующие остановки сервиса: подготовка, окно, порядок отката, ответственные.
- Передача. Отдаём конфигурации, схемы, инструкции и разбор типовых сбоев — команда ведёт миграции дальше сама.
Что остаётся в репозитории и у команды после внедрения
Внедрение считается завершённым не тогда, когда миграция прошла на тестовом контуре, а когда у команды остался комплект артефактов, по которому следующий релиз выпускает любой инженер, а не автор изменений. Ниже — минимальный набор, который мы передаём вместе с рабочим конвейером; каждый пункт проверяем на приёмке.
- Репозиторий миграций — плоские версионированные файлы с прямым и обратным сценарием, одна логическая правка на файл. Уже применённые файлы не редактируются: любое изменение схемы — новый файл, иначе контрольные суммы разойдутся между контурами.
- Политика ревью — обязательный просмотр скрипта вторым инженером, правила именования и порядок выкладки. Отдельно фиксируем запрет на ручные правки схемы: любые изменения проходят только через репозиторий.
- Настройки окружений — профили подключения для разработки, теста и промышленного контура, отдельные учётные записи с минимально нужными правами. Блокировки и таймауты заданы явно, чтобы долгая миграция не роняла сервис.
- Регламент отката — что делаем при неудачной миграции: точка восстановления, порядок компенсирующих скриптов, кто принимает решение об остановке. Целевое время возврата к рабочей версии фиксируем и проверяем на учениях.
- Документация схемы — актуальная модель данных, собираемая из самого хранилища после каждой выкладки, с описанием ключевых сущностей и связей. Живая схема вместо устаревшей презентации полугодовой давности.
- Инструкции для дежурной смены — где смотреть журнал миграций, какие ошибки означают остановку конвейера, как перевести выкладку в ручной режим. Плюс чек-лист приёмки релиза на 5–7 пунктов.
Комплект остаётся в вашем репозитории и вашей системе управления задачами — им можно пользоваться без нас.
Кейс: как схема на нескольких контурах перестала расходиться
Проект — сервис с тремя контурами: разработка, приёмка и продуктив. Миграции там катили руками: скрипты лежали в репозитории, инженер запускал их по очереди и следил за выводом. К моменту разбора схемы разошлись больше чем на 40 объектов — индексы, ограничения, значения по умолчанию и типы отдельных полей.
Цена расхождения проявилась на приёмке: проверки шли по структуре, которой в продуктиве не было, и часть дефектов доезжала до пользователей. Сам выкат занимал 40–60 минут ручной работы и требовал окна, а откат превращался в разбор журналов и правки по месту.
Схему перевели на Flyway: каждый скрипт получил номер версии и контрольную сумму, состояние фиксируется в служебной таблице. Миграции встроили в конвейер сборки — они применяются на каждом контуре автоматически, а попытка применить уже накатанный или изменённый скрипт останавливает сборку до разбора.
Что стало после внедрения
Выкат схемы сократился до 4–6 минут и перестал требовать отдельного окна. Расхождений между контурами — ноль: структура на приёмке и в продуктиве собирается из одной цепочки версий. Время восстановления при неудачной миграции — около 10 минут: обратный сценарий плюс возврат предыдущего артефакта. Ушёл целый класс отказов, когда на контур попадал не тот скрипт или один и тот же применялся дважды.
Что делать, если часть миграций уже применена вручную
Схема развивалась прямыми правками: колонку добавили через консоль, индекс построили вручную, часть объектов уже давно в продакшене. Таблицы истории применённых миграций при этом нет, и первый запуск Flyway видит пустой журнал — он пытается накатить всё с начала и падает на уже существующих таблицах. Порядок восстанавливают через базовую линию, а не через ручной пересбор журнала.
Базовая линия — это зафиксированное текущее состояние схемы, от которого начинается управляемая история. Выставляют baselineVersion на версию, с которой дальше идут миграции, и включают baselineOnMigrate: при первом запуске создаётся одна запись о базовой линии, а существующие объекты остаются нетронутыми. Всё, что делалось руками до неё, считается частью стартовой точки.
Одной базовой линии мало. Ручные правки накатывались без контроля, поэтому объекты могут расходиться с тем, что описано в миграциях — вплоть до типов колонок и ограничений. Прогоняют validate и смотрят расхождения, затем repair пересобирает контрольные суммы и убирает записи о неудавшихся попытках.
Дальше восстанавливают порядок: изменения идут только файлами миграций, а прямая правка продакшена запрещена или откатывается отдельной миграцией. Полезно сверить схему тестового и рабочего контуров — так базовая линия не закрепит незамеченное расхождение, которое всплывёт через несколько релизов.
Если схема разошлась слишком сильно, честнее поставить базовую линию на версию ниже текущей и описать остаток отдельным скриптом приведения. Решение принимают по объёму расхождений, а не по привычке: иногда дешевле один раз выровнять схему, чем тянуть журнал, который никогда не сходился.
Частые технические сомнения по миграциям баз данных
Сомнения инженеров вокруг миграций сводятся к четырём сценариям: одновременный старт нескольких экземпляров сервиса, падение изменения на середине, удаление ставшего ненужным столбца и порядок согласования правок схемы. Ниже — как каждый из них закрывается в настройке Flyway.
Сервис стартует в нескольких экземплярах — миграция применится дважды?
Нет: инструмент берёт блокировку на служебной таблице истории версий, поэтому изменение применяет только первый узел, остальные ждут освобождения и видят, что версия уже зафиксирована. Сложность в другом — при поочерёдном обновлении экземпляров старый код какое-то время работает с новой схемой, поэтому изменения делаем обратно совместимыми: сначала добавили, переключили чтение и запись, и лишь затем убрали лишнее.
Что останется в базе, если миграция упадёт на середине?
Зависит от того, поддерживает ли СУБД транзакционные изменения структуры. Где поддерживает — миграция откатывается целиком, и повторный запуск идёт с чистого состояния. Где нет — часть объектов уже создана, и настройка включает разбор такого состояния: сверяем фактическую схему, помечаем неудачную версию и повторяем с корректной точки. Крупные преобразования поэтому дробим на мелкие шаги.
Как удаляют столбцы и согласуют опасные изменения?
Удаление столбца или таблицы — двухфазная операция: сначала убираем обращения в коде и выкатываем релиз, следующим изменением удаляем объект. Так исчезает риск, что работающий экземпляр обратится к отсутствующему полю. Долгие операции, удерживающие блокировку таблицы, выносим в отдельное окно и ограничиваем время ожидания блокировки, чтобы не собрать очередь запросов. Сами правки схемы проходят общее согласование в том же порядке, что и код.
Обсудим задачу и вернёмся с оценкой и планом
Чтобы вернуться с оценкой и планом работ, а не с общими формулировками, достаточно короткого среза вашего контура миграций. Ниже — входные данные, по которым мы увидим объём и риски, не заходя на ваши стенды.
- СУБД и её версия на проде и на тестовых стендах, плюс дамп структуры схемы без самих данных.
- Текущие скрипты изменений: как именуются, где лежат, есть ли уже применённые вручную и не отмеченные в служебной таблице Flyway.
- Как изменения попадают в прод сейчас: кто и какой командой накатывает, в какое окно, что делают при ошибке на середине.
- Репозиторий и сборка: где хранятся миграции, чем собирается приложение, есть ли отдельный конвейер выката.
- Окружения и доступы: сколько стендов, чем различаются наборы данных, какие учётные записи можно выдать автоматике.
- Требования к откату и простою: допустимое время недоступности и что считается корректным откатом — обратный скрипт или восстановление из копии.
Дальше мы разбираем переданное, проверяем порядок применения и повторяемость скриптов, отмечаем шаги, которые придётся оставить ручными, и сверяем описание схемы с тем, что уже развёрнуто. На выходе вы получаете план этапов, состав автоматических проверок перед выкатом и порядок отката — с оценкой по срокам и составу работ.
Следующий шаг — короткий разговор по делу. Опишите задачу: достаточно пары абзацев о текущем состоянии и о том, что мешает, — вернёмся с оценкой и планом.







