Плавный Canary Release с использованием APISIX Ingress Controller и Flagger

Hengliang Tan

January 19, 2023

Ecosystem

Автор: Хэнлян Тан, менеджер по разработке в XPENG

В процессе разработки проекта обновление сервисов часто становится вызовом. Чтобы обеспечить наилучший пользовательский опыт, нам необходимо максимально избегать рисков недоступности сервисов. Таким образом, появилась непрерывная поставка (continuous delivery), которая стала общепринятой практикой в корпоративной разработке программного обеспечения и естественным развитием устоявшихся принципов непрерывной интеграции. Однако непрерывное развертывание (continuous deployment) до сих пор встречается редко из-за сложности управления и страха, что сбои при развертывании повлияют на доступность системы. Канареечное развертывание (canary release), вероятно, является наиболее классическим сценарием в системе непрерывной поставки. На его основе мы можем быстро обнаруживать нездоровые и проблемные сервисы и легко откатываться к предыдущей версии.

Канареечное развертывание

Канареечное развертывание также известно как серое развертывание (grayscale release). Обычно новая версия приложения выпускается и развертывается как "канарейка" для тестирования производительности. Старая версия остается для нормальной работы на том же этапе. Во время обновления часть пользователей будет направлена на использование новой версии, в то время как другие пользователи продолжат использовать старую версию. При условии обеспечения общей стабильности системы это позволяет раньше обнаруживать ошибки и своевременно вносить корректировки.

Канареечное развертывание не выпускает обновление напрямую. Оно постепенно направляет определенный процент трафика на небольшое количество пользователей. Если ошибок не обнаружено, обновление будет распространено на всех пользователей, а старая версия будет постепенно выведена из эксплуатации. Этот метод снижает риск внедрения новых функций в производственную среду.

В этой статье будет рассказано, как добиться плавного канареечного развертывания с помощью Apache APISIX Ingress и Flagger, повысить эффективность выпуска и снизить риски.

О Apache APISIX Ingress

Apache APISIX Ingress реализован через Kubernetes Ingress Controller, который использует Apache APISIX в качестве прокси-сервера на уровне данных. Он предоставляет сотни функций, таких как балансировка нагрузки, динамический апстрим, канареечное развертывание, детальная маршрутизация, ограничение скорости, деградация сервисов, автоматическое отключение сервисов, аутентификация и наблюдаемость. Он был принят компаниями и организациями как в Китае, так и за рубежом, включая Zoom, Tencent Cloud, Jiakaobaodian, Horizon Robotics, European Copernicus Reference System и другие.

О Flagger

Flagger — это проект CNCF (Cloud Native Computing Foundation) и часть семейства инструментов GitOps Flux. Недавно CNCF также объявил о официальном выпуске Flux, что является хорошим показателем успеха и перспективности технологии облачных вычислений. Как инструмент прогрессивной поставки, Flagger автоматизирует процесс выпуска приложений, работающих на Kubernetes. Он снижает риск внедрения новой версии программного обеспечения в производственную среду, постепенно перенаправляя трафик на новую версию, измеряя аналитические метрики и выполняя тесты на соответствие.

После непрерывных усилий сообществ Apache APISIX и Flux, Flagger недавно выпустил версию v1.27.0, которая поддерживает автоматическое канареечное развертывание с использованием Apache APISIX Ingress и Flagger.

featured-<Flagger and Apache APISIX Ingress>.jpg

Давайте вместе испытаем этот плавный процесс канареечного развертывания.

Окружение

Требуется кластер Kubernetes версии 1.19 или новее, который можно установить через kind.

Установка компонентов

Используйте Helm V3 для установки Apache APISIX и Apache APISIX Ingress Controller

helm repo add apisix https://charts.apiseven.com kubectl create ns apisix helm upgrade -i apisix apisix/apisix --version=0.11.3 \ --namespace apisix \ --set apisix.podAnnotations."prometheus\.io/scrape"=true \ --set apisix.podAnnotations."prometheus\.io/port"=9091 \ --set apisix.podAnnotations."prometheus\.io/path"=/apisix/prometheus/metrics \ --set pluginAttrs.prometheus.export_addr.ip=0.0.0.0 \ --set pluginAttrs.prometheus.export_addr.port=9091 \ --set pluginAttrs.prometheus.export_uri=/apisix/prometheus/metrics \ --set pluginAttrs.prometheus.metric_prefix=apisix_ \ --set ingress-controller.enabled=true \ --set ingress-controller.config.apisix.serviceNamespace=apisix

Установите компоненты Flagger и Prometheus в пространстве имен apisix.

helm repo add flagger https://flagger.app helm upgrade -i flagger flagger/flagger \ --namespace apisix \ --set prometheus.install=true \ --set meshProvider=apisix

Примечание: если вам нужно настроить Prometheus или Prometheus Operator, вы можете найти соответствующие статьи для внесения изменений.

Инициализация приложения

Flagger может быть применен к развертываниям Kubernetes и другим рабочим нагрузкам, а также может быть объединен с HPA. Он создаст серию объектов: развертывания Kubernetes, службы ClusterIP и ApisixRoute. Эти объекты могут предоставлять приложения за пределами кластера для предоставления услуг и использоваться для анализа процесса канареечного развертывания.

Создайте новое тестовое пространство имен:

kubectl create ns test

Создайте новое развертывание и HPA. Здесь мы используем официальный пример кода из Flagger.

kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main

Разверните службу нагрузочного тестирования Flagger для генерации трафика во время канареечного развертывания для анализа.

helm upgrade -i flagger-loadtester flagger/loadtester \ --namespace=test

Создайте ApisixRoute Apache APISIX, затем Flagger будет ссылаться на созданный ресурс и генерировать ApisixRoute Apache APISIX Ingress в канареечной версии. (Замените app.example.com в примере ниже на ваш фактический домен)

apiVersion: apisix.apache.org/v2 kind: ApisixRoute metadata: name: podinfo namespace: test spec: http: - backends: - serviceName: podinfo servicePort: 80 match: hosts: - app.example.com methods: - GET paths: - /* name: method plugins: - name: prometheus enable: true config: disable: false prefer_name: true

Сохраните это как podinfo-apisixroute.yaml и отправьте в кластер:

kubectl apply -f ./podinfo-apisixroute.yaml

Создайте пользовательский ресурс Canary в Flagger. (Замените app.example.com в примере на ваш фактический домен)

apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: podinfo namespace: test spec: provider: apisix targetRef: apiVersion: apps/v1 kind: Deployment name: podinfo # Ссылка на маршрут apisix routeRef: apiVersion: apisix.apache.org/v2 kind: ApisixRoute name: podinfo progressDeadlineSeconds: 60 service: port: 80 targetPort: 9898 analysis: interval: 10s # максимальное количество сбоев для отката threshold: 10 # максимальный процент трафика на канареечную версию # (0-100) maxWeight: 50 # шаг анализа канареечного развертывания # (0-100) stepWeight: 10 # используйте Prometheus для проверки информации о трафике APISIX metrics: - name: request-success-rate # минимальный уровень успешности (без ответов 5xx) # (0-100) thresholdRange: min: 99 interval: 1m - name: request-duration # P99 — это максимальная задержка запроса (мс) thresholdRange: max: 500 interval: 30s webhooks: # автоматизированный трафик для анализа канареечного развертывания, измененный на основе фактического сценария - name: load-test url: http://flagger-loadtester.test/ timeout: 5s type: rollout metadata: cmd: |- hey -z 1m -q 10 -c 2 -h2 -host app.example.com http://apisix-gateway.apisix/api/info

Сохраните это как podinfo-canary.yaml и отправьте в кластер:

kubectl apply -f ./podinfo-canary.yaml

Flagger автоматически создаст связанные ресурсы:

# Отправлено deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo

# Автоматически создано deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary

featured-<version 1>.jpg

На этом этапе вы можете получить доступ к приложению через доменное имя app.example.com (Замените app.example.com в примере на ваш фактический домен), и вы увидите текущую версию приложения.

Автоматизация канареечного развертывания

Flagger реализует цикл управления, который постепенно перенаправляет трафик на канареечные узлы, измеряя ключевые показатели производительности, такие как уровень успешности HTTP-запросов, средняя продолжительность запроса и состояние подов. В зависимости от анализа соответствующих показателей, выпуск или остановка канареечного развертывания и публикация результатов анализа на соответствующих платформах, таких как Slack, MS Teams или Prometheus Alert Manager.

Flagger Control Loop

Запустите канареечное развертывание, обновив версию контейнера

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.1

Flagger обнаружит, что есть новая версия развертывания, и начнет пробный запуск анализа канареечного развертывания.

kubectl -n test describe canary/podinfo Status: Canary Weight: 0 Conditions: Message: Canary analysis completed successfully, promotion finished. Reason: Succeeded Status: True Type: Promoted Failed Checks: 1 Iterations: 0 Phase: Succeeded Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Synced 2m59s flagger podinfo-primary.test not ready: waiting for rollout to finish: observed deployment generation less than desired generation Warning Synced 2m50s flagger podinfo-primary.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available Normal Synced 2m40s (x3 over 2m59s) flagger all the metrics providers are available! Normal Synced 2m39s flagger Initialization done! podinfo.test Normal Synced 2m20s flagger New revision detected! Scaling up podinfo.test Warning Synced 2m (x2 over 2m10s) flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available Normal Synced 110s flagger Starting canary analysis for podinfo.test Normal Synced 109s flagger Advance podinfo.test canary weight 10 Warning Synced 100s flagger Halt advancement no values found for apisix metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found Normal Synced 90s flagger Advance podinfo.test canary weight 20 Normal Synced 80s flagger Advance podinfo.test canary weight 30 Normal Synced 69s flagger Advance podinfo.test canary weight 40 Normal Synced 59s flagger Advance podinfo.test canary weight 50 Warning Synced 30s (x2 over 40s) flagger podinfo-primary.test not ready: waiting for rollout to finish: 1 old replicas are pending termination Normal Synced 9s (x3 over 50s) flagger (combined from similar events): Promotion completed! Scaling down podinfo.test

Во время процесса канареечного развертывания вы будете получать разные ответы при доступе к приложению через доменное имя app.example.com (Замените app.example.com на ваш фактический домен).

featured-<version 2>.jpg

Просматривая ресурс ApisixRoute podinfo-podinfo-canary Apache APISIX, автоматически созданный Flagger, вы обнаружите, что веса службы podinfo-primary и службы podinfo-canary изменяются в процессе публикации.

spec: http: - backends: - serviceName: podinfo-primary servicePort: 80 # Автоматически регулируется Flagger weight: 80 - serviceName: podinfo-canary servicePort: 80 # Автоматически регулируется Flagger weight: 20

Вы увидите последнюю стабильную версию, когда окончательный выпуск будет завершен.

featured-<version 3>.jpg

Примечание: Flagger повторно запустит анализ канареечного развертывания, если вы измените развертывание во время канареечного развертывания.

Вы можете наблюдать за всеми канареечными развертываниями с помощью этой команды:

watch kubectl get canaries --all-namespaces NAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME test podinfo-2 Progressing 10 2022-11-23T05:00:54Z test podinfo Succeeded 0 2022-11-23T06:00:54Z

Откат

Во время анализа канареечного развертывания вы можете протестировать Flagger, чтобы приостановить канареечное развертывание и откатиться к старой версии, создав HTTP 500 Bad Request.

Запустите еще одно канареечное развертывание:

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.2

Войдите в контейнер нагрузочного тестирования

kubectl -n test exec -it deploy/flagger-loadtester bash

Создайте ошибку HTTP 500:

hey -z 1m -c 5 -q 5 -host app.example.com http://apisix-gateway.apisix/status/500

Симулируйте задержку сервера:

watch -n 1 curl -H \"host: app.example.com\" http://apisix-gateway.apisix/delay/1

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

kubectl -n apisix logs deploy/flagger -f | jq .msg "New revision detected! Scaling up podinfo.test" "canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available" "Starting canary analysis for podinfo.test" "Advance podinfo.test canary weight 10" "Halt podinfo.test advancement success rate 0.00% < 99%" "Halt podinfo.test advancement success rate 26.76% < 99%" "Halt podinfo.test advancement success rate 34.19% < 99%" "Halt podinfo.test advancement success rate 37.32% < 99%" "Halt podinfo.test advancement success rate 39.04% < 99%" "Halt podinfo.test advancement success rate 40.13% < 99%" "Halt podinfo.test advancement success rate 48.28% < 99%" "Halt podinfo.test advancement success rate 50.35% < 99%" "Halt podinfo.test advancement success rate 56.92% < 99%" "Halt podinfo.test advancement success rate 67.70% < 99%" "Rolling back podinfo.test failed checks threshold reached 10" "Canary failed! Scaling down podinfo.test"

Настройка метрик для анализа канареечного развертывания

Анализ канареечного развертывания может быть расширен путем запроса метрик Prometheus. Мы настраиваем их на основе фактических бизнес-сценариев. Создайте шаблон метрики и отправьте его в кластер.

apiVersion: flagger.app/v1beta1 kind: MetricTemplate metadata: name: not-found-percentage namespace: test spec: provider: type: prometheus address: http://flagger-prometheus.apisix:9090 query: | sum( rate( apisix_http_status{ route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+", code!~"4.." }[{{ interval }}] ) ) / sum( rate( apisix_http_status{ route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+" }[{{ interval }}] ) ) * 100 # Измените анализ в канареечном развертывании и добавьте созданный выше шаблон метрики. analysis: metrics: - name: "404s percentage" templateRef: name: not-found-percentage thresholdRange: max: 5 interval: 1m

Приведенная выше конфигурация проверяет канареечное развертывание, проверяя, превышает ли QPS (запросов в секунду) HTTP 404 запросов 5% от общего трафика. Если HTTP 404 запросы превышают порог в 5%, канареечное развертывание завершается неудачей.

Заключение

Вышеуказанный процесс может быть расширен с помощью дополнительных пользовательских проверок метрик, Webhook, ручных утверждений и уведомлений через Slack или MS Teams.

Очень плавное канареечное развертывание достигается благодаря интеграции Apache APISIX и Flagger, что повышает эффективность выпуска и снижает риски. В будущем два сообщества будут более тесно сотрудничать для реализации дополнительных возможностей публикации, таких как Blue/Green Mirroring и A/B Testing.

Tags: