Automatiza las decisiones de Canary Release en tu clúster de Kubernetes
December 30, 2022
Antecedentes
Hoy en día, los microservicios se han convertido en un patrón de arquitectura de software típico y ampliamente utilizado. Los servicios están débilmente acoplados y colaboran a través de APIs. El patrón de microservicios hace que cada aplicación sea independientemente desplegable y mantenible, por lo que las versiones son más frecuentes. Como todos sabemos, el lanzamiento es riesgoso; nunca se sabe si hay errores en la nueva versión. Es por eso que las personas utilizan estrategias como el lanzamiento canario y el despliegue azul-verde para implementar gradualmente su última versión y reducir el riesgo.
El lanzamiento canario divide el tráfico en dos grupos del servicio objetivo: el grupo estable y el grupo canario. Un API Gateway, como Apache APISIX, expone de manera eficiente y segura la arquitectura de microservicios a las APIs. Está equipado con la función de lanzamiento canario. Normalmente, hay dos formas de decidir cómo dividir el tráfico: la forma basada en peso y la forma basada en expresiones de predicado.
Forma Basada en Peso
Los usuarios deben especificar la proporción de tráfico que llegará al grupo canario. En la imagen anterior, el 95% del tráfico se redirigirá al servicio estable, mientras que el otro 5% se redirigirá al canario.
Forma Basada en Expresiones de Predicado
La forma de expresión de predicado de solicitud indica que solo el tráfico que cumple con las características especificadas llegará al grupo canario. Por ejemplo, solo las solicitudes HTTP con el encabezado de solicitud X-Debug y su valor real llegarán al servicio canario.
Automatización del Lanzamiento Canario
Cuando se opera el API Gateway llamando a la API o al panel de control, habrá un retraso en el ajuste de la proporción de tráfico (para la forma basada en peso) o de los predicados (para la forma basada en expresiones de predicado). Hoy en día, cada vez más usuarios utilizan Kubernetes para orquestar sus microservicios. ¿Pueden las personas iniciar el lanzamiento canario una vez que se crea la nueva versión del servicio? En este artículo, te mostraré cómo usar API7 Cloud para automatizar el lanzamiento canario en tu clúster de Kubernetes.
¿Qué es API7 Cloud?
API7 Cloud es una plataforma SaaS multiubicación y en cualquier nube para desplegar, controlar, visualizar y monitorear APIs a escala. Ejecuta tus APIs en cualquier lugar, pero adminístralas en un solo lugar. API7 Cloud utiliza Apache APISIX como el API Gateway para exponer tus APIs de manera eficiente y segura.
Para usar API7 Cloud, debes desplegar Apache APISIX en tus infraestructuras, como Docker y Kubernetes. Puedes usar Cloud CLI para facilitar el despliegue.
# Configura un token de acceso desde la consola de API7 Cloud.
cloud-cli configure --token {YOUR TOKEN}
# Despliega Apache APISIX (versión 2.15.1) en el espacio de nombres apisix, con solo una réplica.
cloud-cli deploy kubernetes \
--name my-apisix \
--namespace apisix \
--replica-count 1 \
--apisix-image apache/apisix:2.15.1-centos
El lanzamiento canario es una de las funciones integradas de API7 Cloud. Los usuarios pueden configurar las reglas de lanzamiento canario a través de la consola o llamar a la API abierta de API7 Cloud. Nuestro objetivo es automatizar las decisiones de lanzamiento canario, por lo que usaremos la segunda forma.
Escenario
Digamos que en nuestro clúster de Kubernetes hay una aplicación simple de página de error, que siempre devuelve un mensaje de error. Estamos lanzando la versión 2.0 y queremos usar la estrategia de lanzamiento canario para reducir el riesgo del lanzamiento. Además, también queremos automatizar todo el proceso. Por lo tanto, creamos un controlador de lanzamiento canario, que monitorea los cambios en los recursos de servicio de Kubernetes, luego crea/modifica los lanzamientos canarios en API7 Cloud a través del SDK de Go de API7 Cloud. Solo usamos la forma basada en peso para dividir el tráfico. Todos los componentes, incluido el API Gateway Apache APISIX, se desplegarán en Kubernetes, por lo que el diagrama será así:
El controlador de lanzamiento canario observa los cambios en los servicios y reacciona según algunas anotaciones, específicamente:
- Si el servicio contiene la anotación api7.cloud/published-service, el controlador de lanzamiento canario intentará crear una Aplicación en API7 Cloud.
- Si el servicio tiene la anotación api7.cloud/published-canary-service, el controlador de lanzamiento canario intentará configurar la regla de lanzamiento canario en API7 Cloud y la anotación api7.cloud/published-service-canary-percentage decidirá el porcentaje.
Ten en cuenta que este controlador no es autónomo (no elimina la Aplicación si se elimina el servicio), pero es suficiente para mostrar el proceso automatizado de lanzamiento canario.
¡Aquí Vamos!
Comencemos desplegando Apache APISIX y el controlador de lanzamiento canario. Como se mencionó anteriormente, usamos Cloud CLI para desplegar Apache APISIX. También tenemos dos archivos YAML (error-page/manifest-v1.yaml y controller/manifest.yaml) para desplegar la aplicación de página de error y el controlador de lanzamiento canario.
- Prepara un clúster de Kubernetes disponible si deseas ejecutar los siguientes comandos.
- El controlador de lanzamiento canario necesita un token de acceso para llamar a la API de API7 Cloud. Obtenemos un token según este documento y almacenamos el token en un secreto de K8s.
kubectl create namespace canary-release-demo
# Despliega la versión v1 de la página de error.
kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/error-page/manifest-v1.yaml -n canary-release-demo
# Crea un secreto de K8s para guardar el token de acceso de API7 Cloud.
kubectl create secret generic api7-cloud --namespace canary-release-demo --from-literal token={Tu Token de Acceso}
# Despliega el controlador de lanzamiento canario.
kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/controller/manifest.yaml -n canary-release-demo
# Verifica si todas las cargas de trabajo están normales.
kubectl get all -n canary-release-demo
Verifica el proxy
Vamos a publicar este servicio anotándolo.
kubectl annotate service -n canary-release-demo error-page-v1 "api7.cloud/published-service=error-page"
El controlador de lanzamiento canario observará este cambio y creará una Aplicación en API7 Cloud. Ahora accedamos a Apache APISIX para ver si el proxy funciona correctamente.
kubectl port-forward -n canary-release-demo service/apisix-gateway 10080:80
curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
Si todo está bien, verás {"error": "injected by error_page service", "version": "v1"}
.
Actualmente, el controlador de lanzamiento canario crea una API "match-everything" en la Aplicación, y el Host es el mismo que el nombre de la Aplicación (error-page).
Lanzamiento de V2
Queremos lanzar la versión 2 de la aplicación de página de error. Primero, desplegamos la versión 2 aplicando el archivo manifest-v2.yaml. Anotamos el servicio error-page-v2 con las anotaciones de lanzamiento canario.
kubectl apply -f https://raw.githubusercontent.com/tokers/canary-release-automation-demo/main/error-page/manifest-v2.yaml -n canary-release-demo
# Indica al controlador de lanzamiento canario que habilitamos el lanzamiento canario para error-page-v2, y el porcentaje es del 10%.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-canary-service=true" "api7.cloud/published-service-canary-percentage=10"
# Inicia el canario.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service=error-page"
Ahora enviemos 100
solicitudes a Apache APISIX nuevamente y veamos si algunas solicitudes fueron redirigidas al servicio canario error-page-v2.
kubectl port-forward -n canary-release-demo service/apisix-gateway 10080:80
for ((i=0; i<100; i++)); do
curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done
Solo alrededor del 10% de las solicitudes llegarán a error-page-v2 (no exactamente el 10% debido a la estrategia interna que Apache APISIX utiliza para seleccionar el backend) si todo está bien.
Reversión
Descubrimos que la versión 2 es inestable y queremos revertirla. Antes de hacerlo, detendremos el canario, por lo que cambiamos el porcentaje a 0. Luego enviamos solicitudes a Apache APISIX nuevamente.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service-canary-percentage=0" --overwrite
for ((i=0; i<100; i++)); do
curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done
Verás que todas las solicitudes ahora van a error-page-v1.
Lanzamiento
Después de un tiempo, creemos que la versión 2 es lo suficientemente estable y queremos que todas las solicitudes lleguen a la versión 2. Luego podemos retirar la aplicación de página de error versión 1. Así que cambiamos el porcentaje al 100%.
kubectl annotate service -n canary-release-demo error-page-v2 "api7.cloud/published-service-canary-percentage=100" --overwrite
for ((i=0; i<100; i++)); do
curl http://127.0.0.1:10080/api/error_page -H 'Host: error-page' -s
done
Ahora todas las solicitudes son redirigidas a error-page-v2. Y error-page-v1 puede retirarse de manera segura.
Resumen
El lanzamiento canario es una herramienta efectiva para el lanzamiento. Sin embargo, ajustar la estrategia de lanzamiento canario puede ser lento. Este artículo muestra cómo operar los lanzamientos canarios de manera declarativa y automatizar el lanzamiento canario hasta cierto punto. Algunas personas podrían buscar el lanzamiento canario completamente automático con la ayuda de componentes de GitOps. Por ejemplo, al usar Argo Rollouts, uno puede promover o revertir automáticamente los servicios. Argo Rollouts consulta las métricas del servicio y se integra con los controladores de ingreso para cambiar sus CRDs. Finalmente, el API Gateway redirigirá las solicitudes en las proporciones correctas a la versión canaria.
Referencia
Código fuente para la página de error y el controlador de lanzamiento canario: https://github.com/tokers/canary-release-automation-demo.