Módulo 4: Deployment Automation
Proyecto: Workflow de Deployment Completo
Proyecto: Workflow de Deployment Completo
Descripción del proyecto
Este proyecto integra todo lo aprendido en el Módulo 4: changelog automático, readiness validation, flujo staging → producción con approval gates. Vas a construir un workflow de deployment end-to-end funcional, desde el merge a main hasta el deploy a producción, con notificaciones al equipo en cada etapa.
No es un ejercicio teórico. El entregable es un repositorio con:
- Pipeline funcional (probado al menos en staging mock)
- Documentación operacional para el equipo
- Análisis de costos y tiempos
- Plan de extensión para tu caso real
Al completar, vas a tener un template de deployment que puedes adaptar a cualquier proyecto profesional que toques.
Objetivo del Proyecto
Construir un workflow de GitHub Actions que ejecute el ciclo completo de deployment con Claude Code asistiendo en cada paso crítico.
Al completar:
- ✅ Pipeline ejecutable desde merge a main hasta producción
- ✅ Changelog generado automáticamente con cada release
- ✅ Readiness validation antes de cada deploy
- ✅ Deploy automático a staging con smoke tests
- ✅ Approval gate humano antes de producción
- ✅ Análisis pre-promoción que informa al reviewer
- ✅ Notificaciones post-deploy al equipo
- ✅ Documentación operacional completa
Especificaciones Técnicas
Estructura del proyecto
deployment-pipeline-project/
├── .github/
│ └── workflows/
│ ├── release-changelog.yml # cápsula 02
│ ├── readiness-validation.yml # cápsula 03
│ └── staged-deployment.yml # cápsula 04 + integración
├── scripts/
│ ├── generate_changelog.py # cápsula 02
│ ├── validate_readiness.py # cápsula 03
│ ├── validate_staging.py # cápsula 04
│ ├── deploy.sh # mock deploy script
│ ├── smoke_tests.sh # mock smoke tests
│ ├── post_deploy_notification.py # nuevo
│ └── platform_helpers.py # helpers comunes
├── docs/
│ ├── DEPLOYMENT.md # cómo opera el pipeline
│ ├── RUNBOOK.md # qué hacer si X falla
│ └── METRICS.md # análisis de costos
├── CLAUDE.md
├── CHANGELOG.md
└── README.md
Setup inicial
mkdir deployment-pipeline-project && cd deployment-pipeline-project
git init
git checkout -b main
# Configurar GitHub
gh repo create my-deployment-project --public
# Configurar environments en GitHub Settings:
# - staging (sin required reviewers)
# - production (con required reviewers + branch protection)
El Workflow Integrado
# .github/workflows/staged-deployment.yml
name: Staged Deployment
on:
push:
branches: [main]
permissions:
contents: read
pull-requests: write
deployments: write
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false
env:
PYTHON_VERSION: '3.11'
jobs:
# ============================================
# JOB 1: Readiness Validation
# ============================================
validate:
runs-on: ubuntu-latest
outputs:
readiness_status: ${{ steps.validate.outputs.status }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- run: pip install anthropic requests
- name: Run readiness validation
id: validate
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
python scripts/validate_readiness.py
if [ $? -eq 0 ]; then
echo "status=ready" >> $GITHUB_OUTPUT
else
echo "status=blocked" >> $GITHUB_OUTPUT
exit 1
fi
- uses: actions/upload-artifact@v4
if: always()
with:
name: readiness-report
path: readiness_report.json
# ============================================
# JOB 2: Generate Changelog
# ============================================
generate-changelog:
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'pip'
- run: pip install anthropic requests
- name: Generate changelog from last release
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
NEW_TAG: ${{ github.sha }}
run: python scripts/generate_changelog.py
- uses: actions/upload-artifact@v4
with:
name: changelog
path: CHANGELOG_*.md
# ============================================
# JOB 3: Deploy a Staging
# ============================================
deploy-staging:
needs: [validate, generate-changelog]
runs-on: ubuntu-latest
environment: staging
outputs:
deploy_url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Deploy to staging
id: deploy
env:
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
run: |
./scripts/deploy.sh staging
echo "url=https://staging.example.com" >> $GITHUB_OUTPUT
- name: Smoke tests
run: ./scripts/smoke_tests.sh https://staging.example.com
- name: Validate staging metrics with Claude
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: python scripts/validate_staging.py
# ============================================
# JOB 4: Deploy a Producción (con approval gate)
# ============================================
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # ← required reviewers configurados
steps:
- uses: actions/checkout@v4
- name: Deploy to production
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
run: ./scripts/deploy.sh production
- name: Smoke tests on production
run: ./scripts/smoke_tests.sh https://app.example.com
- name: Notify team
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
run: python scripts/post_deploy_notification.py
Script Mock: deploy.sh
#!/bin/bash
# scripts/deploy.sh — mock deploy para testing del pipeline
set -euo pipefail
ENV="${1:?'Usage: deploy.sh <staging|production>'}"
echo "[deploy.sh] Deploying to $ENV..."
echo "[deploy.sh] Pulling latest image..."
sleep 2
echo "[deploy.sh] Running migrations..."
sleep 1
echo "[deploy.sh] Updating containers..."
sleep 2
echo "[deploy.sh] Health check..."
sleep 1
echo "[deploy.sh] Deploy to $ENV complete."
# En producción real, este script invocaría:
# kubectl rollout restart deployment/app -n $ENV
# o
# terraform apply -auto-approve -var "env=$ENV"
# o el mecanismo específico de tu plataforma
Haz el script ejecutable: chmod +x scripts/deploy.sh
Script Mock: smoke_tests.sh
#!/bin/bash
# scripts/smoke_tests.sh — mock smoke tests
set -euo pipefail
URL="${1:?'Usage: smoke_tests.sh <url>'}"
echo "[smoke] Testing $URL..."
# En producción real, ejecutar requests reales:
# curl -f $URL/health || exit 1
# curl -f $URL/api/status || exit 1
# Mock: simular tests
PASSED=0
FAILED=0
SKIPPED=0
for test in health api status auth payments; do
sleep 0.5
if [ $((RANDOM % 10)) -lt 9 ]; then
echo " ✓ $test"
PASSED=$((PASSED + 1))
else
echo " ✗ $test (FAILED)"
FAILED=$((FAILED + 1))
fi
done
echo "{\"passed\": $PASSED, \"failed\": $FAILED, \"skipped\": $SKIPPED}" > smoke_results.json
if [ "$FAILED" -gt 0 ]; then
echo "[smoke] $FAILED tests failed"
exit 1
fi
echo "[smoke] All $PASSED tests passed"
Script Nuevo: post_deploy_notification.py
"""scripts/post_deploy_notification.py
Notifica al equipo del deploy exitoso con resumen útil.
"""
import json
import os
import sys
from pathlib import Path
import requests
from anthropic import Anthropic
def get_changelog() -> str:
"""Leer el último changelog generado."""
changelogs = sorted(Path(".").glob("CHANGELOG_*.md"))
if changelogs:
return changelogs[-1].read_text()
return "No changelog disponible"
def generate_notification_summary(changelog: str) -> str:
"""Generar resumen ejecutivo para Slack/email."""
prompt = f"""Genera un mensaje breve (máximo 150 palabras) para notificar al
equipo de un deploy a producción exitoso. El mensaje debe:
1. Empezar con "🚀 Deployed to production"
2. Resumir los cambios principales del changelog en 2-3 bullets
3. Mencionar si hay breaking changes
4. Cerrar con "Monitoring en curso. Revisar [link a dashboard]."
CHANGELOG:
{changelog[:3000]}
Output: solo el mensaje, sin texto adicional.
"""
client = Anthropic()
response = client.messages.create(
model="claude-haiku-4-5",
max_tokens=500,
messages=[{"role": "user", "content": prompt}],
)
return response.content[0].text.strip()
def send_slack_notification(message: str, webhook: str):
"""Enviar a Slack via webhook."""
payload = {
"text": message,
"username": "Deploy Bot",
"icon_emoji": ":rocket:",
}
r = requests.post(webhook, json=payload, timeout=10)
if r.status_code != 200:
print(f"WARNING: Slack notification failed: {r.status_code}", file=sys.stderr)
def main() -> int:
changelog = get_changelog()
summary = generate_notification_summary(changelog)
print("--- Notification preview ---")
print(summary)
print("---")
webhook = os.environ.get("SLACK_WEBHOOK")
if webhook:
send_slack_notification(summary, webhook)
print("Notificación enviada a Slack")
else:
print("SLACK_WEBHOOK no configurado, skipping notification")
return 0
if __name__ == "__main__":
sys.exit(main())
Documentación: docs/DEPLOYMENT.md
# Deployment Pipeline
Este documento describe el flujo de deployment del proyecto.
## Cuándo se dispara
- **Trigger:** push a `main` (típicamente vía merge de PR)
- **Branches:** solo `main` deploya. Otros branches solo corren CI.
## Stages
### 1. Validate (~30s)
- Tests pasan
- Linting + type checking
- Readiness check (env vars, migrations, deps)
- Análisis con Claude Code para detectar issues
### 2. Generate Changelog (~30s)
- Lista commits desde el último deploy
- Genera changelog estructurado
- Sube como artifact
### 3. Deploy Staging (~3-5 min)
- Deploy automático
- Smoke tests
- Validación con Claude Code de métricas
### 4. Approval Gate (variable)
- Reviewer humano evalúa el deploy
- Tiene info pre-cargada (análisis del Job 3)
- Click "Approve" o investigar
### 5. Deploy Production (~3-5 min)
- Deploy
- Smoke tests
- Notificación al equipo
## Tiempo total esperado
- Sin issues: 8-15 minutos
- Con investigación humana: variable
## Quién aprueba
Reviewers configurados en environment `production`:
- @tech-lead
- @sre-lead
Cualquiera puede aprobar.
## Cuándo NO deployar
- Fines de semana (sin SRE on-call)
- Antes de eventos críticos del negocio
- Cuando staging muestra issues persistentes
Documentación: docs/RUNBOOK.md
# Runbook: Qué Hacer Cuando X Falla
## Validate Failure
**Síntomas:** Job `validate` falla con readiness check error.
**Acción:**
1. Descargar artifact `readiness-report.json`
2. Identificar el check que falló
3. Si es env var faltante en producción: agregarla en Settings → Environments → production
4. Si es migration: verificar que esté aplicada y luego re-disparar
## Staging Deploy Failure
**Síntomas:** Job `deploy-staging` falla.
**Acción:**
1. Ver logs del job
2. Si error de infraestructura: re-run el job
3. Si error de aplicación: revertir el commit en `main`, investigar offline
4. NO promocionar a producción mientras staging falle
## Smoke Tests Falla en Staging
**Síntomas:** Smoke tests reportan failures.
**Acción:**
1. Verificar URL/endpoints accesibles
2. Si endpoint específico falla: review del cambio que afecta ese endpoint
3. Si TODO falla: probable issue de infraestructura
4. NO aprobar producción
## Approval Gate "Stuck"
**Síntomas:** Job production lleva mucho esperando approval.
**Acción:**
1. Verificar que los reviewers están notificados
2. Si urgente: contactar a un reviewer directamente
3. Si nadie disponible: revertir el merge y reintentar
## Production Deploy Failure
**Síntomas:** Producción falla post-deploy.
**Acción:**
1. **Inmediato:** disparar rollback (manual o automático según setup)
2. Verificar métricas en monitoring dashboard
3. Postmortem
4. NO re-deployar el mismo cambio sin investigación
Análisis: docs/METRICS.md
# Pipeline Metrics
Datos del pipeline después de [N runs].
## Tiempos promedio
| Stage | Promedio | P95 |
|-------|----------|-----|
| Validate | 35s | 45s |
| Generate changelog | 25s | 40s |
| Deploy staging | 4 min | 6 min |
| Smoke tests | 90s | 2 min |
| Approval wait | 12 min | 1 hour |
| Deploy production | 4 min | 6 min |
| **Total (sin wait)** | **11 min** | **17 min** |
## Costos estimados
Por run:
- Anthropic API: ~$0.05 (varios calls a Claude)
- GitHub Actions runner: ~$0.04 (5 min × $0.008)
- **Total: ~$0.09 por run**
Mensual (asumiendo 50 deploys/mes):
- ~$4.50/mes en CI/CD
## Frequency
- Deploys/semana promedio: 12
- Pasos manuales antes vs ahora:
- Antes: 8 (changelog manual, readiness manual, comunicación, etc.)
- Ahora: 1 (click de approval)
## Time saved
- Por deploy: ~25 min de tiempo humano
- Mensual: ~25 min × 50 deploys = ~20 hours
ROI: ~$2K/mes ahorrados (con cost de developer ~$100/h)
Entregables del Proyecto
- Repositorio funcional con:
- Workflow ejecutándose end-to-end (al menos staging)
- Scripts (Python + bash)
- Configuración de environments
- Documentación:
docs/DEPLOYMENT.mddocs/RUNBOOK.mddocs/METRICS.md
- Demostración:
- Screenshot/video del pipeline corriendo
- Pipeline completo (todos los jobs verdes)
- Approval gate funcionando
- Plan de extensión documentado:
- Cómo aplicarlo a tu proyecto real
- Qué scripts mock reemplazar con reales
- Qué adaptaciones específicas necesita
Rúbrica de Evaluación (100 puntos)
Pipeline Funcional (40 pts)
- ✅ (10 pts) Validate corre y bloquea correctamente
- ✅ (5 pts) Changelog se genera automáticamente
- ✅ (10 pts) Deploy a staging es completamente automático
- ✅ (10 pts) Approval gate antes de producción funciona
- ✅ (5 pts) Notification post-deploy se envía
Calidad del Código (20 pts)
- ✅ (8 pts) Scripts Python con manejo de errores
- ✅ (4 pts) Exit codes apropiados
- ✅ (4 pts) Logs claros para debugging
- ✅ (4 pts) Estructura limpia (config + main + helpers)
Documentación (25 pts)
- ✅ (10 pts) DEPLOYMENT.md explica el flujo completo
- ✅ (10 pts) RUNBOOK.md cubre los failure modes principales
- ✅ (5 pts) METRICS.md tiene análisis cuantitativo
Setup Profesional (10 pts)
- ✅ (5 pts) Environments configurados correctamente (staging vs production)
- ✅ (5 pts) Secrets separados por environment
Reflexión y Plan (5 pts)
- ✅ (3 pts) Plan de adaptación a proyecto real
- ✅ (2 pts) Lecciones aprendidas documentadas
Extra Credit (+15 pts)
- ✅ (+5 pts) Implementar canary deploy adicional
- ✅ (+3 pts) Integración con un sistema de observability real (Datadog, Prometheus, etc.)
- ✅ (+3 pts) Test del rollback (simular failure post-deploy)
- ✅ (+2 pts) Multi-región deploy (us-east + eu-west, etc.)
- ✅ (+2 pts) Slack bot interactivo (reaccionar emoji para aprobar)
Errores Comunes en el Proyecto
1. No probar el flujo completo
Síntoma: Implementaste cada job pero nunca corriste el pipeline end-to-end.
Por qué pasa: Los jobs separados parecen funcionar.
Cómo corregir: Haz un PR de prueba, mergéalo, observa el pipeline correr completo. Cualquier inconsistencia sale acá.
2. Approval gate sin reviewer asignado
Síntoma: El job deploy-production se queda "esperando aprobación" pero nadie configurado.
Por qué pasa: Olvidaste agregar required reviewers al environment production.
Cómo corregir: Settings → Environments → production → Required reviewers. Agregar a tú mismo para testing.
3. Scripts no ejecutables
Síntoma: ./scripts/deploy.sh: Permission denied.
Por qué pasa: Los scripts bash necesitan flag +x.
Cómo corregir:
chmod +x scripts/*.sh
git update-index --chmod=+x scripts/*.sh
git commit -am "fix: make scripts executable"
4. Documentación superficial
Síntoma: RUNBOOK.md tiene "qué hacer si falla: investigar".
Por qué pasa: Documentación escrita rápido sin pensar casos reales.
Cómo corregir: Para cada failure mode, escribe pasos concretos: comando exacto, dónde mirar logs, a quién contactar. El runbook debe ser usable bajo presión.
5. Ignorar costos en METRICS
Síntoma: El proyecto está completo pero no analizaste cuánto cuesta.
Por qué pasa: Costos parecen secundarios cuando algo funciona.
Cómo corregir: Calcular costo por run, mensual, ROI vs proceso manual. Es lo que justifica el pipeline ante el equipo.
Reflexión Final
Cuando termines este proyecto, tienes un template profesional de deployment automation que:
- Aplica los 6 módulos del path (CI/CD, code review, SDK, scripts, secrets, observability)
- Es portfolio-worthy — demuestra senior-level thinking sobre deployment
- Es transferible — el patrón aplica a cualquier proyecto
Lo más importante: aprendiste a balancear automatización con criterio humano. La automatización elimina trabajo repetitivo. El humano agrega contexto y autoridad. Ese balance es la diferencia entre un pipeline que el equipo confía y uno que el equipo desactiva.
Conexión con el Módulo 5
El siguiente módulo agrega la resiliencia post-deploy: ¿qué pasa cuando producción falla? Rollback automático, security scanning como gate adicional, diagnóstico inteligente de incidents. Tu pipeline actual deploya correctamente; el Módulo 5 lo hace resistente a fallos.
Recursos para el Proyecto
- GitHub Actions Workflow Examples — Templates oficiales
- The DevOps Handbook — Referencia clásica
- Kubernetes Deployment Strategies — Si usas K8s
- Slack Incoming Webhooks — Para notificaciones
- Datadog GitHub Integration — Observability moderna
- Anthropic API Best Practices — Aplicables a deployment