Lanzamiento Canary Suave Usando APISIX Ingress Controller con Flagger

Hengliang Tan

January 19, 2023

Ecosystem

Autor: Hengliang Tan, Gerente de Ingeniería en XPENG

En el proceso de desarrollo de proyectos, las actualizaciones de servicios suelen ser un desafío. Para ofrecer la mejor experiencia de usuario, necesitamos evitar en la medida de lo posible el riesgo de indisponibilidad del servicio. Así nació la entrega continua, aceptada como una práctica empresarial de software y una evolución natural de los principios bien establecidos de integración continua. Sin embargo, el despliegue continuo sigue siendo muy raro debido a la complejidad de la gestión y al temor de que los fallos en el despliegue afecten la disponibilidad del sistema. La liberación Canary es probablemente el escenario más clásico en el sistema de entrega continua. Basándonos en esto, podemos descubrir rápidamente servicios no saludables y problemáticos y revertir a la versión anterior sin esfuerzo.

Liberación Canary

La liberación Canary también se conoce como liberación en escala de grises. En términos generales, la nueva versión de la aplicación se lanza y despliega como un "canario" para probar su rendimiento. La versión anterior permanece para operaciones normales en la misma etapa. Durante la actualización, algunos usuarios serán dirigidos a usar la nueva versión, mientras que otros continuarán usando la versión anterior. Bajo la premisa de garantizar la estabilidad general del sistema, permite la detección temprana de errores y ajustes oportunos.

La liberación Canary no lanza directamente la actualización. Dirige lentamente un cierto porcentaje de tráfico a un pequeño número de usuarios. Si no se detectan errores, se promocionará a todos los usuarios y la versión anterior se eliminará gradualmente. Este método reduce el riesgo de introducir nuevas funciones en el entorno de producción.

Este artículo presentará cómo lograr una liberación Canary fluida a través de Apache APISIX Ingress y Flagger, mejorar la eficiencia de la liberación y reducir los riesgos de la misma.

Sobre Apache APISIX Ingress

Apache APISIX Ingress se realiza mediante el Kubernetes Ingress Controller que utiliza Apache APISIX como el proxy del plano de datos. Ofrece cientos de funciones, como balanceo de carga, upstream dinámico, liberación Canary, enrutamiento granular, limitación de tasa, degradación de servicio, corte de servicio, autenticación y observabilidad. Ha sido adoptado por empresas y organizaciones nacionales e internacionales, incluyendo Zoom, Tencent Cloud, Jiakaobaodian, Horizon Robotics, European Copernicus Reference System, entre otros.

Sobre Flagger

Flagger es un proyecto de CNCF (Cloud Native Computing Foundation) y parte de la familia de herramientas GitOps de Flux. Recientemente, la CNCF también anunció la graduación oficial de Flux, lo cual es un buen indicador del éxito y el futuro prometedor de la tecnología cloud-native. Como herramienta de entrega progresiva, Flagger automatiza el proceso de liberación para aplicaciones que se ejecutan en Kubernetes. Reduce el riesgo de introducir una nueva versión de software en producción al trasladar gradualmente el tráfico a la nueva versión mientras mide métricas analíticas y ejecuta pruebas de conformidad.

Después de los esfuerzos continuos de las comunidades de Apache APISIX y Flux, Flagger lanzó recientemente la versión v1.27.0, que soporta liberaciones Canary automatizadas utilizando Apache APISIX Ingress y Flagger.

featured-<Flagger y Apache APISIX Ingress>.jpg

Experimentemos juntos este proceso fluido de liberación Canary.

Entorno

Se requiere un clúster de Kubernetes v1.19 o más reciente, que puedes instalar a través de kind.

Instalación de Componentes

Usa Helm V3 para instalar Apache APISIX y 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

Instala los componentes de Flagger y Prometheus en el namespace apisix.

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

Nota: si necesitas personalizar Prometheus o Prometheus Operator, puedes buscar artículos relacionados para modificarlo.

Inicialización de la Aplicación

Flagger puede aplicarse a despliegues de Kubernetes y otras cargas de trabajo, y también puede combinarse con HPA. Creará una serie de objetos: despliegues de Kubernetes, servicios ClusterIP y ApisixRoute. Estos objetos pueden exponer aplicaciones a clústeres externos para proporcionar servicios y se utilizan para el análisis del proceso de liberación Canary.

Crea un nuevo namespace de prueba:

kubectl create ns test

Crea un nuevo despliegue y HPA. Aquí extraemos el código de muestra oficial de Flagger.

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

Despliega el servicio de prueba de carga de Flagger para generar tráfico durante la liberación Canary para su análisis.

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

Crea el ApisixRoute de Apache APISIX, luego Flagger hará referencia al recurso creado y generará el ApisixRoute de Apache APISIX Ingress en la versión Canary. (Reemplaza app.example.com en el siguiente ejemplo con tu nombre de dominio real)

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

Guárdalo como podinfo-apisixroute.yaml y envíalo al clúster:

kubectl apply -f ./podinfo-apisixroute.yaml

Crea un recurso personalizado Canary de Flagger. (Reemplaza app.example.com en el ejemplo con tu nombre de dominio real)

apiVersion: flagger.app/v1beta1 kind: Canary metadata: name: podinfo namespace: test spec: provider: apisix targetRef: apiVersion: apps/v1 kind: Deployment name: podinfo # Referencia a la ruta de apisix routeRef: apiVersion: apisix.apache.org/v2 kind: ApisixRoute name: podinfo progressDeadlineSeconds: 60 service: port: 80 targetPort: 9898 analysis: interval: 10s # número máximo de fallos para revertir threshold: 10 # porcentaje máximo de tráfico a la versión Canary # (0-100) maxWeight: 50 # tamaño del paso del análisis Canary # (0-100) stepWeight: 10 # usa Prometheus para verificar la información de tráfico de APISIX metrics: - name: request-success-rate # tasa mínima de éxito (respuestas no 5xx) # (0-100) thresholdRange: min: 99 interval: 1m - name: request-duration # P99 es el mayor retraso de solicitud(ms) thresholdRange: max: 500 interval: 30s webhooks: # tráfico automatizado para el análisis Canary, modificado según el escenario real - 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

Guárdalo como podinfo-canary.yaml y envíalo al clúster:

kubectl apply -f ./podinfo-canary.yaml

Flagger generará automáticamente los recursos relacionados:

# Enviado deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo

# Generado automáticamente deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary

featured-<versión 1>.jpg

En este punto, puedes acceder a la aplicación a través del nombre de dominio app.example.com (Reemplaza app.example.com en el ejemplo con tu nombre de dominio real), y verás la versión actual de la aplicación.

Automatización de la Liberación Canary

Flagger implementa un bucle de control que traslada gradualmente el tráfico a los nodos Canary mientras mide métricas clave de rendimiento como la tasa de éxito de solicitudes HTTP, la duración promedio de las solicitudes y la salud de los pods. Según el análisis de las métricas relevantes, libera o detiene el despliegue Canary y publica los resultados del análisis en plataformas relevantes como Slack, MS Teams o Prometheus Alert Manager, entre otros.

Bucle de Control de Flagger

Desencadena una liberación Canary actualizando la versión de la imagen del contenedor

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

Flagger detecta que hay una nueva versión del despliegue y comenzará una ejecución de prueba del análisis de liberación Canary.

kubectl -n test describe canary/podinfo Estado: Peso Canary: 0 Condiciones: Mensaje: Análisis Canary completado con éxito, promoción finalizada. Razón: Exitoso Estado: Verdadero Tipo: Promovido Chequeos Fallidos: 1 Iteraciones: 0 Fase: Exitoso Eventos: Tipo Razón Edad Desde Mensaje ---- ------ ---- ---- ------- Advertencia Sincronizado 2m59s flagger podinfo-primary.test no está listo: esperando que finalice el despliegue: la generación observada del despliegue es menor que la generación deseada Advertencia Sincronizado 2m50s flagger podinfo-primary.test no está listo: esperando que finalice el despliegue: 0 de 1 (umbral de listo 100%) réplicas actualizadas están disponibles Normal Sincronizado 2m40s (x3 sobre 2m59s) flagger ¡todos los proveedores de métricas están disponibles! Normal Sincronizado 2m39s flagger ¡Inicialización completada! podinfo.test Normal Sincronizado 2m20s flagger ¡Nueva revisión detectada! Escalando podinfo.test Advertencia Sincronizado 2m (x2 sobre 2m10s) flagger despliegue Canary podinfo.test no está listo: esperando que finalice el despliegue: 0 de 1 (umbral de listo 100%) réplicas actualizadas están disponibles Normal Sincronizado 110s flagger Iniciando análisis Canary para podinfo.test Normal Sincronizado 109s flagger Avanzando peso Canary de podinfo.test 10 Advertencia Sincronizado 100s flagger Deteniendo avance, no se encontraron valores para la métrica de apisix request-success-rate probablemente podinfo.test no está recibiendo tráfico: ejecución de consulta fallida: no se encontraron valores Normal Sincronizado 90s flagger Avanzando peso Canary de podinfo.test 20 Normal Sincronizado 80s flagger Avanzando peso Canary de podinfo.test 30 Normal Sincronizado 69s flagger Avanzando peso Canary de podinfo.test 40 Normal Sincronizado 59s flagger Avanzando peso Canary de podinfo.test 50 Advertencia Sincronizado 30s (x2 sobre 40s) flagger podinfo-primary.test no está listo: esperando que finalice el despliegue: 1 réplica antigua está pendiente de terminación Normal Sincronizado 9s (x3 sobre 50s) flagger (combinado de eventos similares): ¡Promoción completada! Escalando hacia abajo podinfo.test

Durante el proceso de liberación Canary, recibirás diferentes respuestas cuando accedas a la aplicación a través del nombre de dominio app.example.com (Reemplaza app.example.com con tu nombre de dominio real).

featured-<versión 2>.jpg

Al ver el recurso ApisixRoute podinfo-podinfo-canary de Apache APISIX creado automáticamente por Flagger, encontrarás que los pesos del servicio podinfo-primary y el servicio podinfo-canary cambian junto con el proceso de publicación.

spec: http: - backends: - serviceName: podinfo-primary servicePort: 80 # Ajustado automáticamente por Flagger weight: 80 - serviceName: podinfo-canary servicePort: 80 # Ajustado automáticamente por Flagger weight: 20

Verás la última versión estable cuando la liberación final esté completa.

featured-<versión 3>.jpg

Nota: Flagger volverá a ejecutar el análisis Canary si cambias el despliegue nuevamente durante la liberación Canary.

Puedes observar todas las liberaciones Canary con este comando:

watch kubectl get canaries --all-namespaces NAMESPACE NOMBRE ESTADO PESO ÚLTIMATRANSICIÓNTIEMPO test podinfo-2 En Progreso 10 2022-11-23T05:00:54Z test podinfo Exitoso 0 2022-11-23T06:00:54Z

Reversión

Durante el análisis de la liberación Canary, puedes probar Flagger para suspender la liberación Canary y revertir a la versión anterior generando un HTTP 500 Bad Request.

Desencadena otra liberación Canary:

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

Ingresa al contenedor de prueba de carga

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

Genera un error HTTP 500:

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

Simula un retraso del servidor:

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

Cuando el número de fallos detectados alcanza el umbral del análisis Canary, el tráfico se redirige automáticamente al nodo maestro, el nodo Canary se reduce a cero y el proceso de liberación Canary se marca como fallido.

kubectl -n apisix logs deploy/flagger -f | jq .msg "¡Nueva revisión detectada! Escalando podinfo.test" "despliegue Canary podinfo.test no está listo: esperando que finalice el despliegue: 0 de 1 (umbral de listo 100%) réplicas actualizadas están disponibles" "Iniciando análisis Canary para podinfo.test" "Avanzando peso Canary de podinfo.test 10" "Deteniendo avance de podinfo.test tasa de éxito 0.00% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 26.76% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 34.19% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 37.32% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 39.04% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 40.13% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 48.28% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 50.35% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 56.92% < 99%" "Deteniendo avance de podinfo.test tasa de éxito 67.70% < 99%" "¡Reversión de podinfo.test umbral de chequeos fallidos alcanzado 10" "¡Canary fallido! Escalando hacia abajo podinfo.test"

Personalización de Métricas para el Análisis Canary

El análisis Canary puede extenderse consultando métricas de Prometheus. Personalizamos según los escenarios comerciales reales. Crea una plantilla de métrica y envíala al clúster.

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 # Modifica el análisis en la liberación Canary y agrega la plantilla de indicador creada anteriormente. analysis: metrics: - name: "404s percentage" templateRef: name: not-found-percentage thresholdRange: max: 5 interval: 1m

La configuración anterior valida el Canary verificando si el QPS (Consultas por segundo) de solicitudes HTTP 404 es mayor al 5% del tráfico total. La liberación Canary falla si las solicitudes HTTP 404 superan el umbral del 5%.

Resumen

El proceso anterior puede extenderse con más verificaciones de métricas personalizadas, Webhooks, aprobaciones manuales y notificaciones en Slack o MS Teams.

Se logra una liberación Canary muy fluida a través de la integración de Apache APISIX y Flagger, lo que mejora la eficiencia de la liberación y reduce los riesgos de la misma. En el futuro, las dos comunidades cooperarán más estrechamente para realizar más capacidades de publicación como Blue/Green Mirroring y A/B Testing.

Tags: