При деплое в Kubernetes часто требуется выкатывать ресурсы в определённом порядке, а иногда и дожидаться готовности сторонних ресурсов. Например, сначала нужно запустить БД, дождаться создания динамического Secret’а сторонним оператором, потом выполнить инициализацию/миграции БД, а уже затем запустить само приложение.
Рассмотрим, как решать такие задачи с помощью Helm, а также сравним с более быстрым и удобным вариантом, который предлагает Open Source-утилита werf.

Развертывание с помощью Helm
Когда возникает необходимость указать порядок, в котором должны быть запущены приложения в кластере, встает вопрос: как это правильно сделать? В Helm задать последовательность выката ресурсов довольно сложно: в основном это делается либо через самодельные проверки готовности требуемых ресурсов в initContainers/containers, либо через разделение одного Helm-релиза на несколько частей и их последовательный выкат. Оба способа неудобны и требуют лишних действий.
Рассмотрим развертывание ресурсов в произвольном порядке. Для этого возьмем простой пример с базой данных и реализуем ожидание БД с помощью initContainers:
kind: StatefulSet metadata: name: postgres --- kind: Deployment metadata: name: redis {{ if $.Release.IsInstall }} --- kind: Job metadata: name: init-db spec: template: spec: initContainers: - name: wait-db image: postgres command: - sh - -ec - | until pg_isready -h postgres -p 5432 -U postgres; do sleep 1 done containers: - name: init-db image: backend command: ["my-backend", "init-db"] {{ else }} --- kind: Job metadata: name: migrate-db annotations: helm.sh/hook: pre-upgrade spec: template: spec: initContainers: - name: wait-db image: postgres command: - sh - -ec - | until pg_isready -h postgres -p 5432 -U postgres; do sleep 1 done containers: - name: migrate-db image: backend command: ["my-backend", "migrate-db"] {{ end }} --- kind: Deployment metadata: name: backend spec: template: spec: initContainers: - name: wait-db-init-and-ready image: backend command: - sh - -ec - | until <db-initialized-and-ready>; do sleep 1 done - name: wait-redis image: redis command: - sh - -ec - | until redis-cli -h redis -p 6379 get hello; do sleep 1 done containers: - name: backend image: backend
В этом примере реализован такой порядок:
-
развертывание БД;
-
инициализация или миграции БД;
-
развертывание приложения.
Здесь есть особенность: перед тем, как начинать деплой, нам необходимо убедиться, что динамически создающийся (например, оператором на основе секретов из Vault) Secret my-dynamic-secret присутствует в кластере. Поэтому сначала дождемся его создания, а затем начнем деплой приложения:
kubectl wait ... secret/my-dynamic-secret helm install app .
Теперь посмотрим, как можно решить эту задачу с werf.
Развертывание в произвольном порядке с помощью werf
Более удобно реализовать упорядоченный выкат можно с утилитой werf. Недавно у нее появилась возможность задать порядок выката ресурсов с помощью аннотаций, через которые указывается «вес» ресурса. По умолчанию (если ничего не указано) все ресурсы имеют вес 0, поэтому разворачиваются и отслеживаются одновременно. Но если задать им разные веса, то при выкате werf сгруппирует ресурсы в соответствии с их весом и будет разворачивать их от группы с меньшим весом к группе с большим весом, ожидая, пока каждая группа не придет в состоянии полной готовности.
Задать вес ресурсов можно через аннотацию werf.io/weight (по аналогии с helm.sh/hook-weight для Helm-хуков). Решим предыдущую задачу уже с использованием весов:
kind: StatefulSet metadata: name: postgres annotations: werf.io/weight: "0" --- kind: Deployment metadata: name: redis annotations: werf.io/weight: "0" {{ if $.Release.IsInstall }} --- kind: Job metadata: name: init-db annotations: werf.io/weight: "10" spec: template: spec: containers: - name: init-db image: backend command: ["my-backend", "init-db"] {{ end }} --- kind: Job metadata: name: migrate-db annotations: werf.io/weight: "20" spec: template: spec: containers: - name: init-db image: backend command: ["my-backend", "migrate-db"] --- kind: Deployment metadata: name: backend annotations: secret.external-dependency.werf.io/resource: "secret/my-dynamic-secret" werf.io/weight: "30" spec: template: spec: containers: - name: backend image: backend
Запустить развертывание теперь можно одной командой:
werf converge
Первыми задеплоятся база данных и Redis, затем произойдет инициализация или миграции БД, и только потом запустится приложение. Обратите внимание на аннотацию secret.external-dependency.werf.io/resource: "secret/my-dynamic-secret". Она добавлена к Deployment’у приложения и указывает, что перед созданием Deployment’а надо также дождаться готовности внешней зависимости — Secret’а my-dynamic-secret. При этом Secret может разворачиваться либо как часть другого релиза werf, либо вообще создаваться без werf (например, сторонним оператором).
Как видно, чарт приложения стал гораздо меньше и удобнее для чтения, а для запуска требуется выполнить одну команду.
Заключение
Мы рассмотрели управление порядком развертывания ресурсов в кластере Kubernetes с помощью новой функции утилиты werf. Она позволяет упростить сложный выкат приложений и быстрее писать чарты приложения, так как теперь нет необходимости реализовывать сложные проверки готовности его составных частей или внешних зависимостей.
P.S.
Читайте также в нашем блоге:
ссылка на оригинал статьи https://habr.com/ru/company/flant/blog/682804/
Добавить комментарий