tutoriales.com

Despliegues Canario con Istio y Kubernetes: Controlando el Riesgo en CI/CD

Este tutorial te guiará a través de la implementación de despliegues canario utilizando Istio en un clúster de Kubernetes. Aprenderás a configurar Istio para dirigir el tráfico de forma gradual a nuevas versiones de tu aplicación, minimizando el impacto de posibles errores y asegurando una transición suave en tus ciclos de CI/CD.

Intermedio20 min de lectura12 views
Reportar error

Los despliegues canario son una estrategia de lanzamiento de software que permite a los equipos introducir nuevas versiones de una aplicación a un pequeño subconjunto de usuarios antes de un despliegue completo. Esta técnica es fundamental en el mundo de CI/CD, ya que reduce drásticamente el riesgo asociado con los cambios en producción, permitiendo detectar problemas tempranamente y revertir el cambio rápidamente si es necesario.

En este tutorial, exploraremos cómo implementar despliegues canario utilizando Istio, una malla de servicios (Service Mesh) de código abierto que proporciona un control granular sobre el tráfico, la seguridad y la observabilidad dentro de un clúster de Kubernetes. Istio simplifica la gestión de despliegues canario al desacoplar el lanzamiento de nuevas versiones de la dirección del tráfico, lo que nos permite redirigir un porcentaje del tráfico a la nueva versión y monitorear su comportamiento antes de una distribución completa.

🎯 ¿Por qué Despliegues Canario? La Ventaja del Riesgo Reducido

Los despliegues canario ofrecen una serie de ventajas clave que los hacen indispensables en cualquier estrategia de CI/CD robusta:

  • Reducción del Riesgo: Al exponer la nueva versión a solo una fracción de los usuarios, el impacto de un error grave se minimiza significativamente.
  • Detección Temprana de Problemas: Permite identificar fallos, regresiones o problemas de rendimiento antes de que afecten a toda la base de usuarios.
  • Reversión Rápida: Si se detecta un problema, es fácil revertir el tráfico a la versión estable anterior sin impacto en la mayoría de los usuarios.
  • Confianza en los Despliegues: Aumenta la confianza del equipo al saber que los nuevos lanzamientos son monitoreados de cerca y pueden ser controlados con precisión.
  • Recopilación de Telemetría: Permite recopilar métricas y logs de la nueva versión en un entorno de producción controlado, validando su comportamiento real.
🔥 Importante: Los despliegues canario son una inversión en la estabilidad y confiabilidad de tus servicios. Aunque requieren una configuración inicial, los beneficios a largo plazo superan con creces el esfuerzo.

🛠️ Herramientas Necesarias

Para seguir este tutorial, necesitarás lo siguiente:

  • Un clúster de Kubernetes (v1.16+ recomendado). Puede ser Minikube, Kind, un clúster en la nube (GKE, AKS, EKS) o cualquier otro.
  • kubectl configurado para interactuar con tu clúster.
  • istioctl instalado para gestionar Istio. Si no lo tienes, puedes descargarlo desde la página de lanzamientos de Istio.
  • helm (opcional, pero útil para instalar Istio).

⚙️ Instalación y Configuración de Istio en Kubernetes

Antes de poder implementar despliegues canario, necesitamos instalar Istio en nuestro clúster de Kubernetes. Hay varias formas de hacerlo, pero usaremos istioctl para una instalación básica.

Descarga y Configuración de istioctl

Si aún no lo has hecho, descarga la versión más reciente de Istio:

curl -L https://istio.io/downloadIstio | sh -
cd istio-<VERSION>
export PATH=$PWD/bin:$PATH

Verifica que istioctl funcione:

istioctl version

Instalación de Istio

Instalaremos el perfil demo de Istio, que es adecuado para propósitos de demostración y desarrollo. Este perfil incluye todos los componentes principales de Istio.

istioctl install --set profile=demo -y

La instalación puede tardar unos minutos. Una vez completada, verifica que todos los pods de Istio estén en ejecución en el namespace istio-system:

kubectl get pods -n istio-system

Deberías ver varios pods, incluyendo istiod-, istio-ingressgateway-, etc., todos en estado Running.

💡 Consejo: Para entornos de producción, considera perfiles como `default` o `minimal`, o personaliza la instalación con un archivo `IstioOperator` para un control más fino sobre los componentes.

🧑‍💻 Preparando Nuestra Aplicación de Ejemplo

Para demostrar el despliegue canario, usaremos una aplicación simple de 'Hola Mundo'. Crearemos dos versiones de esta aplicación: v1 y v2.

Namespace con Inyección de Sidecar

Istio funciona inyectando un sidecar proxy (Envoy) en los pods de tu aplicación. Para que esto ocurra automáticamente, debemos etiquetar el namespace donde desplegaremos nuestra aplicación.

kubectl create namespace canary-app
kubectl label namespace canary-app istio-injection=enabled

Despliegue de la Versión 1 (v1)

Crearemos una Deployment y un Service para la versión 1 de nuestra aplicación. El Deployment tendrá dos réplicas.

# app-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world-v1
  namespace: canary-app
  labels:
    app: hello-world
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-world
      version: v1
  template:
    metadata:
      labels:
        app: hello-world
        version: v1
    spec:
      containers:
      - name: hello-world
        image: nginxdemos/hello:plain-text
        ports:
        - containerPort: 80
        env:
        - name: MESSAGE
          value: "Hello from v1!"
---
apiVersion: v1
kind: Service
metadata:
  name: hello-world
  namespace: canary-app
  labels:
    app: hello-world
spec:
  selector:
    app: hello-world
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Aplica este manifiesto:

kubectl apply -f app-v1.yaml

Verifica que los pods estén ejecutándose:

k get pods -n canary-app -l app=hello-world

Creando un Gateway de Istio

Para exponer nuestra aplicación al exterior del clúster, necesitamos un Gateway de Istio. Este Gateway define los puertos y protocolos que la malla de servicios acepta para el tráfico entrante.

# gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: hello-world-gateway
  namespace: canary-app
spec:
  selector:
    istio: ingressgateway # Usa el ingressgateway predeterminado de Istio
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"

Aplica este manifiesto:

kubectl apply -f gateway.yaml

Creando un VirtualService de Istio (Inicial)

Un VirtualService define cómo se enruta el tráfico a los servicios. Inicialmente, todo el tráfico irá a v1.

# virtualservice-v1.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: hello-world-vs
  namespace: canary-app
spec:
  hosts:
  - "*"
  gateways:
  - hello-world-gateway
  http:
  - route:
    - destination:
        host: hello-world
        subset: v1 # Apunta al subconjunto v1
      weight: 100
⚠️ Advertencia: El `VirtualService` apunta a un `subset`. Necesitamos definir estos `subsets` usando un `DestinationRule`.

Creando un DestinationRule

Un DestinationRule define políticas para el tráfico de un servicio y, crucialmente, permite definir subsets (subconjuntos) de pods basados en etiquetas. Esto es fundamental para los despliegues canario.

# destinationrule.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: hello-world
  namespace: canary-app
spec:
  host: hello-world
  subsets:
  - name: v1
    labels:
      version: v1

Aplica estos manifiestos:

kubectl apply -f virtualservice-v1.yaml
kubectl apply -f destinationrule.yaml

Accediendo a la Aplicación

Necesitamos obtener la IP externa y el puerto del istio-ingressgateway para acceder a la aplicación.

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

Ahora, podemos probar la aplicación:

curl -s $GATEWAY_URL/hello

Deberías ver Hello from v1! repetidamente. Si el INGRESS_HOST no es una IP externa (ej. en Minikube), puedes usar kubectl port-forward o la dirección interna del gateway.

🚀 Implementando el Despliegue Canario: Introduciendo v2

Ahora que v1 está funcionando, vamos a introducir v2 y configurarla para recibir un pequeño porcentaje de tráfico.

Despliegue de la Versión 2 (v2)

Primero, creamos el Deployment para v2. Notarás que el Service hello-world no necesita ser modificado, ya que Istio usará los labels de los pods para dirigir el tráfico.

# app-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world-v2
  namespace: canary-app
  labels:
    app: hello-world
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world
      version: v2
  template:
    metadata:
      labels:
        app: hello-world
        version: v2
    spec:
      containers:
      - name: hello-world
        image: nginxdemos/hello:plain-text
        ports:
        - containerPort: 80
        env:
        - name: MESSAGE
          value: "Hello from v2!"

Aplica este manifiesto:

kubectl apply -f app-v2.yaml

Verifica que los pods de v2 estén en ejecución:

k get pods -n canary-app -l app=hello-world

Actualizando el DestinationRule con v2

Ahora debemos añadir v2 como un nuevo subset en nuestro DestinationRule.

# destinationrule-updated.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: hello-world
  namespace: canary-app
spec:
  host: hello-world
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2 # Nuevo subset
    labels:
      version: v2

Aplica este manifiesto:

kubectl apply -f destinationrule-updated.yaml

⚖️ Redirigiendo Tráfico con el VirtualService

Aquí es donde la magia del despliegue canario ocurre. Modificaremos el VirtualService para dirigir un pequeño porcentaje del tráfico a v2.

1. Tráfico 90% v1 / 10% v2

Vamos a enviar el 10% del tráfico a v2 y el 90% restante a v1.

# virtualservice-canary-10.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: hello-world-vs
  namespace: canary-app
spec:
  hosts:
  - "*"
  gateways:
  - hello-world-gateway
  http:
  - route:
    - destination:
        host: hello-world
        subset: v1
      weight: 90 # 90% del tráfico a v1
    - destination:
        host: hello-world
        subset: v2
      weight: 10 # 10% del tráfico a v2

Aplica este manifiesto:

kubectl apply -f virtualservice-canary-10.yaml

Ahora, realiza múltiples solicitudes a la aplicación. Deberías ver una mezcla de Hello from v1! y Hello from v2!, con v2 apareciendo aproximadamente una de cada diez veces.

for i in $(seq 1 20); do curl -s $GATEWAY_URL/hello; done
💡 Consejo: Monitorea tus métricas clave (errores, latencia, uso de CPU/memoria) en v2 durante esta fase. Herramientas como Prometheus y Grafana, a menudo integradas con Istio, son ideales para esto.

2. Tráfico 50% v1 / 50% v2

Si v2 se comporta bien con el 10% del tráfico, podemos aumentar gradualmente su exposición. Ahora probemos con 50% para cada versión.

# virtualservice-canary-50.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: hello-world-vs
  namespace: canary-app
spec:
  hosts:
  - "*"
  gateways:
  - hello-world-gateway
  http:
  - route:
    - destination:
        host: hello-world
        subset: v1
      weight: 50 # 50% del tráfico a v1
    - destination:
        host: hello-world
        subset: v2
      weight: 50 # 50% del tráfico a v2

Aplica y prueba de nuevo:

kubectl apply -f virtualservice-canary-50.yaml
for i in $(seq 1 20); do curl -s $GATEWAY_URL/hello; done

Deberías ver una distribución más equilibrada entre v1 y v2.

3. Tráfico 0% v1 / 100% v2 (Despliegue Completo)

Una vez que estés seguro de que v2 es estable y funciona correctamente, puedes redirigir todo el tráfico a v2.

# virtualservice-canary-100.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: hello-world-vs
  namespace: canary-app
spec:
  hosts:
  - "*"
  gateways:
  - hello-world-gateway
  http:
  - route:
    - destination:
        host: hello-world
        subset: v2
      weight: 100 # 100% del tráfico a v2

Aplica y prueba:

kubectl apply -f virtualservice-canary-100.yaml
for i in $(seq 1 10); do curl -s $GATEWAY_URL/hello; done

Ahora, todas las respuestas deberían ser Hello from v2!.

📌 Nota: Este proceso de escalado de tráfico puede ser automatizado en un pipeline CI/CD utilizando herramientas como Argo Rollouts o Flagger, que se integran con Istio para orquestar los despliegues canario de forma declarativa.
1. Desplegar v1 2. Istio Gateway/VirtualService 100% a v1 3. Desplegar v2 (Canary) 4. Istio DestinationRule: Subsets v1 y v2 5. Istio VirtualService 90% a v1, 10% a v2 6. Monitorear y aumentar tráfico (ej. 50/50) 7. Istio VirtualService 100% a v2 8. Eliminar v1 PREPARACIÓN CONFIGURACIÓN CANARY TEST FINALIZACIÓN

↩️ Reversión de Despliegues Canario

Uno de los mayores beneficios de los despliegues canario es la facilidad de reversión. Si detectas un problema en v2 en cualquier punto durante el proceso de escalado de tráfico, simplemente puedes volver a aplicar un VirtualService que dirija todo el tráfico a v1.

Por ejemplo, para revertir al 100% v1:

kubectl apply -f virtualservice-v1.yaml

Esto redirigirá instantáneamente todo el tráfico de vuelta a la versión estable, minimizando el impacto en los usuarios. Una vez revertido, puedes investigar el problema en v2 sin presionar.

✨ Opciones Avanzadas de Despliegue Canario con Istio

Istio ofrece una gran flexibilidad para controlar el tráfico. Más allá de la ponderación simple, puedes realizar enrutamiento basado en:

  • Headers HTTP: Dirigir usuarios con un header específico (ej. x-user-type: beta-tester) a v2.
  • Cookies: Enviar usuarios con una cookie específica a v2.
  • URLs/Paths: Enrutar solo ciertas rutas a la nueva versión.
  • Direcciones IP: Dirigir tráfico desde rangos IP específicos.

Ejemplo: Enrutamiento Basado en Headers

Imagina que solo quieres que tus testers internos vean v2. Puedes modificar el VirtualService para que el 100% del tráfico vaya a v1 por defecto, pero si un usuario envía el header x-canary-test: true, entonces se redirige a v2.

# virtualservice-header-based.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: hello-world-vs
  namespace: canary-app
spec:
  hosts:
  - "*"
  gateways:
  - hello-world-gateway
  http:
  - match:
    - headers:
        x-canary-test:
          exact: "true"
    route:
    - destination:
        host: hello-world
        subset: v2
      weight: 100
  - route:
    - destination:
        host: hello-world
        subset: v1
      weight: 100 # Por defecto, todo el tráfico a v1

Aplica esto y pruébalo:

kubectl apply -f virtualservice-header-based.yaml

# Tráfico normal (v1)
curl -s $GATEWAY_URL/hello

# Tráfico de tester (v2)
curl -s -H "x-canary-test: true" $GATEWAY_URL/hello

Este método es excelente para pruebas internas o para permitir que un grupo específico de usuarios acceda a características beta.

📊 Monitoreo y Observabilidad

Un despliegue canario no está completo sin un monitoreo robusto. Istio se integra con herramientas de observabilidad como Prometheus (para métricas), Grafana (para dashboards) y Jaeger (para trazas distribuidas). Estas herramientas te permiten:

  • Verificar el rendimiento de v2 en comparación con v1.
  • Detectar aumentos en tasas de error.
  • Identificar latencias en la nueva versión.
  • Visualizar el flujo de tráfico y la distribución entre versiones.

Si instalaste Istio con el perfil demo, Prometheus, Grafana y Kiali ya deberían estar instalados. Puedes acceder a ellos para monitorear el tráfico a tus servicios. Por ejemplo, para abrir la UI de Kiali:

istioctl dashboard kiali -n istio-system

Kiali te proporciona una vista de malla de servicios, mostrando el tráfico entre v1 y v2 y sus métricas asociadas. Es una herramienta invaluable para visualizar el progreso de tu despliegue canario.

♻️ Limpieza de Recursos

Una vez que hayas terminado de experimentar, puedes limpiar los recursos creados.

  1. Elimina la aplicación de ejemplo y los recursos de Istio en el namespace canary-app:
kubectl delete -f app-v1.yaml
kubectl delete -f app-v2.yaml
kubectl delete -f gateway.yaml
kubectl delete -f virtualservice-v1.yaml # o el último VirtualService que aplicaste
kubectl delete -f destinationrule.yaml
kubectl delete namespace canary-app
  1. Desinstala Istio del clúster:
istioctl uninstall --purge -y
kubectl get crd | grep 'istio.io' | awk '{print $1}' | xargs kubectl delete crd

Conclusión

Los despliegues canario, potenciados por Istio y Kubernetes, representan una estrategia moderna y eficaz para gestionar la introducción de cambios en producción con un riesgo mínimo. Al permitirte dirigir el tráfico de forma gradual y monitorear el comportamiento de las nuevas versiones en tiempo real, Istio te ofrece el control y la confianza necesarios para mantener la agilidad de tu CI/CD sin comprometer la estabilidad de tus servicios.

Este tutorial te ha proporcionado los pasos fundamentales para configurar e implementar un despliegue canario básico. Recuerda que la automatización de estos pasos en tu pipeline CI/CD con herramientas como Argo Rollouts o Flagger es el siguiente paso lógico para una gestión de despliegues verdaderamente madura y eficiente.

FAQs sobre Despliegues Canario e Istio

¿Cuál es la diferencia entre un despliegue Blue/Green y un Canario?

Los despliegues Blue/Green implican tener dos entornos idénticos (Blue y Green) y conmutar el tráfico de uno al otro de una vez. Todo el tráfico va a la versión nueva o a la antigua. Los despliegues Canario introducen la nueva versión a un pequeño porcentaje del tráfico, escalando gradualmente.

¿Puedo usar Istio para AB Testing?

¡Absolutamente! La funcionalidad de enrutamiento basado en headers, cookies o pesos es perfecta para implementar estrategias de AB Testing, donde diferentes grupos de usuarios ven distintas versiones de tu aplicación para probar hipótesis.

¿Es Istio demasiado complejo para mi caso de uso?

Istio es una herramienta potente y puede tener una curva de aprendizaje. Para casos de uso más simples donde solo necesitas un despliegue canario básico, soluciones más ligeras o incluso un Ingress Controller como Nginx con configuración avanzada pueden ser suficientes. Sin embargo, para entornos con muchos microservicios o requisitos de seguridad y observabilidad complejos, Istio brilla.

¿Cómo se integra esto en mi pipeline CI/CD?

La idea es que tu pipeline CI/CD genere la nueva imagen de contenedor (v2), actualice el Deployment y luego use kubectl apply para aplicar los diferentes manifiestos de VirtualService que controlan la distribución de tráfico (10%, 50%, 100%). Herramientas como Argo Rollouts automatizan esta orquestación de VirtualServices basada en métricas y criterios de éxito/fallo.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!