Как правильно делать миграции в Kubernetes, чтобы новые поды стартовали после миграций, а старые не сломались
Что проверяют
Понимаете ли вы, что проблема не в Kubernetes, а в совместимости схемы: во время rolling update старая и новая версии приложения работают с одной базой одновременно. Следом обычно спрашивают, как вы удалите или переименуете колонку, не уронив старые поды.
Как отвечать
Ответ складывается из двух частей: где запускать миграции и какими их писать.
- отдельный
Jobперед выкладкой: образ тот же, командаalembic upgrade headилиpython manage.py migrate. В Helm это хукhelm.sh/hook: pre-upgrade, в Argo CD хукPreSync, в обычном CI шагkubectl wait --for=condition=complete job/migrateперед применением манифеста. НовыйDeploymentраскатывается, только если миграция завершилась успешно; - не в каждом поде: миграция в entrypoint или
initContainerпри пяти репликах запустится пять раз параллельно, а ни Alembic, ни Django сами блокировку не берут; - expand/contract: каждая миграция совместима с предыдущей версией кода. Колонку сначала добавляют nullable или с дефолтом, код пишет в обе, затем бэкфилл пачками, и только через релиз старое удаляется. Переименование превращается в цепочку «добавить, скопировать, переключить, удалить»;
- блокировки: перед
ALTER TABLEв PostgreSQL ставятSET lock_timeout, индексы создаютCONCURRENTLY(в Alembic внутриautocommit_block(), в Django операциейAddIndexConcurrentlyсatomic = False); - readiness probe: новый под получает трафик, только когда реально готов, а
maxUnavailable: 0держит старые поды до этого момента.
Откат через kubectl rollout undo возвращает только код. Схему он не трогает, поэтому совместимость назад и нужна.
Где спотыкаются
Кладут migrate в команду запуска контейнера. Под рестартует, миграция гоняется заново, а при масштабировании реплики конкурируют за одну схему.
Удаляют или переименовывают колонку в том же релизе, где меняют код. Старые поды, которые ещё обслуживают трафик, падают с ошибкой «column does not exist».
Советуют перейти на StatefulSet. К миграциям схемы он отношения не имеет: он про стабильные имена и тома подов, а не про порядок обновления базы.