CultivaSaaS — DevOps Dashboard
GitHub Actions Kubernetes Terraform / AWS
Generado por CULTIVA IA · devops-senior-cicd-kubernetes · 2026-06-12
Proyecto CultivaSaaS API Node.js + React · eu-west-1
Imagen desplegada ghcr.io/cultiva-saas/api:v2.4.1 Blue slot · 3 réplicas activas
Estrategia Blue / Green Health gate en /api/health
Estado pipeline ✓ Passed build → test → security → deploy
🔄 Pipeline CI/CD — GitHub Actions ✓ main branch
Commit: a7f3e2c  ·  Branch: main  ·  Duración total: 4m 23s
🏗️
Build
1m 05s
✓ passed
🧪
Test
1m 48s
✓ 142/142
🔒
Security
0m 52s
✓ 0 CRITICAL
🚀
Deploy
0m 38s
✓ EKS prod
.github/workflows/ci.yml YAML
# Generado por pipeline_generator.py — CultivaSaaS name: CI/CD Pipeline on: push: branches: [main, develop] pull_request: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci && npm run build test: needs: [build] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test -- --coverage security: needs: [test] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Trivy filesystem scan uses: aquasecurity/trivy-action@master with: scan-type: 'fs' severity: 'CRITICAL,HIGH' exit-code: '1' deploy: needs: [security] if: github.ref == 'refs/heads/main' steps: - name: Build and push image uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }} - name: Deploy blue slot to EKS production run: kubectl apply -f deploy/production/deployment-blue.yaml
Kubernetes — Blue/Green Deployment · namespace: production
Diagrama de tráfico actual — slot blue activo recibiendo 100% del tráfico
Load Balancer
api-svc
port 80 → 3000
100% tráfico
BLUE — ACTIVO
LIVE
ghcr.io/cultiva-saas/api:v2.4.1
api-blue-7d4f9-xk2p1 api-blue-7d4f9-mn3q2 api-blue-7d4f9-vl7r3
100%
GREEN — STANDBY
anterior
ghcr.io/cultiva-saas/api:v2.3.8
api-green-5c2d1-aa1b2 api-green-5c2d1-bb3c4 api-green-5c2d1-cc5d6
0%
deploy/production/deployment-blue.yaml K8s
apiVersion: apps/v1 kind: Deployment metadata: name: api-blue namespace: production labels: app: api slot: blue spec: replicas: 3 selector: matchLabels: app: api slot: blue template: spec: containers: - name: app image: ghcr.io/cultiva-saas/api:v2.4.1 readinessProbe: # health gate httpGet: path: /api/health port: 3000 initialDelaySeconds: 10 periodSeconds: 5 resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "1000m" memory: "1Gi"
deploy/production/service.yaml Service
apiVersion: v1 kind: Service metadata: name: api-svc namespace: production spec: selector: app: api slot: blue # ← cambiar a green # para el switch ports: - port: 80 targetPort: 3000 # Traffic switch command: # kubectl patch service api-svc \ # -n production \ # -p '{"spec":{"selector": # {"app":"api","slot":"blue"}}}'
🏗️ Terraform — Módulo AWS ECS Service
infra/modules/ecs-service/main.tf HCL
resource "aws_ecs_task_definition" "app" { family = var.service_name requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" cpu = var.cpu memory = var.memory container_definitions = jsonencode([{ name = var.service_name image = var.container_image essential = true portMappings = [{ containerPort = var.container_port protocol = "tcp" }] logConfiguration = { logDriver = "awslogs" options = { awslogs-group = "/ecs/${var.service_name}" awslogs-region = var.aws_region } } }]) } resource "aws_ecs_service" "app" { name = var.service_name cluster = var.cluster_id task_definition = aws_ecs_task_definition.app.arn desired_count = var.desired_count launch_type = "FARGATE" network_configuration { subnets = var.private_subnet_ids security_groups = var.security_group_ids assign_public_ip = false } }
infra/modules/ecs-service/variables.tf vars
variable "service_name" { description = "Name of the ECS service" type = string } variable "container_image" { description = "Container image (repo:tag)" type = string # ghcr.io/cultiva-saas/api:v2.4.1 } variable "cpu" { description = "Fargate task CPU units" type = number default = 512 # production } variable "memory" { description = "Fargate task memory (MiB)" type = number default = 1024 # production } variable "desired_count" { description = "Desired task count" type = number default = 3 } variable "env_vars" { description = "Env vars for container" type = map(string) default = { NODE_ENV = "production" PORT = "3000" LOG_LEVEL = "info" } }
📋 Runbook — Deploy Blue/Green v2.4.1 → Production
Generado por deployment_manager.py deploy --env=production --image=ghcr.io/cultiva-saas/api:v2.4.1 --strategy=blue-green
1
Aplicar manifiesto blue
Despliega los pods del slot blue sin recibir tráfico todavía
kubectl apply -f deploy/production/deployment-blue.yaml
2
Esperar rollout + health gate
Los 3 pods deben pasar el readinessProbe en /api/health:3000 antes de continuar
kubectl rollout status deployment/api-blue -n production # Espera hasta que todos los pods estén Ready
3
Verificación manual (opcional)
Probar el slot blue via port-forward antes de redirigir tráfico
kubectl port-forward deployment/api-blue 3001:3000 -n production curl -sf http://localhost:3001/api/health && echo "OK"
4
Switch de tráfico al slot blue
Redirige el 100% del tráfico de api-svc al slot blue. Accion irreversible sin rollback.
kubectl patch service api-svc -n production \ -p '{"spec":{"selector":{"app":"api","slot":"blue"}}}'
5
Monitorizar post-deploy
Observar errores durante 10 minutos. Si hay problemas, ejecutar rollback inmediato.
kubectl get pods -n production -l app=api,slot=blue watch kubectl top pods -n production -l app=api
⚠️ Rollback inmediato — si algo falla
Rollback a v2.3.8 (slot green)
# Opción 1 — via deployment_manager.py python3 scripts/deployment_manager.py rollback --env=production --to-version=v2.3.8 # Opción 2 — via kubectl (switch de vuelta a green) kubectl patch service api-svc -n production \ -p '{"spec":{"selector":{"app":"api","slot":"green"}}}' # Verificar rollback curl -sf https://api.cultivasaas.io/api/health || echo "ROLLBACK FAILED — escalar"
📊 Infraestructura — estado tras el deploy
Pods en producción
3/3
slot blue · namespace production
✓ Todos Running
Latencia p95
42ms
/api/v1/campaigns
↓ 18ms vs v2.3.8
Error rate
0.02%
últimos 10 minutos
↓ 0.3% vs baseline
CPU utilization
34%
avg · 3 pods Fargate
→ dentro del rango normal
Memory usage
412Mi
avg · limit 1Gi
40% de capacidad
Terraform state
✓ Clean
4 resources · 0 drift
Last apply: hace 12m