Ag baint brainse gné as dáta i mbraisle Kubernetes
Dia duit! Feature branch (aka deploy preview, review app) — это когда деплоится не только master ветка, но и каждый pull request на уникальный URL. Можно проверить работает ли код в production-окружении, фичу можно показать другим программистам или продуктологам. Пока вы работаете в pull request’е, каждый новый commit текущий deploy для старого кода удаляется, а новый deploy для нового кода выкатывается. Вопросы могут возникнуть тогда, когда вы смерджили pull request в master ветку. Feature branch вам больше не нужна, но ресурсы Kubernetes все еще находятся в кластере.
Еще про feature branch’и
Один из подходов как сделать feature branch’и в Kubernetes — использовать namespace’ы. Если кратко, production конфигурации выглядит так:
В общем, я написал Oibreoir Kubernetes (приложение, которое имеет доступ к ресурсам кластера), ссылка на проект на Github. Он удаляет namespace’ы, которые относятся к старым feature branch’ам. В Kubernetes, если удалить namespace, другие ресурсы в этом namespace также удаляются автоматически.
$ kubectl get pods --all-namespaces | grep -e "-pr-"
NAMESPACE ... AGE
habr-back-end-pr-264 ... 4d8h
habr-back-end-pr-265 ... 5d7h
Про то как внедрить feature branch’и в кластер, можно почитать anseo и anseo.
Spreagadh
Давайте посмотрим на типичный жизненный цикл pull request’a с непрерывной интеграцией (continuous integration):
Пушим новый commit в ветку.
На билде, запускаются линтеры и/или тесты.
На лету формируются конфигурации Kubernetes pull request’a (например, в готовый шаблон подставляется его номер).
С помощью kubectl apply конфигурации попадают в кластер (deploy).
Pull request сливается в master ветку.
Пока вы работаете в pull request’е, каждый новый commit текущий deploy для старого кода удаляется, а новый deploy для нового кода выкатывается. Но когда pull request сливается в master ветку, будет билдится только master ветка. В итоге получается, что про pull request мы уже забыли, а его Kubernetes ресурсы все еще находятся в кластере.
Paraiméadar namespaceSubstring нужен, чтобы отфильтровать namespace’ы для pull request’ов от других namespace’ов. Например, если в кластере есть следующие namespace’ы: habr-back-end, habr-front-end, habr-back-end-pr-17, habr-back-end-pr-33, тогда кандидатами на удаление будут habr-back-end-pr-17, habr-back-end-pr-33.
Paraiméadar afterDaysWithoutDeploy нужен чтобы, удалять старые namespace’ы. Например, если namespace создан 3 дня 1 час назад, а в параметре указано 3 дня, этот namespace будет удален. Работает и в обратную сторону, если namespace создан 2 дня 23 часа назад, а в параметре указано 3 дня, этот namespace не будет удален.
Есть еще один параметр, он отвечает за то как часто сканировать все namespace’ы и проверять на дни без deploy’я — checkEveryMinutes. По умолчанию он равен 30 минутам.
cubectl — интерфейс командной строки для управления кластером.
Поднимаем Kubernetes кластер локально:
$ minikube start --vm-driver=docker
minikube v1.11.0 on Darwin 10.15.5
Using the docker driver based on existing profile.
Starting control plane node minikube in cluster minikube.
Cuirimid in iúl kubectl использовать локальный кластер по умолчанию:
$ kubectl config use-context minikube
Switched to context "minikube".
Так как production конфигурации настроены проверять старые namespace’ы, а в нашем ново поднятом кластере их нет, заменим переменную окружения IS_DEBUG ar true. При таком значении параметр afterDaysWithoutDeploy не учитывается и namespace’ы не проверяются на дни без deploy’я, только на вхождение подстроки (-pr-).
Má tá tú ar Linux:
$ sed -i 's|false|true|g' stale-feature-branch-production-configs.yml
Má tá tú ar macOS:
$ sed -i "" 's|false|true|g' stale-feature-branch-production-configs.yml
$ kubectl get pods --namespace stale-feature-branch-operator
NAME ... STATUS ... AGE
stale-feature-branch-operator-6bfbfd4df8-m7sch ... Running ... 38s
Если заглянуть в его логи, он готов обрабатывать ресурсы StaleFeatureBranch:
Оператор отреагировал и готов проверять namespace’ы:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Stale feature branch is being processing.","namespaceSubstring":"-pr-","afterDaysWithoutDeploy":1,"checkEveryMinutes":1,"isDebug":"true"}
Socraigh fixtures, содержащие два namespace’а (project-pr-1, project-pr-2) и их deployments, services, ingress, и так далее:
$ kubectl apply -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/first-feature-branch.yml -f https://raw.githubusercontent.com/dmytrostriletskyi/stale-feature-branch-operator/master/fixtures/second-feature-branch.yml
...
namespace/project-pr-1 created
deployment.apps/project-pr-1 created
service/project-pr-1 created
horizontalpodautoscaler.autoscaling/project-pr-1 created
secret/project-pr-1 created
configmap/project-pr-1 created
ingress.extensions/project-pr-1 created
namespace/project-pr-2 created
deployment.apps/project-pr-2 created
service/project-pr-2 created
horizontalpodautoscaler.autoscaling/project-pr-2 created
secret/project-pr-2 created
configmap/project-pr-2 created
ingress.extensions/project-pr-2 created
Проверяем, что все ресурсы выше успешно созданы:
$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
NAME ... READY ... STATUS ... AGE
pod/project-pr-1-848d5fdff6-rpmzw ... 1/1 ... Running ... 67s
NAME ... READY ... AVAILABLE ... AGE
deployment.apps/project-pr-1 ... 1/1 ... 1 ... 67s
...
Так как мы включили debug, namespace’ы project-pr-1 и project-pr-2, следовательно и все остальные ресурсы, должны будут сразу удалиться не учитывая параметр afterDaysWithoutDeploy. В логах оператора это видно:
$ kubectl logs stale-feature-branch-operator-6bfbfd4df8-m7sch -n stale-feature-branch-operator
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-1"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-1","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-1"}
... "msg":"Namespace should be deleted due to debug mode is enabled.","namespaceName":"project-pr-2"}
... "msg":"Namespace is being processing.","namespaceName":"project-pr-2","namespaceCreationTimestamp":"2020-06-16 18:43:58 +0300 EEST"}
... "msg":"Namespace has been deleted.","namespaceName":"project-pr-2"}
Если проверить наличие ресурсов, они будут в статусе Terminating (процесс удаления) или уже удалены (вывод команды пуст).
$ kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-1 && kubectl get namespace,pods,deployment,service,horizontalpodautoscaler,configmap,ingress -n project-pr-2
...
Можете повторить процесс создания fixtures несколько раз и убедиться, что они будут удалены в течение минуты.
Roghanna eile
Что можно сделать вместо оператора, который работает в кластере? Подходов несколько, все они неидеальны (и их недостатки субъективны), и каждый сам решает что лучше всего подойдет на конкретном проекте:
Удалять feature branch во время билда непрерывной интеграции master ветки.
Для этого надо знать какой pull request относится к commit’у, который билдится. Так как feature branch namespace содержит в себе идентификатор pull request’a — его номер, или название ветки, идентификатор всегда придется указывать в commit’e.
Билды master веток фейлятся. Например, у вас следующие этапы: скачать проект, запустить тесты, собрать проект, сделать релиз, отправить уведомления, очистить feature branch последнего pull request’a. Если билд сфейлится на отправке уведомления, вам придется удалять все ресурсы в кластере руками.
Без должного контекста, удаление feature branch’и в master билде неочевидно.
Возможно, это не ваш подход. Например, в Jenkins, только один вид пайплайна поддерживает возможность сохранять его конфигурации в исходном коде. При использовании webhook’ов нужно написать свой скрипт для их обработки. Этот скрипт придется размещать в интерфейсе Jenkins’а, что трудно поддерживать.