Lanzamiento Canary Suave Usando APISIX Ingress Controller con Flagger
Hengliang Tan
January 19, 2023
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.
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
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.
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).
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.
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.