Как лучше всего запускать одноразовые задачи миграции в кластере кубернетов

У меня есть миграции баз данных, которые я хотел бы запустить до развертывания новой версии моего приложения в кластере Kubernetes. Я хочу, чтобы эти миграции выполнялись автоматически в рамках конвейера непрерывной доставки. Миграция будет инкапсулирована как изображение контейнера. Какой лучший механизм для достижения этого?

Требования к решению:

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

Я предположил, что функциональность Jobs в Kubernetes сделает это легко, но, похоже, есть несколько проблем:

Было бы лучше использовать "голые стручки"? Если да, то как это может работать?

Ответ 1

Вы можете попытаться сделать оба задания миграции и приложение независимыми друг от друга, выполнив следующие действия:

  • Успешное возвращение задания миграции, даже если миграция завершилась неудачно. Храните машиночитаемую запись где-нибудь, что было результатом миграции. Это можно сделать либо явно (например, путем написания последней версии схемы в каком-либо поле таблицы базы данных), либо неявно (предположим, что при успешном задании на миграцию должно быть создано определенное поле). Задача миграции вернет код ошибки, если он не по техническим причинам (так же как недоступность базы данных, к которой должна применяться миграция). Таким образом, вы можете выполнять миграции через Kubernetes Jobs и полагаться на свою способность работать до завершения в конце концов.
  • Построена новая версия приложения, так что она может работать с базой данных как на этапах до и после миграции. Это означает, что это зависит от ваших бизнес-требований: приложение может либо простаивать до тех пор, пока миграция не завершится успешно, либо может привести к другим результатам для своих клиентов в зависимости от текущей фазы. Ключевым моментом здесь является то, что приложение обрабатывает результат миграции, созданный ранее заданиями миграции, и действует соответственно, не прерывая ошибки.

Объединяя эти два подхода к разработке, вы должны иметь возможность разрабатывать и выполнять задания и приложения миграции независимо друг от друга и не должны вводить временную связь.

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

Ответ 2

  блокирование во время ожидания результата задания в очереди, по-видимому, требует сценариев, созданных вручную

Это больше не нужно, благодаря команде kubectl wait.

Вот как я выполняю миграцию БД в CI:

kubectl apply -f migration-job.yml
kubectl wait --for=condition=complete --timeout=60s job/migration
kubectl delete job/migration

В случае сбоя или тайм-аута одна из двух первых команд CLI возвращается с ошибочным кодом выхода, который затем принудительно завершает работу остальной части конвейера CI.

migration-job.yml описывает ресурс Job для kubernetes, настроенный с restartPolicy: Never и достаточно низким activeDeadlineSeconds.

Вы также можете использовать атрибут spec.ttlSecondsAfterFinished attribute вместо запуска kubectl delete вручную, но он все еще находится в альфа-режиме на момент написания и, по крайней мере, не поддерживается Google Kubernetes Engine.

Ответ 3

Учитывая возраст этого вопроса, я не уверен, что initContainers были доступны в то время, но теперь они очень полезны.

https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

Недавно я настроил это так, чтобы модуль postgres и наше приложение django работали в одном и том же пространстве имен, однако модуль django имеет 3 initContainers:

  1. Инициализационная-миграция
  2. Инициализационные-светильники
  3. INIT-createsuperUser

Для этого нужно будет запустить модуль django и модуль postgres параллельно, а также постоянно запускать модуль initContainers до тех пор, пока модуль postgres не появится, а затем ваши миграции должны выполняться.

Что касается модулей, которые постоянно перезапускаются, возможно, они уже исправили restartPolicy. Я в настоящее время довольно плохо знаком с kubernetes, но это - то, что я нашел работы для меня.