Доброго времени суток, читатель!
Вот мы и подошли к заключительной части цикла статей о Канареечных релизах в Kubernetes и методах их реализации. Желаю приятного чтения и надеюсь, что данный цикл был для вас полезным.
Использование решения Jenkins X для выполнения Canary деплоя в кластере Kubernetes
В этом цикле:
- Canary Deployment через GitlabCI + GitOps/Manual Approach
- Canary Deployment через Argo Rollouts
- Canary Deployment с Istio
- (эта статья)
Что мы будем делать здесь?
Мы создадим Jenkins X k8s кластер и тестовое приложение на Python шаг за шагом. Вы можете повторять по примеру, либо просто читать, смотреть иллюстрации и результаты для получения представления о взаимодействии JenkinsX+Flagger+Istio сanary deployment и решить для себя, стоит ли эта связка более глубокого изучения.
Canary Deployment
Надеемся, что вы читали первую часть, где мы кратко объясняли что такое сanary deployment и показывали как его реализовать через стандартные ресурсы Kubernetes.
Jenkins X
И мы предполагаем, что читая эту статью, вы уже имеете представление о том, что такое Jenkins X. Если нет, то вы можете почитать о нем здесь.
Istio
Также, мы надеемся, что вы знаете что такое Istio. Если нет, то вы можете почитать о нем здесь. Вам также стоит прочитать часть 3, где мы осуществляли Canary deployment при помощи Istio, для лучшего понимания.
Flagger
Flagger это оператор Kubernetes, который автоматизирует сanary deployments используя Istio, Linkerd, App Mesh, NGINX, Contour или Gloo routing для управления трафиком и метрики Prometheus для canary-аналитики. Canary-аналитика может быть расширена с помощью веб-хуков для проведения тестов доступа, нагрузочных испытаний или любой другой проверки. (источник)
Создаем тестовую инфраструктуру и приложение
Мы будем использовать инструмент командной строки Jenkins X jx
для создания кластера Kubernetes, репозитория Github и пробного приложения, он отлично подходит для создания быстрого примера.
Jenkins X k8s кластер
Первым делом мы создаем Jenkins X кластер, здесь мы используем Gcloud:
jx create cluster gke -n jenkinsx --machine-type n1-standard-4
Вам нужно выбрать тип “Serverless Jenkins X Pipelines with Tekton” и привязать все к вашему Github аккаунту. Это автоматически создаст два Github репозитория для stage и production окружений.
Далее мы установим некоторые дополнения (addons):
jx create addon istio
jx create addon flagger
jx create addon prometheus
Если вы столкнетесь с проблемами с Istio (у меня отсутствовали метрики istio_requests_total
в Prometheus), вы можете установить Istio вручную:
istioctl manifest generate --set values.kiali.enabled=true --set values.tracing.enabled=true --set values.grafana.enabled=true --set values.prometheus.enabled=true > istio.yaml
kubectl -f istio.yaml install
Установка Flagger через jx
автоматически внедрит Istio sidecar в поды namespace jx-production
. Проверяем:
kubectl get ns -L istio-injection
Добавьте label istio-injection: enabled
к любому namespace, в поды которого Istio sidecar должен быть внедрен.
Test App / Quickstart
Теперь ждем пока jxing-nginx-ingress-controller
в namespace kube-system
получит External IP. Затем создаем простое python-приложение:
jx create quickstart --project-name python-test
Выбираем тип python-http
. Вы можете установить любой другой, потому что canary deployment работает для всех типов. Это должно быть что-то предоставляющее простые HTTP endpoints для тестовых нужд.
Jenkins X автоматически создаст Github репозиторий для приложения.
Я изменил do_GET
метод в сгенерированном app.py
, что бы он возвращал текст, а не изображение:
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
# Send the html message
output = 'v1'
self.wfile.write(output.encode('utf-8'))
return
Окружения
Jenkins X создаст три окружения по умолчанию (jx get env
):
Каждое окружения имеет свой собственный Git-репозиторий, где все сконфигурировано через GitOps. Окружения на самом деле сконфигурированы из Helm Charts и ссылаются на все приложения + версии, установленные в них, через require.yaml.
Начальный Deployment
При создании нового quickstart приложения, или импорта существующего (jx import
), он будет выпущен как версия 0.0.1 в stage окружении. Так происходит, потому что PROMOTE установлен в Auto для stage окружения. Мы можем видеть их как Pull Request в stage репозитории, который Jenkins X автоматически создает и сливает. Мы можем отслеживать все действия Pipeline через:
jx get activities -w
После того как pipelines завершатся успешно, мы можем проверить доступность приложений:
jx get applications
Jenkins X работает автоматически с версиями Semver
В данный момент мы видим, что версия 0.0.1
задеплоена на stage
, в prod
пока ничего нет. Мы можем проверить следующим образом:
kubectl -n jx-staging get all # shows the app
kubectl -n jx-production get all # shows nothing
У нас должна быть возможность открыть доступ к stage приложению, через предоставленный URL:
Перемещение в production
(Прежде чем переходить в production я внес ещё одно изменение, которое увеличило версию до 0.0.2
)
Перемещение (promote
) в production по факту означает “деплой”. Через jx get env
мы можем увидеть, что production требует ручного деплоя, поэтому мы делаем:
jx promote --version 0.0.2 --env production
Это автоматически создаст Pull Request в Jenkins X production Github репозиторий. И сейчас jx get applications
покажет версию 0.0.2 на stage и так же на production:
Мы можем также переместить приложение в production через изменение requirements.yaml
файла вручную в репозитории prod окружения.
Включение Canary для prod окружения
Прямо сейчас деплой в prod или stage производится без использования canary, но через rolling-rollouts Kubernetes.
В нашем репозитории для тестового приложения Python, Jenkins X автоматически создал через хелм-чарт. Если мы откроем файл charts/APP_NAME/values.yaml,
то можем увидеть различные варианты Flagger Canary:
# Canary deployments
# If enabled, Istio and Flagger need to be installed in the cluster
canary:
enabled: false
progressDeadlineSeconds: 60
canaryAnalysis:
interval: "1m"
threshold: 5
maxWeight: 60
stepWeight: 20
# WARNING: Canary deployments will fail and rollback if there is no traffic that will generate the below specified metrics.
metrics:
requestSuccessRate:
threshold: 99
interval: "1m"
requestDuration:
threshold: 1000
interval: "1m"
# The host is using Istio Gateway and is currently not auto-generated
# Please overwrite the `canary.host` in `values.yaml` in each environment repository (e.g., staging, production)
host: acme.com
С данными настройками успешный canary deployment пройдет примерно за 3 минуты, по 1 минуте на каждый шаг: 20%, 40%, 60%.
Тем не менее по умолчанию сanary отключен через canary: enabled: false
.
Мы можем изменить этот параметр для каждого Jenkins X окружения, что я и делаю для production репозитория environment-jenkinsx-production
. Можно аналогично переопределить эти значения в Python, потому что репозитории с окружениями представляют собой Helm charts и ссылаются на все развернутые приложения через requirements.yaml
. Я добавил следующий env/values.yaml
в репозиторий environment-jenkinsx-production
:
...
jenkinsx-istio-canary-python-test:
canary:
enabled: true
host: jenkinsx-istio-canary-python-test.35.204.67.7.nip.io
- Домен
xxx.IP_ADDRESS.nip.io
будет просто перенапрален на IP_ADDRESS. Отлично подходит для простого тестирования по доменному имени. host
: будет именем хоста Istio, через которое он сможет принимать запросы. Найдем внешний IP-адрес шлюза Istio с помощью:kubectl -n istio-system get svc
. Нам необходимо убедиться, что доменное имя, указанное вhost:
, указывает на External IP шлюза Istio.
Внесение изменений в репозиторий production окружения будет автоматически триггерить сборку в Jenkins X, проверим через:
jx get activity
Ждем пока все activities станут successful. Теперь нам нужно увидеть как автоматически создались Istio VirtualService и Gateway:
kubectl -n jx-production get virtualservices.networking.istio.io,gateways.networking.istio.io
Заметим, что в первый раз, когда он был задеплоен, он не выполнит сanary, так как ему нужна предыдущая версия приложения для сравнения, но он заработает после второго деплоя. (источник)
Теперь нам нужна возможность доступа к нашему приложению в production через Istio на определенном хосте:
jenkinsx-istio-canary-python-test.35.204.67.7.nip.io:
Откроем Flagger Grafana Dashboard
Flagger установит Grafana в namespace istio-system, следовательно, мы можем выполнить:
kubectl port-forward -n istio-system service/flagger-grafana 3000:80
# admin:admin
В Grafana перейдите в Istio Dashboard и введите:
- namespace:
jx-production
- primary:
jx-jenkinsx-istio-canary-python-test-primary
- canary:
jx-jenkinsx-istio-canary-python-test-canary
Primary и canary это названия services. Они созданы автоматически при деплое, когда Canary был включен.
Если у вас отсутствуют метрики istio_requests_total
, убедитесь, что Istio установлена правильно, возможно, потребуется установка вручную, а не через jx
.
Flagger Canary Workflow и Анализ
В Helm Chart для Python приложений у нас есть множество настроек, которые мы можем изменять (здесь можно почитать описания большинства из них):
canary:
enabled: false # false, but we set to true in prod env git repo
progressDeadlineSeconds: 60
canaryAnalysis:
interval: "1m"
threshold: 5
maxWeight: 60
stepWeight: 20
# WARNING: Canary deployments will fail and rollback if there is no traffic that will generate the below specified metrics.
metrics:
requestSuccessRate:
threshold: 99
interval: "1m"
requestDuration:
threshold: 1000
interval: "1m"
Мы должны скорректировать их в зависимости от потребностей нашего приложения. Flagger выполнит автоматический анализ метрик и будет выполнять развертывание только при соблюдении требований.
Чтобы увидеть текущий статус развертывания Canary, проверьте ресурсы Flagger:
kubectl -n jx-production get canaries.flagger.app
Выполнение Canary Deployment
Deploy изменений
Сейчас мы изменили приложение app.py
так, чтобы оно возвращало другой текст на GET запрос. Создаем Pull Request в master-репозитории с приложением и делаем его merge. Jenkins X выполнит его автоматический deploy на stage.
Теперь задеплоим его вручную на prod, скопируем новую версию, которая запущена на stage. Сейчас я на 0.0.6 версии, так как я внес некоторые изменения между ними:
jx promote --version 0.0.6 --env production
И можем посмотреть статус работы Canary:
kubectl -n jx-production get events --field-selector involvedObject.kind=Canary --sort-by='{.lastTimestamp}'
Запуск Canary с весом 20%
2m39s Normal Synced Canary Advance jx-jenkinsx-istio-canary-python-test.jx-production canary weight 20
Мы запускаем повторяющийся curl на production Istio endpoint, который выдает результат, что 20% запросов отправлены на новую версию:
Canary терпит неудачу (недостаточно трафика)
Мы должны убедиться, что достаточно трафика достигает endpoint, иначе Canary анализ через Flagger провалится и запустит откат:
Canary также не запустится, если соответственные требования не будут выполнены.
Canary с весом 40%
Если трафика, который успешно достигает приложения достаточно, Flagger увеличит вес до 40%:
Canary с весом 60%
Если будет достаточно трафика, которое смог быть корректно обработан, Flagger увеличит его объем до 60%:
60s Normal Synced Canary Advance jx-jenkinsx-istio-canary-python-test.jx-production canary weight 60
Canary прошел успешно
25s Normal Synced Canary Routing all traffic to primary
Теперь все запросы обрабатываются новой версией:
Итог
Jenkins X можно относительно легко настроить для работы с Istio и Flagger для Canary Deployments. Однако, у меня были проблемы с установкой Istio через jx create addon istio, и мне пришлось делать это вручную.
Я не игрался с настройками Flagger, но использование настроек просто по умолчанию, как мне кажется, отлично подходит для тестовых исследований. Я думаю, что как только вы познакомитесь с Jenkins X и с предлагаемым им функционалом, то сможете избавиться от множества ручной или повторяющейся работы.
Так же без Jenkins X, я думаю, сама по себе комбинация Flagger и Istio для Canary Deployments весьма мощна, относительно тех, которые я изучал самостоятельно в последнее время.
Ещё/Источники
https://jenkins-x.io/docs/managing-jx/tutorials/progressive-delivery/
https://docs.flagger.app/usage/progressive-delivery
(Прим. пер. — в конце статьи автор приводит ссылку на тренажер для подготовки к экзамену для получения сертификата CKAD — https://killer.sh/ )