Cómo hacer un despliegue canario en Kubernetes con GitHub Actions: paso a paso
Este tutorial muestra cómo realizar un despliegue canario en Kubernetes con GitHub Actions para implementar nuevas versiones de forma gradual y reducir el riesgo. Explico por qué el despliegue canario es útil; a continuación detallo un flujo concreto con manifiestos de Kubernetes, GitHub Actions y verificación simple.
Requisitos previos
- Cuenta en GitHub y repositorio con el código de la aplicación (por ejemplo: imagen Docker pública o registrada).
- Cluster Kubernetes accesible (minikube, kind o cluster en la cloud) con el kubectl configurado.
- Runner de GitHub Actions con permisos para el kubectl (use secrets KUBECONFIG o un token).
- Conocimientos básicos de Kubernetes: Deployment, Service y labels.
Paso 1: Preparar manifiestos de Kubernetes para soporte de canario
Cree un Deployment principal y prepare un Deployment separado para el canario. La idea es tener dos Deployments (app-primary, app-canary) y un Service que balancee por label. Así podemos controlar el tráfico hacia el canario cambiando réplicas o weights en el Ingress/Service.
# deployment-primary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-primary
spec:
replicas: 3
selector:
matchLabels:
app: myapp
role: primary
template:
metadata:
labels:
app: myapp
role: primary
spec:
containers:
- name: myapp
image: myrepo/myapp:stable
ports:
- containerPort: 80
# deployment-canary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
role: canary
template:
metadata:
labels:
app: myapp
role: canary
spec:
containers:
- name: myapp
image: myrepo/myapp:canary
ports:
- containerPort: 80
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-svc
spec:
selector:
app: myapp
ports:
- port: 80
targetPort: 80
type: ClusterIP
Paso 2: Configurar GitHub Actions para crear imagen y hacer deploy canario
Creе un workflow que construya la imagen canary, haga push al registry y aplique los manifiestos al cluster. Use un job que actualice solo el Deployment canary a la nueva tag; así el primary mantiene la versión estable.
# .github/workflows/canary-deploy.yaml
name: Canary Deploy
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push image
uses: docker/build-push-action@v4
with:
push: true
tags: myrepo/myapp:${{ github.sha }}
# configure registry credentials via secrets
- name: Configure kubectl
run: |
echo "$KUBECONFIG" > kubeconfig
export KUBECONFIG=$PWD/kubeconfig
env:
KUBECONFIG: ${{ secrets.KUBECONFIG }}
- name: Update canary deployment image
run: |
kubectl set image deployment/app-canary myapp=myrepo/myapp:${{ github.sha }}
kubectl rollout status deployment/app-canary --timeout=60s
Paso 3: Aumentar gradualmente el tráfico hacia el canario
Hay varias formas de aumentar el tráfico: aumentar las réplicas del canario, usar Ingress/Service con weights (por ejemplo: Istio, Traefik) o manipular selectors. Aquí mostramos la forma simple: aumentar las réplicas del canario y, más tarde, reducir las del primary.
# scale-canary.sh (ejecutar vía GitHub Action o manualmente)
kubectl scale deployment/app-canary --replicas=2
# tras la verificación
kubectl scale deployment/app-primary --replicas=2
# finalmente promover el canario a primary cambiando imágenes y restaurando réplicas
kubectl set image deployment/app-primary myapp=myrepo/myapp:${CANARY_TAG}
kubectl scale deployment/app-canary --replicas=0
kubectl scale deployment/app-primary --replicas=3
Paso 4: Monitorización y rollback automático
Configure health checks liveness/readiness y use un script simple para comprobar métricas (errores, latencia) o el estado de readiness. En el ejemplo abajo, un paso del workflow verifica endpoints y realiza rollback si la tasa de error aumenta.
# ejemplo simplificado de verificación vía curl
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://myapp-svc/health)
if [ "$STATUS" != "200" ]; then
kubectl set image deployment/app-canary myapp=myrepo/myapp:stable
kubectl rollout status deployment/app-canary --timeout=60s
exit 1
fi
Verificar el resultado
Confirme que el canario está ejecutando la nueva imagen y sirviendo tráfico solo a una parte de los usuarios. Use kubectl para inspeccionar:
kubectl get deployments
kubectl get pods -l role=canary -o wide
kubectl describe deployment app-canary
kubectl logs deployment/app-canary --tail=50
Si usa un Ingress o Service con weight, verifique métricas en el controlador de Ingress o en las herramientas de observabilidad (Prometheus/Grafana). Pruebe endpoints y confirme que el rollback funciona simulando fallos.
Conclusión
El despliegue canario en Kubernetes con GitHub Actions permite reducir el riesgo de releases, controlando gradualmente el tráfico. Próximos pasos: integrar Istio/Linkerd para traffic shifting por weight, automatizar métricas con Prometheus y crear gates automáticos en el workflow. Consejo: empiece con réplicas y health checks simples antes de introducir un service mesh — ¿cuál es la mayor preocupación que desea mitigar con canarios?