CD (Entrega Continua) — Parte 3: Deploy a Dev y Smoke Tests


📚 Serie: CI/CD y la IA: De la teoría a la práctica

Esta parte cubre el primer despliegue real del ciclo: el deploy al entorno de desarrollo y la validación inmediata mediante smoke tests para confirmar que el servicio está vivo y funciona.

Partes de este bloque:


Deploy a Dev

Es un despliegue controlado del artefacto o imagen en un entorno de desarrollo que replica la configuración de producción en lo esencial. Incluye provisión con IaC (Infrastructure as Code), gestión de secrets, activación de observabilidad y ejecución de smoke tests, para dar feedback rápido a desarrolladores antes de promover a entornos superiores.

Este paso se ejecuta después del merge a la rama destino (por ejemplo develop o release/x.y), o bien como pipeline independiente si se usa promoción de artefactos.

Se recomienda promover la misma imagen firmada entre entornos y usar entornos efímeros para PRs.

Dos modelos de pipeline

Se recomienda usar pipeline por rama para entornos de integración y preproducción (por su flexibilidad), y promoción de artefactos para producción (por la trazabilidad y reproducibilidad):

Pipeline por rama destino (recomendado en entornos corporativos):

  • PR → CI en rama feature → merge a develop → CD de develop despliega a Dev.
  • Merge a release/x.y → CD de release despliega a Preprod.
  • Merge a main → CD de main despliega a Producción.
  • Ventaja: separación clara de responsabilidades y políticas por rama.

Pipeline único con promoción de artefactos (alternativa):

  • Un único pipeline construye el artefacto y lo publica; luego se promueve la misma imagen entre entornos (Dev → Staging → Prod).
  • Ventaja: garantiza que exactamente la misma imagen pasa por todos los entornos.

¿Cuándo usar cada uno?

  • Trazabilidad estricta y reproducibilidad en producción: construir una vez y promover artefactos.
  • Velocidad y flexibilidad en integración: pipelines por rama para Dev/Staging.
  • Híbrido recomendado: pipeline por rama para Dev/Staging + promoción del artefacto firmado para Producción.

Pasos de esta etapa

  1. Seleccionar artefacto: usar la imagen construida y firmada; preferible promover la imagen publicada en el registry en lugar de reconstruirla.
  2. Provisionar entorno: namespace/cluster efímero o persistente para Dev; aplicar configuración de runtime (config maps, secrets gestionados por vault).
  3. Desplegar con IaC: Helm, Kustomize o Terraform para infra y manifiestos; usar valores específicos para Dev.
  4. Configurar observabilidad mínima: logs, métricas y trazas activas (Prometheus, Grafana, OpenTelemetry) para detectar fallos.
  5. Ejecutar Smoke Tests: health checks, endpoints críticos, autenticación básica.
  6. Reportar resultados: publicar resultados estructurados (JSON/SARIF) y métricas; si falla, detener y crear ticket/PR de remediación.
  7. Trazabilidad: registrar versión de imagen, SBOM, firma y commit asociado en el despliegue.

Buenas prácticas

  • No reconstruir la imagen en cada entorno; promover la imagen publicada.
  • Entornos efímeros para PRs o features (preview environments) y un entorno Dev persistente para integración continua.
  • Paridad de configuración con staging/producción (variables, límites, sidecars) salvo datos sensibles.
  • Secrets gestionados fuera del repo (Vault, SealedSecrets, Azure Key Vault).
  • Rollback automático: mantener estrategia de rollback si el smoke test falla.
  • Feature flags para habilitar/deshabilitar funcionalidades en Dev sin desplegar nuevo código.
  • Políticas de acceso y auditoría para quién puede promover a entornos superiores.

Ventajas

  • Feedback rápido para desarrolladores.
  • Detecta problemas de integración en entorno cercano a producción.
  • Facilita debugging con trazas y logs reales.

Desventajas

  • Coste en recursos y tiempo si no se optimiza (entornos efímeros mal gestionados).
  • Posible divergencia de configuración si no se mantiene paridad.
  • Riesgo de exponer datos sensibles si los secrets no están bien gestionados.

Ejemplo completo con GitLab CI

Este ejemplo incluye: promoción de imagen firmada, verificación de firma, generación y almacenamiento de SBOM, despliegue con Helm a dev, smoke tests y creación automática de issue si falla.

stages:
  - promote
  - deploy
  - smoke
  - notify

variables:
  REGISTRY: registry.example.com
  IMAGE_NAME: myapp
  NAMESPACE: dev
  HELM_CHART_PATH: ./chart
  SBOM_FILE: sbom-cyclonedx.json

# Job: verificar y preparar imagen (promoción)
promote_and_verify:
  stage: promote
  image: docker:24.0.0
  services:
    - docker:dind
  variables:
    DOCKER_DRIVER: overlay2
  script:
    - echo "Promote job: tag=${IMAGE_TAG:-latest}"
    - docker login $REGISTRY -u "$REGISTRY_USER" -p "$REGISTRY_PASSWORD"
    - docker pull $REGISTRY/$IMAGE_NAME:${IMAGE_TAG}
    # Verificar firma con cosign (clave pública en variable secreta)
    - |
      if ! cosign verify --key "$COSIGN_PUBKEY" $REGISTRY/$IMAGE_NAME:${IMAGE_TAG}; then
        echo "Image signature verification failed" >&2
        exit 2
      fi
    # Generar SBOM (Syft) y guardarlo como artifact
    - syft $REGISTRY/$IMAGE_NAME:${IMAGE_TAG} -o cyclonedx-json > $SBOM_FILE
  artifacts:
    paths:
      - $SBOM_FILE
    expire_in: 1h
  rules:
    - if: $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "pipeline" || $CI_COMMIT_BRANCH == "develop"

# Job: escaneo de imagen opcional (Trivy)
image_scan:
  stage: promote
  image: aquasec/trivy:latest
  dependencies:
    - promote_and_verify
  script:
    - trivy image --format json --output trivy.json --severity HIGH,CRITICAL $REGISTRY/$IMAGE_NAME:${IMAGE_TAG} || true
    - cat trivy.json
    - |
      CRITICAL_COUNT=$(jq '.Results[].Vulnerabilities[]? | select(.Severity=="CRITICAL")' trivy.json | wc -l || true)
      HIGH_COUNT=$(jq '.Results[].Vulnerabilities[]? | select(.Severity=="HIGH")' trivy.json | wc -l || true)
      echo "HIGH: $HIGH_COUNT CRITICAL: $CRITICAL_COUNT"
      if [ "$CRITICAL_COUNT" -gt 0 ]; then
        echo "Critical vulnerabilities found, failing pipeline" >&2
        exit 3
      fi
  artifacts:
    paths:
      - trivy.json
    expire_in: 1h
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

# Job: deploy a Dev con Helm
deploy_to_dev:
  stage: deploy
  image: alpine/helm:3.12.0
  dependencies:
    - promote_and_verify
  before_script:
    - apk add --no-cache curl jq bash
    - echo "$KUBE_CONFIG_BASE64" | base64 -d > /tmp/kubeconfig
    - export KUBECONFIG=/tmp/kubeconfig
  script:
    - echo "Deploying $REGISTRY/$IMAGE_NAME:${IMAGE_TAG} to namespace $NAMESPACE"
    - helm upgrade --install myapp $HELM_CHART_PATH \
        --namespace $NAMESPACE \
        --create-namespace \
        --set image.repository=$REGISTRY/$IMAGE_NAME \
        --set image.tag=${IMAGE_TAG} \
        --wait --timeout 5m
    - kubectl -n $NAMESPACE annotate deployment myapp "ci.commit=${CI_COMMIT_SHA}" --overwrite || true
    - kubectl -n $NAMESPACE annotate deployment myapp "ci.image=${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" --overwrite || true
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

# Job: smoke tests post-deploy
smoke_tests:
  stage: smoke
  image: curlimages/curl:8.3.0
  dependencies:
    - deploy_to_dev
  before_script:
    - apk add --no-cache jq
    - echo "$KUBE_CONFIG_BASE64" | base64 -d > /tmp/kubeconfig
    - export KUBECONFIG=/tmp/kubeconfig
  script:
    - echo "Discover service endpoint"
    - SERVICE_HOST=$(kubectl -n $NAMESPACE get svc myapp -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' || echo "")
    - if [ -z "$SERVICE_HOST" ]; then SERVICE_HOST=$(kubectl -n $NAMESPACE get svc myapp -o jsonpath='{.spec.clusterIP}'); fi
    - echo "Service host: $SERVICE_HOST"
    - |
      # Health check
      if ! curl -fS --retry 3 --max-time 10 "http://$SERVICE_HOST/health"; then
        echo "Smoke test failed" >&2
        exit 4
      fi
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

# Job: notificar y crear issue si falla
notify_on_failure:
  stage: notify
  image: curlimages/curl:8.3.0
  when: on_failure
  script:
    - echo "Creating issue for failed pipeline"
    - |
      curl --request POST --header "PRIVATE-TOKEN: $GITLAB_API_TOKEN" \
        --header "Content-Type: application/json" \
        --data '{
          "title":"[CD] Fallo en Deploy/Smoke tests - '"${CI_PROJECT_PATH}"' '"${CI_COMMIT_SHORT_SHA}"'",
          "description":"Pipeline: '"${CI_PIPELINE_URL}"' \nBranch: '"${CI_COMMIT_BRANCH}"' \nImage: '"${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}"' \nJob: '"${CI_JOB_NAME}"' \nLogs: see job logs",
          "labels":"security,remediation"
        }' "https://gitlab.example.com/api/v4/projects/${CI_PROJECT_ID}/issues"
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

Detalles a tener en cuenta:

  • Promoción sin reconstruir: promote_and_verify hace pull de la imagen ya publicada y verifica su firma con cosign. Garantiza que la imagen que se despliega es la misma que pasó los controles previos.
  • SBOM: syft genera el SBOM y se guarda como artifact para trazabilidad.
  • Image scan: image_scan usa trivy y falla si hay vulnerabilidades críticas (ajusta política según tu gobernanza).
  • Deploy: deploy_to_dev usa helm upgrade --install y anota el deployment con metadatos (commit, imagen).
  • Smoke tests: smoke_tests valida el health endpoint; si falla, notify_on_failure crea un issue automáticamente en GitLab.
  • Secrets: REGISTRY_USER, REGISTRY_PASSWORD, COSIGN_PUBKEY, KUBE_CONFIG_BASE64, GITLAB_API_TOKEN deben estar como variables protegidas de GitLab.

IA

No sustituye el despliegue real.

Sí mejora el proceso en estas áreas:

  • Generación de manifiestos optimizados (Helm/Kustomize) y sugerencias para reducir imágenes y capas.
  • Diagnóstico post-deploy: analizar logs y trazas para identificar la causa raíz de fallos.
  • Automatización de rollbacks: predecir si un despliegue es riesgoso y sugerir rollback.
  • Generación de PRs de remediación con cambios en configuración o Dockerfile.
  • Optimización de entornos efímeros: decidir cuándo crear o destruir previews según coste/beneficio.

Smoke Tests

Son comprobaciones rápidas y deterministas que validan la salud y las funciones críticas del servicio tras un despliegue en un entorno (Dev, Staging). Deben ser rápidos, idempotentes y con salida estructurada para integrarse con gates y procesos de remediación.

Lo que incluye esta etapa

  • Comprobaciones de salud: endpoints /health, /ready, /metrics y checks de liveness/readiness del orquestador.
  • Pruebas de endpoints críticos: llamadas a rutas esenciales (login, flujo de pago, endpoints de lectura/escritura clave) con aserciones simples sobre código HTTP y esquema básico de respuesta.
  • Verificación de dependencias: comprobar conectividad a bases de datos, colas y servicios externos esenciales.
  • Validación de configuración: comprobar que variables de entorno, secrets y configuraciones aplicadas están presentes y con valores esperados (sin exponer secrets en logs).
  • Comprobaciones de observabilidad: asegurar que logs, métricas y trazas se emiten y son accesibles.
  • Tiempo y tolerancia: tests rápidos con timeouts cortos y retries limitados para evitar bloquear el pipeline.
  • Salida estructurada: resultados en JSON/SARIF para ingestión por dashboards, gates o creación automática de issues.

Buenas prácticas

  • Que sean rápidos: objetivo < 2–5 minutos; timeouts y retries controlados.
  • Aislar lo crítico: seleccionar un conjunto pequeño de endpoints que representen la salud funcional mínima.
  • No exponer secretos: nunca imprimir secrets en logs; validar su presencia sin mostrar valores.
  • Idempotencia: diseñar tests que no alteren datos de forma irreversible; usar datos sintéticos o entornos efímeros.
  • Integración con gates: fallos críticos deben detener la promoción; fallos menores pueden crear tickets automáticos.
  • Observabilidad: adjuntar trazas/logs mínimos al reporte para acelerar diagnóstico.
  • Retries inteligentes: permitir 1–2 reintentos con backoff corto para mitigar flakiness transitorio.
  • Entornos efímeros para PRs: ejecutar smoke tests en previews y destruir el entorno al cerrar el PR.

Ventajas

  • Feedback inmediato sobre si el despliegue es viable.
  • Prevención de regresiones en producción al bloquear promociones con fallos evidentes.
  • Bajo coste comparado con suites E2E completas.

Desventajas

  • Cobertura limitada: no detectan problemas de negocio complejos.
  • Posible flakiness si las dependencias externas no están bien simuladas.
  • Falsa sensación de seguridad si la selección de checks es pobre.

Ejemplos

Comprobación health simple (curl):

curl -fS --retry 3 --max-time 10 "http://$SERVICE_HOST/health"

Smoke test con aserciones en bash:

HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://$SERVICE_HOST/api/v1/status")
if [ "$HTTP_CODE" -ne 200 ]; then
  echo "Smoke test failed: status $HTTP_CODE" >&2
  exit 1
fi
  • Uso de frameworks: Newman/Postman para colecciones de smoke; k6 para checks ligeros de latencia; scripts en pytest, JUnit o SuperTest para aserciones programáticas.
  • Integración con Helm: usar helm test para ejecutar hooks de smoke tras deploy si el chart los define.

IA

No sustituye la ejecución real de los tests ni la verificación determinista. Actúa como asistente de productividad y diagnóstico.

Sí mejora el proceso:

  • Generación de suites de smoke: proponer o generar colecciones de endpoints críticos basadas en el código, OpenAPI o historial de incidentes.
  • Diagnóstico automático: al fallar un smoke test, analizar logs y trazas, agrupar errores relacionados y proponer la causa raíz.
  • Sugerencia de retries y timeouts: optimizar parámetros para reducir flakiness sin perder detección temprana.
  • Creación automática de tickets: rellenar issue templates con evidencia, trazas y recomendaciones.
  • Priorización: combinar impacto de negocio con frecuencia histórica para decidir qué checks incluir en smoke.

En el siguiente artículo, “CD — Parte 4: Deploy a Staging y Performance Smoke Tests”, veremos cómo se promueve el artefacto a un entorno de preproducción con paridad a producción, y cómo se validan E2E y rendimiento ligero antes de avanzar hacia fases más exigentes.

Comparte esta entrada en:
Safe Creative #1401310112503
CD (Entrega Continua) — Parte 3: Deploy a Dev y Smoke Tests por "www.jarroba.com" esta bajo una licencia Creative Commons
Reconocimiento-NoComercial-CompartirIgual 3.0 Unported License.
Creado a partir de la obra en www.jarroba.com

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies

ACEPTAR
Aviso de cookies