En 05-02 desplegamos servicio-pedidos en Kubernetes escribiendo kubectl apply a mano. Es exactamente lo que TechCorp no puede permitirse: con seis servicios y un gateway, cada uno desplegando varias veces por semana, la mano humana es lenta, inconsistente y la fuente de los "despliegues de jueves noche con reversiones" del módulo 1. La integración continua (CI) hace que cada cambio se pruebe automáticamente en minutos; el despliegue continuo (CD) lleva lo que pasa las pruebas hasta producción sin intervención. Esta lección construye el pipeline de servicio-pedidos con GitHub Actions: pruebas unitarias, de integración con Testcontainers y de contrato con Pact (04-05), construcción y publicación de la imagen de 05-01, can-i-deploy como puerta, actualización de los manifiestos Kustomize de 05-02 y despliegue con GitOps. Al final aplicamos la regla de Luis para que los otros cinco servicios no copien 150 líneas de YAML, y medimos el resultado con las métricas DORA. Cómo cambiar de versión sin cortar el servicio es de 05-04.
Contenido
- Qué cambia el CI/CD con microservicios
- Las etapas del pipeline de TechCorp
.github/workflows/ci.ymldeservicio-pedidos, línea a línea- Pruebas de contrato en el pipeline: Pact Broker y
can-i-deploy - Despliegue continuo:
.github/workflows/cd.yml - GitOps con Argo CD:
techcorp/plataformacomo fuente de verdad - Versiones, etiquetas y changelogs por servicio
- Entornos y promoción: dev → staging → prod
- Secretos en CI
- El pipeline de
@techcorp/comun-http - La regla de Luis: un workflow reutilizable para los seis servicios
- Métricas DORA: medir el pipeline
- Qué cambia el CI/CD con microservicios
El monolito techcorp-shop tenía un pipeline: 40 minutos de suite, un artefacto, un despliegue coordinado. Con microservicios:
| Aspecto | Monolito | Microservicios (TechCorp) |
|---|---|---|
| Número de pipelines | Uno grande | Uno por repositorio: seis servicios + gateway + librería + plataforma |
| Duración | 40 min (todo se prueba siempre) | 5-8 min por servicio (solo se prueba lo que cambia) |
| Artefacto | Un paquete | Una imagen por servicio, con su versión |
| Despliegue | Todo o nada, coordinado | Independiente: Pedidos despliega sin esperar a Catálogo |
| Versionado | Una versión global | Semver por servicio; la compatibilidad la garantizan los contratos (03-06) y Pact (04-05) |
| Riesgo por despliegue | Alto (mucho cambio junto) | Bajo (poco cambio, fácil de revertir) |
| Coste oculto | Pocos | Muchos pipelines que mantener: hay que estandarizarlos (apartado 11) |
La independencia de despliegue es la promesa central de la arquitectura (01-02, 02-01) y solo se cumple si el pipeline de cada servicio puede desplegar solo, sin un "tren de releases" que agrupe a todos. La condición para atreverse es la confianza que dan las pruebas de contrato: es Pact, no una prueba E2E de todo el sistema, quien responde "¿romperé a alguien?".
- Las etapas del pipeline de TechCorp
flowchart LR
A[lint] --> B[unitarias + componente<br/>npm test] --> C[integración<br/>Testcontainers] --> D[contrato<br/>Pact + publicar pactos]
D --> E[build imagen<br/>ghcr.io] --> F[escaneo<br/>Trivy] --> G[can-i-deploy<br/>staging]
G --> H[desplegar staging<br/>Job + rollout] --> I[E2E mínima<br/>gateway 8080] --> J[can-i-deploy prod] --> K[promoción a prod<br/>GitOps]
style E fill:#dfe,stroke:#393
style G fill:#ffd,stroke:#a90
style J fill:#ffd,stroke:#a90
| Etapa | Qué hace | Cuándo | Falla si... |
|---|---|---|---|
| Lint | eslint con la configuración de la plantilla |
Cada push y PR | Estilo o errores estáticos |
| Unitarias + componente | npm test (Jest, Supertest, sin Docker; 04-05) |
Cada push y PR | Lógica de dominio o rutas |
| Integración | npm run test:integracion con Testcontainers (PostgreSQL 16, RabbitMQ) |
Cada push y PR | Outbox, consumidor de saga, SQL |
| Contrato | npm run test:contrato genera pactos (consumidor) o verifica (proveedor); publicación en el Broker |
Cada push y PR | Un contrato roto |
| Build + push | Imagen de 05-01 con etiquetas sha-<commit> y semver |
Solo en main y en tags |
Dockerfile o npm ci |
| Escaneo | Trivy sobre la imagen | Tras el build | CVE crítica (política en 07-04) |
can-i-deploy |
¿Es compatible con lo que hay en el entorno destino? | Antes de cada despliegue | Algún pacto no verificado |
| Despliegue a staging | Job de migraciones + kubectl apply -k + rollout status |
Cada push a main |
Migración o arranque |
| E2E mínima | La única E2E de 04-05 contra staging | Tras desplegar staging | Cableado |
| Promoción a prod | Cambio de imagen en el overlay prod (GitOps) |
Manual o automático según servicio | — |
Todo lo anterior a la imagen es CI: rápido, en cada cambio. Lo posterior es CD.
.github/workflows/ci.yml de servicio-pedidos, línea a línea
.github/workflows/ci.yml de servicio-pedidos, línea a línea# techcorp/servicio-pedidos/.github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
tags: ["v*"] # v1.0.1 → imagen 1.0.1 (apartado 7)
pull_request:
permissions:
contents: read
packages: write # necesario para hacer push a ghcr.io con GITHUB_TOKEN
env:
IMAGEN: ghcr.io/techcorp/servicio-pedidos
PACT_BROKER_BASE_URL: https://pact.techcorp.example
jobs:
pruebas:
runs-on: ubuntu-latest # trae Docker instalado: Testcontainers funciona sin configuración extra
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # cachea ~/.npm entre ejecuciones a partir del package-lock.json
registry-url: https://npm.pkg.github.com
scope: "@techcorp" # @techcorp/comun-http se resuelve contra GitHub Packages (04-01)
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # lectura de paquetes de la organización
- run: npm run lint
- run: npm test # unitarias + componente + eventos: segundos, sin Docker
- run: npm run test:integracion # Testcontainers levanta postgres:16 y rabbitmq en el runner
- run: npm run test:contrato # genera pactos/servicio-pedidos-servicio-catalogo.json
- name: Publicar pactos en el Broker
run: |
npx pact-broker publish pactos \
--consumer-app-version ${{ github.sha }} \
--branch ${{ github.head_ref || github.ref_name }} \
--broker-token ${{ secrets.PACT_BROKER_TOKEN }}
imagen:
needs: pruebas
if: github.event_name == 'push' # en PR no se publica imagen
runs-on: ubuntu-latest
outputs:
etiqueta: ${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3 # BuildKit: necesario para --mount=type=secret y caché remota
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5 # calcula las etiquetas según el evento
with:
images: ${{ env.IMAGEN }}
tags: |
type=sha,prefix=sha-,format=short # siempre: sha-9f3c2ab
type=semver,pattern={{version}} # solo en tags v1.0.1 → 1.0.1
- name: Preparar .npmrc para el build (secreto, no capa)
run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" > /tmp/npmrc
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
secrets: npmrc=/tmp/npmrc # el --secret id=npmrc del Dockerfile de 05-01
cache-from: type=gha # caché de capas entre ejecuciones (el npm ci de 05-01 §4)
cache-to: type=gha,mode=max
- name: Escaneo de vulnerabilidades (detalle en 07-04)
uses: aquasecurity/[email protected]
with:
image-ref: ${{ env.IMAGEN }}:sha-${{ github.sha }}
severity: CRITICAL
exit-code: "1"Notas de lectura:
- Dos
jobs(pruebas,imagen) conneeds: la imagen solo se construye si todo pasa; en un PR (pull_request) solo correpruebas. ubuntu-latesttrae Docker, así quetest:integracionfunciona tal cual: Testcontainers descargapostgres:16yrabbitmq:3-managementen el runner. Es la razón por la que en 04-05 separamostest(sin Docker) detest:integracion.docker/metadata-actionproduce las dos etiquetas de 05-01 sin scripts a mano:sha-<commit>siempre, y la semver cuando el evento es un tagv1.0.1.secrets: npmrc=enbuild-push-actionalimenta el--mount=type=secret,id=npmrcdelDockerfile: el token no queda en ninguna capa.cache-from/to: type=ghaguarda las capas en la caché de GitHub Actions: un cambio ensrc/no repitenpm cien CI, igual que en el portátil.permissionsmínimos:contents: readpara clonar,packages: writepara publicar. Nada de tokens personales.
- Pruebas de contrato en el pipeline: Pact Broker y
can-i-deploy
can-i-deployEn 04-05 el fichero de pacto viajaba a mano de servicio-pedidos a servicio-catalogo. En CI viaja por el Pact Broker (autoalojado o PactFlow), que guarda cada pacto con la versión (github.sha) y la rama del consumidor, y cada resultado de verificación con la versión del proveedor:
sequenceDiagram
participant P as CI servicio-pedidos (consumidor)
participant B as Pact Broker
participant C as CI servicio-catalogo (proveedor)
P->>B: publish pactos (version sha-9f3c2ab, branch main)
B-->>C: webhook: hay un pacto nuevo que verificar
C->>C: npm run test:contrato (Verifier con stateHandlers, 04-05)
C->>B: resultado de la verificación (catalogo sha-1a2b3c: OK)
P->>B: can-i-deploy --pacticipant servicio-pedidos --version sha-9f3c2ab --to-environment staging
B-->>P: sí: el catálogo desplegado en staging verificó este pacto
En el CI del proveedor (servicio-catalogo), el test:contrato de 04-05 se ejecuta con pactBrokerUrl en lugar de pactUrls, con publishVerificationResult: true y providerVersion: process.env.GITHUB_SHA, y tras desplegar registra en qué entorno está cada versión (pact-broker record-deployment --environment staging). Con eso, la puerta antes de desplegar es una línea:
puerta-staging:
needs: imagen
runs-on: ubuntu-latest
steps:
- run: |
npx pact-broker can-i-deploy \
--pacticipant servicio-pedidos --version ${{ github.sha }} \
--to-environment staging \
--broker-base-url ${{ env.PACT_BROKER_BASE_URL }} --broker-token ${{ secrets.PACT_BROKER_TOKEN }}can-i-deploy responde "sí" solo si todas las versiones de proveedores actualmente desplegadas en staging han verificado con éxito los pactos de esta versión de Pedidos (y, si Pedidos fuera proveedor de alguien, si sus consumidores desplegados siguen satisfechos). Es la garantía de integración a coste de una consulta HTTP: la razón por la que la única E2E de TechCorp puede seguir siendo una.
- Despliegue continuo:
.github/workflows/cd.yml
.github/workflows/cd.ymlEl despliegue a staging es directo desde el workflow: actualiza la etiqueta de imagen en el overlay de Kustomize (05-02), lanza el Job de migraciones, aplica y espera al rollout, y ejecuta la E2E.
# techcorp/servicio-pedidos/.github/workflows/cd.yml
name: CD staging
on:
workflow_run:
workflows: [CI]
branches: [main]
types: [completed]
permissions: { contents: read }
jobs:
staging:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
environment: staging # entorno de GitHub: secretos propios y reglas de protección
env:
ETIQUETA: sha-${{ github.event.workflow_run.head_sha }}
steps:
- uses: actions/checkout@v4
with:
repository: techcorp/plataforma # los manifiestos viven en el repo de plataforma (05-02)
token: ${{ secrets.PLATAFORMA_TOKEN }}
- uses: azure/setup-kubectl@v4
- name: Credenciales del clúster de staging
run: echo "${{ secrets.KUBECONFIG_STAGING }}" | base64 -d > $HOME/.kube/config
- name: Fijar la imagen en el overlay de staging
working-directory: k8s/servicio-pedidos/overlays/staging
run: kustomize edit set image ghcr.io/techcorp/servicio-pedidos=ghcr.io/techcorp/servicio-pedidos:${{ env.ETIQUETA }}
- name: Migraciones (Job de 05-02): borrar el anterior, aplicar, esperar
run: |
kubectl -n techcorp delete job servicio-pedidos-migraciones --ignore-not-found
kubectl kustomize k8s/servicio-pedidos/overlays/staging | kubectl apply -f -
kubectl -n techcorp wait --for=condition=complete job/servicio-pedidos-migraciones --timeout=180s
- name: Esperar al rollout
run: kubectl -n techcorp rollout status deploy/servicio-pedidos --timeout=180s
- name: E2E mínima contra staging (04-05)
run: GATEWAY_URL=https://api-staging.techcorp.example npm run test:e2e
- name: Registrar el despliegue en el Pact Broker
run: npx pact-broker record-deployment --pacticipant servicio-pedidos --version ${{ github.event.workflow_run.head_sha }} --environment staging --broker-token ${{ secrets.PACT_BROKER_TOKEN }}Dos detalles frente a 05-02: el Job de migraciones pasa a llamarse servicio-pedidos-migraciones a secas y el workflow borra el anterior antes de aplicar (un Job es inmutable); es la alternativa al nombre versionado, y funciona porque migrar.js es idempotente. Y kustomize edit set image modifica la línea images: que dejamos preparada en el overlay: el YAML sigue siendo la fuente de verdad, el pipeline solo cambia una etiqueta. Con Helm el equivalente sería helm upgrade --set image.tag=$ETIQUETA.
rollout status es lo que convierte "he aplicado" en "está desplegado y listo": espera a que las réplicas nuevas pasen el readinessProbe y falla (y el job falla) si en 180 s no lo consiguen. Qué hace Kubernetes mientras tanto con las réplicas viejas es 05-04.
- GitOps con Argo CD:
techcorp/plataforma como fuente de verdad
techcorp/plataforma como fuente de verdadPara producción, TechCorp no quiere que un workflow con un kubeconfig en un secreto ejecute kubectl apply contra el clúster de producción. Adopta GitOps: el estado deseado de producción es lo que hay en git (techcorp/plataforma, rama main, overlays/prod), y un agente dentro del clúster (Argo CD; Flux es equivalente) lo lee y lo aplica continuamente.
flowchart LR
CI[CI servicio-pedidos] -->|imagen sha-9f3c2ab| REG[(ghcr.io)]
CI -->|PR: overlays/prod images newTag=1.0.1| GIT[(techcorp/plataforma)]
REV[Revisión + merge<br/>Luis o el pipeline] --> GIT
ARGO[Argo CD<br/>en el clúster prod] -->|pull cada 3 min / webhook| GIT
ARGO -->|kubectl apply| K8S[Clúster producción]
ARGO -.->|detecta drift| K8S
# techcorp/plataforma/argocd/servicio-pedidos-prod.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata: { name: servicio-pedidos-prod, namespace: argocd }
spec:
project: techcorp
source:
repoURL: https://github.com/techcorp/plataforma
targetRevision: main
path: k8s/servicio-pedidos/overlays/prod
destination: { server: https://kubernetes.default.svc, namespace: techcorp }
syncPolicy:
automated: { prune: true, selfHeal: true } # aplica lo que hay en git; revierte cambios manuales en el clústerPor qué TechCorp lo adopta: (1) auditoría: cada despliegue a producción es un commit revisable en plataforma; (2) sin credenciales del clúster fuera del clúster: Argo CD hace pull, nadie hace push; (3) detección de desviaciones: si alguien hace kubectl scale a mano un viernes, Argo lo devuelve al estado de git (o avisa); (4) rollback = revertir el commit. El Job de migraciones se anota como argocd.argoproj.io/hook: PreSync con hook-delete-policy: BeforeHookCreation, que es la forma GitOps de "borrar el anterior y ejecutar antes del Deployment". Argo CD y Flux también pueden desplegar en staging; TechCorp empieza con el workflow directo en staging para aprender y con GitOps en producción, y unificará más adelante.
- Versiones, etiquetas y changelogs por servicio
- Semver por servicio:
servicio-pedidos1.0.1 no tiene nada que ver conservicio-catalogo1.4.2. Mayor = cambio incompatible de contrato (que en 03-06 significa/v2/), menor = funcionalidad compatible, parche = corrección. - La imagen
sha-<commit>se construye siempre; la semver, al etiquetar:git tag v1.0.1 && git push --tagsdisparaci.ymlcon el tag ymetadata-actionañade1.0.1a la misma imagen (mismo digest) que ya pasó por staging comosha-.... No se reconstruye nada para producción. - Changelog:
CHANGELOG.mden cada repositorio, alimentado a mano o generado a partir de mensajes de commit con la convención conventional commits (feat:,fix:,feat!:), que herramientas comosemantic-releaseorelease-pleaseusan para calcular la versión y publicar la release automáticamente. TechCorp adopta la convención de mensajes; la automatización de la versión queda como paso siguiente.
- Entornos y promoción: dev → staging → prod
| Entorno | Clúster | Quién despliega | Qué imagen | Datos |
|---|---|---|---|---|
| dev | kind en el portátil o Compose (05-01) | El desarrollador | :local o sha-... |
Semilla |
| staging | Clúster compartido, gestionados en tamaño pequeño | cd.yml en cada push a main |
sha-<commit> |
Sintéticos, anonimizados |
| prod | Clúster de producción, Argo CD | Merge del PR de promoción (revisión humana para Pedidos y Pagos; automático para Catálogo y Notificaciones) | 1.0.1 (misma imagen) |
Reales |
Los tres entornos aplican la misma base Kustomize con overlays distintos (05-02): lo único que cambia entre staging y prod es la etiqueta de imagen, las réplicas y dos claves de ConfigMap. Promover es abrir un PR en plataforma que cambia newTag en overlays/prod (el workflow lo abre solo con peter-evans/create-pull-request); revisar y fusionar es la aprobación.
- Secretos en CI
secrets.GITHUB_TOKEN: lo genera GitHub para cada ejecución, con lospermissionsdeclarados; sirve paraghcr.ioy GitHub Packages sin crear nada.- Secretos de repositorio/organización (
PACT_BROKER_TOKEN,PLATAFORMA_TOKEN) y de entorno (KUBECONFIG_STAGING, ligado alenvironment: staging, con revisores obligatorios si se quiere). - OIDC en lugar de claves de larga duración: para hablar con la nube (AWS/GCP/Azure) o con un registro externo, el workflow obtiene un token efímero por identidad federada (
permissions: id-token: write+aws-actions/configure-aws-credentials) en vez de guardar una access key en un secreto. Es la práctica recomendada y la que TechCorp usará para el clúster de producción si algún día un workflow necesita tocarlo (con GitOps, no lo necesita). - Nunca
echode un secreto en los logs; GitHub los enmascara, pero base64 o transformaciones los destapan.
- El pipeline de
@techcorp/comun-http
@techcorp/comun-httpLa librería (04-01) tiene su propio workflow, más corto: npm ci, npm test, y en tag v*, npm publish a GitHub Packages:
# techcorp/comun-http/.github/workflows/publicar.yml (extracto)
on: { push: { tags: ["v*"] } }
permissions: { contents: read, packages: write }
jobs:
publicar:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm, registry-url: https://npm.pkg.github.com, scope: "@techcorp" }
- run: npm ci && npm test
- run: npm publish
env: { NODE_AUTH_TOKEN: "${{ secrets.GITHUB_TOKEN }}" }Cada servicio fija en su package.json la versión que usa ("@techcorp/comun-http": "^2.3.0") y la actualiza cuando quiere, con Renovate/Dependabot abriendo el PR: la librería no obliga a redesplegar a nadie, que era la condición para que existiera (04-01).
- La regla de Luis: un workflow reutilizable para los seis servicios
"Si se hace más de una vez por servicio, se automatiza antes del segundo." El ci.yml del apartado 3 tiene 80 líneas y sería idéntico en Catálogo, Inventario, Pagos, Notificaciones y Clientes salvo el nombre. GitHub Actions permite un workflow reutilizable (workflow_call) que vive en techcorp/plataforma:
# techcorp/plataforma/.github/workflows/servicio-node-ci.yml
on:
workflow_call:
inputs:
nombre-servicio: { required: true, type: string }
con-integracion: { type: boolean, default: true } # Notificaciones no tiene BD: puede desactivarla
secrets:
PACT_BROKER_TOKEN: { required: true }
jobs:
pruebas: ... # exactamente los pasos del apartado 3, con ${{ inputs.nombre-servicio }} donde había servicio-pedidos
imagen: ...Y en cada servicio, el ci.yml se reduce a:
# techcorp/servicio-catalogo/.github/workflows/ci.yml
name: CI
on: { push: { branches: [main], tags: ["v*"] }, pull_request: }
permissions: { contents: read, packages: write }
jobs:
ci:
uses: techcorp/plataforma/.github/workflows/servicio-node-ci.yml@v1 # @v1: tag del repo plataforma; se actualiza a propósito
with: { nombre-servicio: servicio-catalogo }
secrets: inheritEl workflow reutilizable es a los pipelines lo que @techcorp/comun-http a los servicios: se versiona (@v1), cada servicio adopta la versión nueva cuando quiere, y la plantilla plantilla-servicio-node (04-01) ya trae estas nueve líneas. Un cambio en el pipeline (añadir Trivy, cambiar la versión de una acción) se hace una vez.
- Métricas DORA: medir el pipeline
Las cuatro métricas DORA (DevOps Research and Assessment) miden si todo lo anterior sirve para algo:
| Métrica | Qué mide | TechCorp antes (monolito, 01-05) | Objetivo con el pipeline |
|---|---|---|---|
| Frecuencia de despliegue | Cuántas veces se llega a producción | Jueves noche, quincenal | Varias veces al día, por servicio |
| Lead time de cambios | Del commit a producción | 1-2 semanas (esperar al tren) | < 1 día (< 1 hora para hotfixes) |
| Tasa de fallo de cambios | % de despliegues que provocan incidente o reversión | Alta: reversiones frecuentes | < 15 % |
| Tiempo de restauración (MTTR) | Cuánto se tarda en recuperar el servicio tras un fallo | 50 min sin vender en Black Friday | Minutos: rollout undo o revertir el commit (05-04) |
Las dos primeras las da el propio pipeline (fecha del commit, fecha del sync de Argo); las otras dos necesitan la gestión de incidentes de 06-05. Lo importante es la relación entre ellas: desplegar más a menudo con cambios más pequeños baja la tasa de fallo y el MTTR, que es lo contrario de la intuición del jueves noche ("desplegamos poco para arriesgar poco").
Errores Comunes y Consejos
- Un pipeline "de sistema" que prueba y despliega todos los servicios juntos. Es el tren de releases del monolito con más YAML. Un pipeline por servicio y contratos como garantía.
- Reconstruir la imagen para producción. Lo que se probó no es lo que se despliega. Etiqueta semver sobre la imagen
sha-ya probada. can-i-deploycomo paso opcional ocontinue-on-error. Se acaba ignorando. Es una puerta: si dice no, no se despliega.kubectl applysinrollout status. El pipeline está verde y las réplicas nuevas enCrashLoopBackOff.- Copiar
ci.ymlentre repositorios. A la tercera versión de una acción, seis PRs idénticos.workflow_call. - Secretos de larga duración en variables cuando OIDC está disponible; tokens personales de un desarrollador en secretos de la organización (dejan de funcionar cuando se va).
- Consejo: ejecuta el
workflowlocalmente conactpara depurar; y guarda en unREADMEde cada repositorio el enlace al workflow reutilizable y a los runbooks, para que "cómo se despliega esto" tenga una respuesta.
Ejercicios
Ejercicio 1. El CI de servicio-catalogo (proveedor) debe verificar los pactos que publican sus consumidores. Escribe los pasos del job contrato de su ci.yml (sin repetir checkout/setup-node) y explica qué variables de entorno necesita el Verifier de 04-05 para trabajar con el Broker en lugar de con un fichero local, y por qué debe ejecutar record-deployment tras desplegar.
Ejercicio 2. Un desarrollador de Pagos abre un PR que cambia el payload del evento pago.confirmado. ¿En qué etapa del pipeline de Pagos se detectaría una incompatibilidad con servicio-pedidos, con las herramientas de 04-05, y qué haría falta añadir para que can-i-deploy la bloqueara?
Ejercicio 3. Marta pide que Catálogo y Notificaciones se promocionen a producción automáticamente tras pasar la E2E en staging, pero Pedidos y Pagos requieran aprobación humana. Describe cómo se implementa con lo visto (entornos de GitHub, workflow_call, PR de promoción, Argo CD) sin duplicar el workflow.
Soluciones
Solución 1. Pasos: npm ci → npm run test:contrato con PACT_BROKER_BASE_URL, PACT_BROKER_TOKEN, GIT_COMMIT=${{ github.sha }} y GIT_BRANCH=${{ github.ref_name }} en env; el Verifier de 04-05 usa pactBrokerUrl y pactBrokerToken en lugar de pactUrls, providerVersion: process.env.GIT_COMMIT, providerVersionBranch, publishVerificationResult: true (solo en CI: process.env.CI === 'true') y consumerVersionSelectors: [{ mainBranch: true }, { deployedOrReleased: true }] para verificar tanto los pactos de la rama principal de cada consumidor como los de las versiones desplegadas. Tras desplegar a un entorno, pact-broker record-deployment --pacticipant servicio-catalogo --version $GIT_COMMIT --environment staging le dice al Broker qué versión de Catálogo está en staging: sin ese registro, el can-i-deploy de Pedidos no sabe contra qué proveedor comprobar y responde "no" por falta de información.
Solución 2. En la etapa contrato, pero del lado del consumidor: 04-05 fijó JSON Schema de eventos con Ajv y una prueba de que servicio-pedidos tolera campos nuevos de pago.confirmado; si Pagos quita o renombra un campo (importe → cantidad), lo detecta la prueba de esquema del propio Pagos si el esquema está compartido en contratos/asyncapi.yaml (falla en npm test de Pagos), o, si no, la prueba de eventos de Pedidos cuando actualice el esquema. Para que can-i-deploy lo bloquee haría falta un pacto de mensajes (Pact soporta message pacts: Pedidos declara el mensaje que espera; Pagos lo verifica con un MessageProviderPact que produce el evento real) publicado en el mismo Broker: entonces la relación Pagos→Pedidos aparece como cualquier otra y can-i-deploy la comprueba. Es la evolución natural del JSON Schema de 04-05.
Solución 3. El workflow reutilizable de CD (servicio-node-cd.yml) recibe un input promocion-automatica: boolean. Su último job abre el PR de promoción en techcorp/plataforma (cambio de newTag en overlays/prod); si promocion-automatica es true, el mismo job lo fusiona (gh pr merge --auto), y Argo CD sincroniza; si es false, el PR queda abierto y el CODEOWNERS de k8s/servicio-pedidos/ y k8s/servicio-pagos/ exige la revisión de Luis o del líder de Pagos. Además, el job de producción usa environment: production en GitHub con required reviewers para esos dos servicios. Ningún workflow se duplica: Catálogo llama con promocion-automatica: true, Pedidos con false.
Conclusión
El pipeline de TechCorp convierte cada push en una secuencia automática y por servicio: ci.yml con actions/setup-node@v4 (Node 20, caché npm, GitHub Packages), npm run lint, npm test, npm run test:integracion con Testcontainers en el runner, npm run test:contrato y publicación de pactos en el Pact Broker, docker/build-push-action con etiquetas sha-<commit> y semver hacia ghcr.io/techcorp/servicio-pedidos (con permissions: packages: write y el .npmrc como secreto de build), escaneo con Trivy, y can-i-deploy como puerta; cd.yml que fija la imagen en el overlay de Kustomize (kustomize edit set image), ejecuta el Job de migraciones, hace kubectl apply + rollout status y lanza la E2E contra staging; GitOps con Argo CD y techcorp/plataforma como fuente de verdad para producción; semver y sha- sobre la misma imagen; entornos con los mismos manifiestos; secretos de GitHub y OIDC; el pipeline de @techcorp/comun-http; el workflow reutilizable servicio-node-ci.yml@v1 que aplica la regla de Luis; y las métricas DORA para comprobar que los jueves noche han terminado. Queda una pregunta que rollout status esconde: ¿qué ocurre exactamente con el tráfico mientras las réplicas de la 1.0.0 dejan paso a las de la 1.0.1, y cómo se despliega una versión a un 10 % de los usuarios antes de dársela a todos? Eso es la siguiente lección: estrategias de despliegue.
Curso de Microservicios
Módulo 1: Introducción a los Microservicios
- Conceptos Básicos de Microservicios
- Ventajas y Desventajas de los Microservicios
- Comparación con la Arquitectura Monolítica
- Cuándo Adoptar Microservicios: Criterios de Decisión
- El Caso Práctico del Curso: la Tienda Online de TechCorp
Módulo 2: Diseño de Microservicios
- Principios de Diseño de Microservicios
- Descomposición de Aplicaciones Monolíticas
- Definición de Bounded Contexts
- Gestión de Datos: una Base de Datos por Servicio
- Consistencia Distribuida: Sagas, CQRS y Event Sourcing
Módulo 3: Comunicación entre Microservicios
- APIs RESTful
- Mensajería Asíncrona
- Protocolos de Comunicación: gRPC, GraphQL
- API Gateway y Backend for Frontend
- Descubrimiento de Servicios y Balanceo de Carga
- Contratos y Versionado de APIs
Módulo 4: Implementación de Microservicios
- Elección de Tecnologías y Herramientas
- Desarrollo de un Microservicio Simple
- Gestión de Configuración
- Integración Práctica: Consumir APIs y Publicar Eventos
- Pruebas en Microservicios: Unitarias, de Integración y de Contrato
Módulo 5: Despliegue y Orquestación
- Contenedores y Docker
- Orquestación con Kubernetes
- CI/CD para Microservicios
- Estrategias de Despliegue: Rolling, Blue-Green y Canary
- Service Mesh: Istio y Linkerd
Módulo 6: Monitoreo y Mantenimiento
- Monitoreo y Logging
- Trazabilidad Distribuida con OpenTelemetry
- Gestión de Errores y Recuperación
- Escalabilidad y Rendimiento
- SLOs, Alertas y Gestión de Incidentes
Módulo 7: Seguridad en Microservicios
- Autenticación y Autorización
- Seguridad en la Comunicación
- Prácticas de Seguridad
- Seguridad en Contenedores y Kubernetes
