La integración continua demuestra que cada cambio puede unirse a la rama principal. La entrega continua demuestra que un artefacto conocido puede llegar a producción de forma segura. El punto no es un archivo YAML heroico. El punto es un camino corto y repetible desde el commit hasta la evidencia y el release.
🎙️ Publicado y grabado: ·
Un pipeline es una secuencia de puertas de evidencia. Pon formateo, comprobaciones estáticas y tests unitarios enfocados primero porque fallan barato. Ejecuta jobs independientes en paralelo. Pon tests de integración y empaquetado después, luego despliega el paquete exacto que pasó. Si los desarrolladores esperan cuarenta minutos para enterarse de un typo, acumularán cambios y dejarán de confiar en el pipeline.
# Fail cheap, then spend more confidence
lint ───────────────┐
unit tests ─────────┼─→ integration → build once → deploy staging → production
secret scan ────────┘
# Every command must also work on a clean developer machine
./ci/lint
./ci/test-unit
./ci/test-integration
./ci/buildError: Process completed with exit code 1.Esa línea es un resumen, no la causa. Uno: abre el paso fallido y encuentra el primer comando que devolvió nonzero. Dos: desplázate hacia arriba hasta su primer error concreto, no el stack trace final. Tres: re-ejecuta ese script exacto localmente con la misma versión de runtime. Cuatro: corrige el comando o el código. No añadas || true; eso convierte una puerta en decoración.
El mismo commit y las mismas entradas declaradas deben producir el mismo artefacto funcional. Fija el runtime, haz commit del lockfile, empieza desde un workspace limpio y mantén las elecciones de red en tiempo de build fuera de tu camino de control. Graba el commit fuente y las versiones de herramientas dentro del artefacto. "Latest" no es una versión; es un incidente aplazado.
# Pin base image by immutable digest
FROM node:22.17.0-alpine@sha256:0123456789abcdef...
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
COPY . .
RUN npm test && npm run build
ARG GIT_SHA
LABEL org.opencontainers.image.revision=$GIT_SHAReproducible no significa que cada byte del archivo sea automáticamente idéntico; timestamps y orden de archivos pueden variar a menos que se normalicen. Significa que nadie puede elegir silenciosamente una dependencia más nueva al reconstruir el commit de ayer. Prefiere desplegar el artefacto ya construido por CI en vez de reconstruirlo en cada entorno.
Una caché es una optimización que puede desaparecer en cualquier momento. Identifica las cachés de dependencias por sistema operativo, arquitectura, versión de runtime y hash del lockfile. Nunca cachees resultados de tests sin incluir cada entrada que los cambia. Nunca pongas secretos ni artefactos de release construidos en una caché general compartida.
# Good cache identity
key: npm-${{ runner.os }}-node-22-${{ hashFiles('package-lock.json') }}
path: ~/.npm
# Prove the pipeline works without yesterday's state
weekly-clean-build: restore-keys: []
# Artifact storage is not a cache
release/app-8f31c2a.tar.gz retention: 90 days immutable: truenpm error code EINTEGRITY
npm error sha512 checksum failed when using sha512: wanted ... but got ...Uno: preserva el lockfile y el nombre del paquete fallido del log. Dos: re-ejecuta una vez con la caché de dependencias desactivada. Tres: si la ejecución limpia pasa, borra la entrada de caché corrupta y rota la clave de caché. Cuatro: si sigue fallando, verifica el registry o proxy y regenera el lockfile solo después de revisar el cambio de dependencia. No desactives las comprobaciones de integridad.
No almacenes credenciales en el repositorio, archivo de workflow, capa de imagen, artefacto, caché ni log. Prefiere identidad de workload: el job de CI demuestra quién es y recibe una credencial de nube de corta duración. Restringe el despliegue a producción a ramas y entornos protegidos. Los pull requests desde forks no deben recibir secretos privilegiados.
# Prefer identity exchange over a permanent cloud key
permissions:
contents: read
id-token: write
environment: production
# Production environment adds approval and branch restrictions.Resource not accessible by integrationUno: identifica la llamada a la API que devolvió el mensaje. Dos: inspecciona los permisos efectivos del token del job; los defaults del repositorio pueden ser solo lectura. Tres: concede solo el scope faltante a nivel de job, como pull requests write, y confirma que el evento puede recibirlo. Cuatro: para un fork no confiable, rediseña el flujo en vez de exponer un token más fuerte. No saltes directamente a un personal access token.
Construye una vez, identifica el resultado por digest, y promueve ese mismo artefacto a través de test, staging y producción. La configuración específica del entorno llega en runtime. Si staging reconstruye desde source y producción reconstruye otra vez, testeaste dos primos del software desplegado, no el software desplegado.
# CI records an immutable identity
IMAGE=registry.example/app@sha256:4c3f...9a10
# Staging and production differ in configuration, not application bytes
deploy staging $IMAGE --config=config/staging
verify staging $IMAGE
approve production
deploy production $IMAGE --config=config/productionMantén los datos de test fuera de producción y las credenciales de producción fuera de staging. Haz los entornos similares en arquitectura, pero no pretendas que son intercambiables. Adjunta el commit, la ejecución del build, el manifiesto de dependencias, checksums y notas de release al artefacto para que un operador pueda responder exactamente qué está corriendo.
El rollback de aplicación es fácil solo cuando la base de datos aún acepta la aplicación antigua. Usa expand and contract. Primero añade una columna nullable, una tabla nueva o un índice compatible. Despliega código que entienda la forma antigua y la nueva. Backfill en lotes acotados. Cambia las lecturas. Elimina la forma antigua en un release posterior cuando el riesgo de rollback haya pasado.
# Release A: expand
ALTER TABLE users ADD COLUMN display_name text;
# App writes both old name and display_name.
# Background job: small batches, observable progress
UPDATE users SET display_name = name
WHERE display_name IS NULL AND id > $1 AND id <= $2;
# Later release: contract after every reader moved
ALTER TABLE users DROP COLUMN name;Ejecuta migraciones revisadas como un paso de release explícito, no una vez por réplica de la aplicación al arrancar. Pruébalas contra volumen similar a producción. Pon un lock timeout en sentencias arriesgadas, monitoriza el lag de replicación y detén un backfill que perjudique el tráfico. Un rename destructivo y un deploy de código en un solo release hace que el rollback sea ficción.
Un rolling deployment reemplaza instancias gradualmente y cuesta poca capacidad extra, pero las versiones antigua y nueva coexisten. Blue-green mantiene dos entornos completos y cambia tráfico rápidamente, lo que hace la reversión rápida pero cuesta más. Un canary envía un porcentaje pequeño a la versión nueva y expande solo cuando las métricas reales se mantienen sanas.
# Canary progression with explicit gates
1% for 10 min → 10% for 20 min → 50% for 20 min → 100%
stop if:
error_rate > baseline + 0.5 percentage points
p95_latency > baseline * 1.20
checkout_success < agreed floor
# Health means dependency-ready, not merely process-alive.No elijas Kubernetes, canaries o blue-green para parecer maduro. Un servicio pequeño con rollback instantáneo puede necesitar un rolling release cuidadoso. Usa canaries cuando el comportamiento de producción aporta evidencia que staging no puede, y haz la puerta automática. Observar un dashboard mientras sube el tráfico es teatro a menos que alguien posea una regla de parada.
Rollback es un control normal, no una admisión de derrota. Mantén el artefacto anterior desplegable, almacena la versión activa y haz la reversión un comando testeado. Haz rollback del código de la aplicación cuando los errores suben. Haz roll forward cuando los datos ya se han transformado de forma incompatible o un fix de seguridad no puede reintroducirse de forma segura. Los feature flags pueden desactivar comportamiento más rápido que ambos, pero flags rancios se convierten en un segundo sistema de configuración.
# A release record gives the operator concrete choices
current: app@sha256:4c3f...9a10 commit: 8f31c2a
previous: app@sha256:119d...7b42 commit: 60ab911
# Reversal changes the desired digest; it does not rebuild.
./deploy production app@sha256:119d...7b42
./smoke-test https://app.example
./verify-metrics --compare-to=pre-releasePractica este camino. Un script de rollback que no se ha ejecutado en seis meses es documentación, no una capacidad. Define quién puede dispararlo, qué métrica cruza el umbral, cómo se comprueba la compatibilidad de base de datos y cómo se informa a los clientes. Preserva el artefacto fallido y los logs para diagnóstico después de que el servicio esté a salvo.
Separa los fallos de pipeline en capas de source, runner, dependencia, credencial, artefacto, despliegue y runtime. Empieza con el primer comando fallido, la imagen y versión del runner, el commit y si una re-ejecución limpia cambia el resultado. Compara hechos con la última ejecución exitosa. Editar YAML aleatoriamente destruye la evidencia.
/bin/sh: ./ci/build: Permission denied
# Inspect the repository mode, not just local filesystem behavior
git ls-files --stage ci/build
# wanted: 100755 ... ci/build
# Fix and commit the executable bit
git update-index --chmod=+x ci/build
# Also verify the first line, for example: #!/bin/shUno: confirma la ruta fallida y el directorio de trabajo. Dos: inspecciona su modo con commit con git ls-files --stage. Tres: haz commit del bit ejecutable y verifica que el intérprete en el shebang existe en el runner. Cuatro: re-ejecuta desde un checkout fresco. Llamar a chmod en cada ejecución del pipeline enmascara el defecto del repositorio y a menudo falla de nuevo en otro job.
Úsalo como revisión de release, no como colección de insignias.
# commit path
fast checks in parallel → integration → build once → checksum and attest
→ deploy same digest to staging → verify → approve → production
# trust boundaries
untrusted fork: no privileged secrets
CI identity: short-lived credential, least privilege
cache: disposable speed-up · artifact: immutable release input
# database
expand → deploy compatible code → backfill → switch reads → contract later
# release
rolling: simple, versions overlap
blue-green: quick switch, double capacity
canary: production evidence, automatic stop rules
# failure order
first failed command → first concrete error → clean local reproduction
→ compare runner, versions, permissions, cache, artifact digest
# rollback
keep previous digest · test the command · preserve database compatibilityMi versión con opinión: optimiza para releases aburridos. Un pipeline de diez minutos que produce un artefacto trazable es mejor que un pipeline de dos minutos que ocasionalmente despliega contenido de caché rancio. Un rollback de un comando es mejor que una estrategia elaborada que nadie ha ensayado. CI/CD tiene éxito cuando enviar un cambio pequeño se siente rutinario y detener uno malo se siente inmediato.