DevOps, CI/CD y contenedores

Pipelines de entrega continua: etapas, artefactos y estrategias de despliegue

Intermedio10 min de lecturaActualizado

Esta página se tradujo del inglés con ayuda de IA y se cotejó con el original. Leer la versión en inglés

Un pipeline de despliegue es el camino automatizado que va de un commit a una release en ejecución, y cada etapa aporta más confianza en que el cambio es seguro. Esta guía explica cómo diseñar las etapas, por qué el artefacto se construye una sola vez y se promueve de un entorno a otro, cómo versionar las releases y hacer evolucionar el esquema de la base de datos sin cortes de servicio, y cuándo elegir un despliegue rolling, blue-green o canary.

Lo que aprenderás

  • Distinguir entre integración continua, entrega continua y despliegue continuo
  • Diseñar un pipeline cuyas etapas compilen una sola vez y promuevan el mismo artefacto por todos los entornos
  • Versionar los artefactos con versionado semántico y guardarlos en un repositorio de artefactos
  • Aplicar migraciones de base de datos expand-and-contract que sigan siendo compatibles con la versión en ejecución
  • Elegir entre despliegue rolling, blue-green y canary, y planificar el rollback

La integración continua demuestra que el código compila y que sus tests pasan. Es necesario, pero ni de lejos suficiente para una release: el artefacto empaquetado todavía tiene que configurarse para un entorno, desplegarse junto a una base de datos cuyo esquema quizá deba cambiar, verificarse contra las dependencias reales y ponerse a recibir tráfico real sin perder peticiones. Un pipeline de despliegue automatiza ese camino del commit a producción, y cada etapa añade pruebas de que el cambio es seguro. La entrega continua es el estado en el que el pipeline es lo bastante fiable como para que cualquier build en verde pueda publicarse pulsando un botón; el despliegue continuo es cuando quitas el botón. Esta guía trata sobre cómo diseñar ese pipeline.

Entrega, despliegue y qué significa «publicable»

Hay tres términos que se confunden a menudo:

  • Integración continua — cada merge se compila y se prueba automáticamente.
  • Entrega continua — cada build que supera el pipeline se empaqueta, se versiona y se verifica en entornos similares a producción, de modo que puede publicarse en cualquier momento mediante una decisión manual.
  • Despliegue continuo — cada build que supera el pipeline se publica en producción automáticamente.

La distancia entre el segundo y el tercero es una decisión de negocio, no técnica. Lo que no es opcional es la función del pipeline: mostrar, para cada commit, si es publicable, y convertir la publicación en una acción rutinaria en lugar de un acontecimiento. Si publicar todavía implica una hoja de cálculo de pasos manuales y un fin de semana perdido, lo que tienes es un servidor de CI, no entrega continua.

Las etapas de un pipeline

Un pipeline hace pasar un mismo cambio por etapas que sacrifican velocidad a cambio de confianza. Una secuencia representativa para un servicio de backend:

EtapaEntornoPropósitoControl
CommitRunner de CICompilación, tests unitarios, análisis estático, empaquetado, publicación del artefactoAutomático
IntegraciónRunner de CI con contenedoresTests contra una base de datos y un broker reales y contra los contratos de los servicios de los que dependeAutomático
AceptaciónEntorno de pruebas dedicado, desplegado a partir del artefactoTests funcionales de extremo a extremo, análisis de seguridadAutomático
Staging / preproducciónDimensionamiento y forma de los datos similares a producciónTests de rendimiento, smoke tests, pruebas exploratorias manuales si hacen faltaAutomático o aprobación manual
ProducciónRealDespliegue progresivo, verificación de salud, rollback si fallaAprobación manual (entrega) o automático (despliegue)

Hay dos propiedades que importan más que la lista exacta. Primero, las etapas se ejecutan en orden y con semántica fail-fast: un fallo en la etapa de commit implica que no se ejecuta nada posterior, de modo que los fallos baratos se notifican en minutos y no se desperdician los entornos caros. Segundo, todas las etapas posteriores a la primera trabajan sobre el mismo artefacto, desplegado con la misma automatización que se usa en producción. Desplegar en el entorno de aceptación con el script de despliegue de producción es, precisamente, la prueba de ese script.

Compilar una vez, promover a todas partes

La regla que condiciona todo lo demás: construye el artefacto una sola vez y luego promuévelo. La etapa de commit produce un jar, una imagen de contenedor o un zip de archivos estáticos —con una versión única— y lo sube a un repositorio de artefactos. Las etapas posteriores descargan ese artefacto exacto por su versión y lo despliegan. No se recompila nada.

Consecuencias:

  • El artefacto no debe contener valores específicos de ningún entorno. Las URL de base de datos, las credenciales, los feature flags y los nombres de host se inyectan en el momento del despliegue mediante variables de entorno, archivos de configuración montados o un servicio de configuración. Es exactamente el principio «config» de las aplicaciones twelve-factor.
  • El artefacto necesita un sitio estable: Sonatype Nexus, JFrog Artifactory, GitHub Packages o un registro de contenedores como Harbor o Amazon ECR. El repositorio es la fuente de verdad sobre qué existe y qué se ha desplegado dónde.
  • El artefacto debe ser inmutable. Volver a publicar la versión 2.3.1 con un contenido distinto es mentir a todos los entornos que ya la descargaron. Los registros de contenedores lo garantizan con digests (sha256:…), y los repositorios de artefactos con repositorios «release» que rechazan sobrescrituras.
  • La trazabilidad se vuelve trivial: una versión corresponde a un commit, a un número de build y a un conjunto de despliegues.

Versionado

Elige un esquema y aplícalo de forma mecánica. Hay dos que dominan.

El versionado semántico (MAJOR.MINOR.PATCH) comunica compatibilidad: un patch corrige bugs, una minor añade funcionalidades compatibles hacia atrás y una major rompe la compatibilidad. Es la opción adecuada para bibliotecas y para cualquier API de la que dependan otros equipos. Las versiones preliminares llevan un sufijo —2.4.0-rc.1— y los metadatos de build, un sufijo con +.

Las versiones basadas en el número de build o en el commit (1.0.437, 2026.09.07-a1b2c3d) encajan en servicios que solo se despliegan y nunca se consumen como dependencia. La versión responde a «¿qué commit es este?» en lugar de a «¿qué ha roto?».

Sea cual sea el esquema, quien asigna la versión es el pipeline, no el editor de un desarrollador. En Maven eso significa quitar -SNAPSHOT en el momento de la release con el release plugin, versions:set o la propiedad CI-friendly ${revision}; para contenedores significa etiquetar la imagen con la versión y llevar el digest al manifiesto de despliegue.

# CI-friendly Maven versioning: the pipeline supplies the revision
mvn -B -Drevision=1.4.$BUILD_NUMBER deploy

# Tag the image twice: a human-readable version and the commit
docker build -t registry.example.com/shop/orders:1.4.$BUILD_NUMBER \
             -t registry.example.com/shop/orders:$GIT_COMMIT .
docker push --all-tags registry.example.com/shop/orders

Migraciones de base de datos

Las bases de datos son la parte más difícil de la entrega continua, porque un esquema, a diferencia de un contenedor, no se puede sustituir sin más. En el mundo Java dominan dos herramientas —Flyway (scripts SQL versionados) y Liquibase (changelogs en XML, YAML o SQL)— y ambas funcionan igual: los scripts de migración viven en el control de versiones junto al código, cada uno lleva una versión, la herramienta registra en una tabla de metadatos cuáles se han aplicado y, al arrancar o como paso del pipeline, aplica en orden los que faltan.

-- src/main/resources/db/migration/V12__add_order_channel.sql
ALTER TABLE orders ADD COLUMN channel VARCHAR(20);
UPDATE orders SET channel = 'web' WHERE channel IS NULL;

La disciplina que hace seguras las migraciones es expand and contract. Un cambio de esquema que la versión anterior del código no tolera rompe los despliegues rolling (las instancias antiguas y nuevas se ejecutan a la vez) y hace imposible el rollback. Así que divide cada cambio incompatible en pasos compatibles:

  1. Expandir

    Añade la columna, tabla o índice nuevo sin eliminar nada. La versión en ejecución lo ignora.
  2. Desplegar código que escriba en ambas

    La nueva versión escribe en la estructura antigua y en la nueva, y lee de la antigua. El rollback es seguro: el código antiguo sigue encontrando todo lo que necesita.
  3. Rellenar los datos

    Una migración o un proceso batch copia los datos históricos a la nueva estructura.
  4. Desplegar código que lea la nueva estructura

    Ahora nada depende de la columna antigua salvo la doble escritura.
  5. Contraer

    En una release posterior, deja de escribir en la estructura antigua y elimínala.

Esto requiere más releases que un simple ALTER TABLE ... RENAME, y precisamente de eso se trata: cada release es pequeña, compatible con la anterior y la siguiente, y reversible.

Estrategias de despliegue

Con el artefacto y el esquema listos, la última etapa consiste en cambiar el tráfico. Las estrategias se diferencian en coste de capacidad, exposición y rapidez del rollback.

Recreate detiene la versión antigua y después arranca la nueva. Es sencillo, y es la única opción cuando dos versiones realmente no pueden coexistir, pero implica un corte de servicio. Aceptable para sistemas batch internos, no para una API pública.

Rolling sustituye las instancias unas pocas cada vez —los Deployments de Kubernetes lo hacen por defecto, controlados por maxSurge y maxUnavailable—. Sin cortes y sin capacidad adicional, pero la versión antigua y la nueva sirven tráfico a la vez mientras dura el despliegue, así que el cambio debe ser compatible en ambos sentidos (algo que la disciplina expand-and-contract garantiza).

# Deployment excerpt: rolling update that never drops below full capacity
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2          # up to 8 pods during the rollout
      maxUnavailable: 0    # never fewer than 6 ready pods
  template:
    spec:
      containers:
        - name: orders
          image: registry.example.com/shop/orders@sha256:3f1c…   # immutable reference
          readinessProbe:
            httpGet: { path: /actuator/health/readiness, port: 8080 }

La readiness probe es lo que hace seguro el rolling: Kubernetes solo envía tráfico a un pod nuevo cuando la sonda responde correctamente, y solo retira uno antiguo cuando hay suficientes pods nuevos listos.

Blue-green mantiene dos entornos completos. Blue sirve producción; green recibe la nueva versión, pasa los smoke tests y, a continuación, el router o el balanceador de carga desvía todo el tráfico a green. Hacer rollback es volver a cambiar. Los costes son el doble de capacidad durante el cambio y una base de datos compartida por ambos colores, lo que de nuevo exige cambios de esquema compatibles.

Canary envía un pequeño porcentaje del tráfico (1 %, luego 10 %, luego 50 %) a la nueva versión mientras vigila la tasa de errores y la latencia, y avanza o aborta automáticamente. Es la estrategia de menor riesgo para servicios de cara al usuario, pero exige buenas métricas y una capa que reparta el tráfico: un service mesh, un ingress controller con enrutamiento ponderado o una herramienta como Argo Rollouts o Flagger.

Los feature flags son ortogonales: el código se despliega para todo el mundo, pero la funcionalidad permanece desactivada hasta que un flag la activa para un grupo de usuarios. Los flags desacoplan el despliegue de la publicación y permiten un «rollback» instantáneo cambiando el flag, a cambio de rutas de código muerto que tarde o temprano habrá que limpiar.

Rollback y verificación

Todo pipeline necesita una respuesta a «¿qué pasa cuando producción falla?» que se mida en minutos, no en un gabinete de crisis.

  • Haz un roll forward redesplegando el artefacto anterior. Como los artefactos son inmutables y están versionados, la versión anterior es una entrada conocida y sana para el mismo paso de despliegue. kubectl rollout undo hace esto para un Deployment; en blue-green basta un cambio en el router.
  • Nunca hagas rollback de la base de datos. Con expand-and-contract, el código anterior funciona con el esquema nuevo; una «down migration» sobre datos de producción es mucho más arriesgada que el bug del que intentas escapar.
  • Automatiza la comprobación de salud tras el despliegue. Un smoke test que llame a unos cuantos endpoints y un breve periodo de observación de la tasa de errores detectan la mayoría de las releases defectuosas antes de que las reporte un usuario. Argo Rollouts y Flagger automatizan la cancelación; un pipeline más sencillo puede ejecutar un script y hacer fallar la etapa.

Aprobaciones y cumplimiento normativo

Los entornos regulados suelen exigir un aprobador independiente, una pista de auditoría y un registro de cambios. Un pipeline cumple estos requisitos mejor que una reunión: el paso input de un pipeline de Jenkins o una regla de protección de entorno en GitHub registra quién aprobó qué y cuándo, la versión del artefacto y el commit forman parte del log, y el propio script de despliegue está versionado y se puede revisar. Lo que necesitan los auditores es evidencia de control, y un pipeline automatizado genera más evidencia de la que jamás generó un proceso manual.

Errores comunes

  • Builds específicos por entorno. Un mvn package -Pprod que incrusta las URL de producción en el jar significa que staging probó otra cosa. Externaliza la configuración.
  • Artefactos snapshot en producción. Una 1.4-SNAPSHOT puede cambiar sin que te enteres entre staging y producción. Solo versiones release.
  • Pasos manuales escondidos en el pipeline. Una etapa que dice «ejecuta el script SQL del ticket» no está automatizada. Si una persona tiene que hacer algo, el pipeline debería hacerlo por ella y dejarlo registrado.
  • Probar el despliegue por primera vez en producción. Despliega en cada entorno previo con la automatización de producción. Los scripts de despliegue también tienen bugs.
  • Las down migrations como plan de rollback. Rara vez se prueban y con frecuencia son destructivas. Diseña en su lugar cambios de esquema compatibles hacia delante.
  • Desplegar en rolling sin readiness checks. Un rolling update en el que cada pod se declara listo en cuanto arranca el proceso sirve errores desde instancias que aún no han terminado de calentarse. Conecta la readiness probe a algo que tenga sentido.
  • Dar el pipeline por terminado. El lead time va creciendo a medida que se añaden etapas. Mide el tiempo del commit a producción y elimina las esperas.

Conclusiones clave

  • Un pipeline de despliegue es la secuencia ordenada y automatizada de etapas que demuestra que cada commit es publicable; la entrega continua consiste en tener ese pipeline, y el despliegue continuo, en dejar que publique sin preguntar.
  • Construye el artefacto una sola vez, versiónalo, guárdalo de forma inmutable y promueve los mismos bytes por todos los entornos, inyectando la configuración en el momento del despliegue.
  • Asigna las versiones en el pipeline: versionado semántico para todo aquello de lo que dependan otros, versiones basadas en el build o el commit para lo que solo se despliega.
  • Aplica los cambios de base de datos como migraciones versionadas en pasos expand-and-contract, para que dos releases consecutivas sean compatibles en ambos sentidos y el rollback nunca toque el esquema.
  • Elige la estrategia de despliegue según el riesgo y la capacidad: rolling para la mayoría de los servicios, blue-green para un cambio y un rollback instantáneos, canary cuando las métricas permiten juzgar una parte del tráfico.
  • Hacer rollback es redesplegar el artefacto anterior en minutos; verifica automáticamente cada despliegue con smoke tests y monitorización de la tasa de errores.

Fuentes y lecturas recomendadas

Preguntas frecuentes

¿Qué diferencia hay entre entrega continua y despliegue continuo?
Entrega continua significa que cada cambio que supera el pipeline está demostrado como desplegable y puede pasar a producción con una sola acción, pero es una persona quien decide cuándo. El despliegue continuo elimina esa decisión: cada build en verde se publica automáticamente. La entrega es un requisito previo del despliegue; muchos equipos regulados o de cara al cliente se quedan en la entrega a propósito para poder elegir el momento de cada release.
¿Por qué no debo recompilar la aplicación para cada entorno?
Porque entonces el artefacto que probaste en staging sería distinto del que ejecutas en producción: otra ejecución del compilador, quizá otra resolución de dependencias y cualquier valor específico del entorno incrustado dentro. Construye un único artefacto, guárdalo con una versión e inyecta las diferencias entre entornos en el momento del despliegue mediante configuración. Así, una ejecución en verde en staging es una prueba sobre los bytes exactos que van a producción.
¿Cómo despliego un cambio en la base de datos sin cortes de servicio?
Divídelo en pasos compatibles hacia atrás. Primero añade la columna o tabla nueva, despliega código que escriba en la estructura antigua y en la nueva, rellena los datos, despliega código que lea solo de la nueva ubicación y elimina la estructura antigua en una release posterior. Cada despliegue es compatible con la versión anterior del código, así que un rollback nunca necesita revertir el esquema.
¿Cuándo conviene más una canary release que un blue-green?
Usa un canary cuando puedas observar la tasa de errores y la latencia de la nueva versión sobre una parte del tráfico real y quieras que el riesgo crezca de forma gradual. Blue-green es más sencillo y ofrece un cambio y un rollback instantáneos, pero expone a todos los usuarios a la vez y necesita el doble de capacidad durante el cambio. Si no tienes métricas lo bastante buenas para juzgar un canary, blue-green con un rollback rápido es la opción más segura.