Seis lecciones, seis herramientas y el mismo pipeline de Reservalia traducido seis veces. Si has llegado hasta aquí esperando que esta lección diga cuál es la mejor, la respuesta va a decepcionar y a la vez es lo más útil que puede darte el módulo: la pregunta está mal planteada. No porque sea de mal gusto comparar —vamos a comparar en detalle—, sino porque "la mejor herramienta" no es una propiedad de la herramienta: es una propiedad de la relación entre la herramienta y un contexto concreto, con su código, su equipo, sus restricciones legales, su presupuesto y lo que ya sabe operar. Esta lección hace cuatro cosas: recapitula el pipeline de Reservalia en las herramientas vistas y fija una tabla de equivalencias de vocabulario que te servirá el resto de tu carrera; compara por dimensiones, sin ganadores globales; ordena los criterios de decisión por su peso real, que es muy distinto del peso que se les da en las discusiones de equipo; y trata lo que casi nunca se trata: cuánto cuesta cambiar de herramienta, cómo reducir ese coste antes de necesitarlo, y cómo migrar sin parar al equipo.
Contenido
- Por qué "¿cuál es la mejor?" está mal planteada
- El mismo pipeline, seis veces: recapitulación
- Tabla de equivalencias de vocabulario
- Comparativa por dimensiones
- Los criterios de decisión, ordenados por peso real
- Un árbol de decisión
- Coste total de propiedad, con números
- El coste de cambiar de herramienta y cómo reducirlo
- Migración entre herramientas, por fases
- Elegir por moda, o por lo que usaba tu antigua empresa
- Errores Comunes y Consejos
- Ejercicios
- Conclusión y cierre del módulo
- Por qué "¿cuál es la mejor?" está mal planteada
La pregunta supone que existe un orden total entre herramientas que resuelven el mismo problema. No existe, por tres razones concretas.
Primera: las herramientas convergen. Compara lo que hacen hoy las seis y verás que el 80 % coincide: pipeline definido en un fichero del repositorio, jobs con dependencias, ejecución en contenedores, caché, artefactos, matrices, secretos, aprobaciones, identidad federada. Las diferencias reales están en el 20 % restante y en cómo se sienten al usarlas. Elegir por una lista de funcionalidades produce empates constantes.
Segunda: el coste dominante no es la herramienta, es el contexto. Migrar de una a otra cuesta semanas; operar una instalación autoalojada cuesta media persona; formar al equipo cuesta meses de fluidez. Comparado con eso, que una tenga mejor sintaxis de matriz es ruido.
Tercera: la mayoría de las decisiones ya están tomadas cuando llega la pregunta. Si el código está en GitHub, la identidad del equipo está en GitHub y la protección de ramas está en GitHub, elegir otro CI significa mantener una integración adicional para siempre. Eso no lo compensa casi ninguna ventaja técnica.
Las preguntas bien planteadas son estas, y el resto de la lección las responde:
| Pregunta útil | Dónde se responde |
|---|---|
| ¿Qué restricciones no negociables tengo? (datos, red, hardware, cumplimiento) | Apartado 5, criterio 2 |
| ¿Dónde vive mi código y mi identidad? | Apartado 5, criterio 1 |
| ¿Qué sabe operar mi equipo hoy, y qué está dispuesto a operar? | Apartado 5, criterio 3 |
| ¿Cuál es el coste total, incluidas las personas? | Apartado 7 |
| ¿Qué me costaría cambiar dentro de tres años, y cómo lo reduzco ya? | Apartado 8 |
Y una pregunta que no es útil: "¿cuál es más potente?". Todas son suficientemente potentes para el 95 % de los pipelines. La potencia deja de ser el factor limitante muy pronto.
- El mismo pipeline, seis veces: recapitulación
El pipeline de Reservalia —instalar con caché → lint y test en paralelo con sharding → build de imagen → escaneo → publicar por digest → desplegar con aprobación— expresado en cada herramienta, y qué reveló cada traducción:
| Herramienta | Cómo quedó | Qué reveló la traducción |
|---|---|---|
| GitHub Actions (base) | needs, matrix, composite action, reusable workflow, OIDC, Environments |
El punto de referencia del curso |
| Jenkins (06-01) | Jenkinsfile declarativo: stages, parallel, matrix, stash, input, post |
El grafo es implícito (árbol, no DAG); el input retiene ejecutor si no se cuida; el stash pasa por el controlador |
| GitLab CI (06-02) | stages + needs, parallel, services, environment, registro integrado |
La distinción cache/artifacts es explícita; el registro y las credenciales vienen regalados; rules gobierna todo |
| CircleCI (06-03) | workflows con requires, parallelism, commands, orbs, contexts |
Caché totalmente manual; workspace ≠ caché ≠ artefactos; reparto por tiempos históricos que las demás no traen |
| Travis CI (06-04) | stages + jobs.include, fases fijas |
No cabe del todo: sin grafo, sin paso de artefactos entre jobs, sharding copiado cuatro veces, promoción por digest comprometida |
| Kubernetes (06-05) | No es CI: es el destino. Deployment por digest, sondas, rollout undo, GitOps |
Cambia quién inicia el despliegue y saca las credenciales del CI |
La conclusión del ejercicio es la que justifica haberlo hecho seis veces: el pipeline es el mismo problema en todas partes. Instalar de forma reproducible, verificar en paralelo, construir un artefacto inmutable, escanearlo, publicarlo identificado por su contenido y promocionarlo con una puerta. Lo que cambia es la sintaxis, el nombre de las piezas y qué te regala la herramienta. Quien entiende el problema traduce a cualquier sintaxis en días; quien solo conoce una sintaxis empieza de cero cada vez.
- Tabla de equivalencias de vocabulario
Esta tabla es probablemente lo más reutilizable de la lección. Guárdala.
| Concepto | GitHub Actions | GitLab CI | Jenkins | CircleCI | Travis CI |
|---|---|---|---|---|---|
| Fichero de definición | .github/workflows/*.yml |
.gitlab-ci.yml |
Jenkinsfile |
.circleci/config.yml |
.travis.yml |
| Ejecución completa | Workflow run | Pipeline | Build / Run | Pipeline | Build |
| Unidad con máquina propia | Job | Job | Stage con agent |
Job | Job de la matriz |
| Agrupación lógica | (no existe) | Stage | Stage | (no existe) | Stage |
| Comando individual | Step | Línea de script |
Step | Step | Fase (script, install…) |
| Máquina ejecutora | Runner | Runner (+ executor) | Agent / node | Executor | Worker |
| Ranura de concurrencia | (implícito) | concurrent |
Executor | (implícito) | (implícito) |
| Dependencia entre unidades | needs |
needs / stages |
Orden de stages |
requires |
Orden de stages |
| Ejecución paralela | matrix, jobs |
parallel, jobs |
parallel |
parallelism, jobs |
Entradas de matriz |
| Caché de dependencias | actions/cache |
cache: |
Plugin / volumen | save_cache/restore_cache |
cache: |
| Paso de ficheros entre unidades | Artefactos | artifacts |
stash/unstash |
Workspace | (no existe) |
| Salida descargable | Artefactos | artifacts |
archiveArtifacts |
store_artifacts |
(externo) |
| Salida de valores | outputs |
reports:dotenv |
env / script |
(fichero + workspace) | (no existe) |
| Servicio auxiliar | services: |
services: |
Contenedor del pod | Contenedor secundario | services: |
| Secretos | secrets |
Variables protegidas | Credentials + withCredentials |
Contexts / variables | secure: |
| Identidad federada | OIDC (id-token) |
id_tokens |
Plugin / rol de instancia | OIDC | (no) |
| Reutilización de pasos | Composite action | extends / include |
Shared Library (vars/) |
Command | (anchors YAML) |
| Reutilización de jobs | Reusable workflow | Componente / include |
Shared Library | Orb | (no) |
| Registro de plantillas | Marketplace | Catálogo de componentes | Repositorio de librería | Registro de orbs | (no) |
| Entorno de despliegue | environment |
environment |
(plugin) | (no modelado) | (no) |
| Aprobación manual | Revisores de Environment | when: manual |
input |
type: approval |
(no) |
| Cancelar obsoletos | concurrency |
interruptible |
disableConcurrentBuilds |
Auto-cancel | (no) |
| Filtro por rutas | paths |
rules: changes |
when { changeset } |
(lógica propia) | (no) |
Dos observaciones que se leen entre líneas. Primero, la columna de Travis tiene muchos huecos, y eso no es un descuido: es la diferencia entre una herramienta de CI y una de CI/CD, y explica su declive mejor que cualquier análisis de mercado. Segundo, "job" significa cosas distintas: en Jenkins un job es lo que en las demás es un workflow, mientras que la unidad con máquina propia es el stage con agente. Es la confusión de vocabulario que más malentendidos causa en equipos mixtos.
- Comparativa por dimensiones
Sin ganadores globales: cada fila es una dimensión y lo relevante es cuáles te importan a ti.
| Dimensión | GitHub Actions | GitLab CI | Jenkins | CircleCI | Travis CI |
|---|---|---|---|---|---|
| Modelo de ejecución | Grafo (needs) |
Etapas → grafo | Árbol con paralelo anidado | Grafo desde el origen | Fases fijas |
| Alojamiento | SaaS + runners propios | SaaS o autoalojado completo | Solo autoalojado | SaaS + runners propios | SaaS |
| Configuración | Código | Código | Código (con herencia de UI) | Código | Código |
| Reutilización | Composite + reusable + marketplace | extends/include/componentes |
Shared Libraries | Orbs con versionado inmutable | Muy limitada |
| Secretos e identidad federada | OIDC nativo, entornos | OIDC nativo, variables protegidas | Plugins; no nativo | OIDC, contexts | Cifrado en repo |
| Ecosistema | El mayor | Medio, integrado | El más amplio en integraciones raras | Medio | Residual |
| Plataforma integrada | Alta (repo, registro, issues) | La más completa | Ninguna: pieza suelta | Ninguna: pieza suelta | Ninguna |
| macOS / ARM / GPU | Sí (macOS caro) | Con runners propios | Cualquier cosa que tengas | Amplia oferta | ARM y arquitecturas raras |
| Madurez de despliegue y aprobaciones | Environments con reglas | Entornos con historial y on_stop |
input, sin modelo de entorno |
type: approval, sin entorno |
Proveedores deploy |
| Observabilidad del pipeline | Media (resúmenes, tiempos) | Buena | Depende de plugins | La mejor | Escasa |
| Modelo de coste | Minutos + almacenamiento | Por usuario + minutos | Infraestructura + personas | Créditos + usuarios | Créditos |
| Coste de salida | Medio | Alto (repo + CI + registro) | Medio | Bajo | Bajo |
Cómo leer esta tabla sin equivocarse: una fila solo importa si es un requisito tuyo. "Plataforma integrada: la más completa" es una ventaja enorme si buscas plataforma y una desventaja si ya tienes un ecosistema montado y solo quieres CI. "Solo autoalojado" es descalificante para un equipo de tres y es exactamente lo que necesita una empresa con datos que no pueden salir. No hay una columna que gane más filas y por tanto gane.
- Los criterios de decisión, ordenados por peso real
Aquí está el contenido más valioso de la lección, y el orden importa más que la lista.
Criterio 1 — Dónde viven el código y la identidad del equipo (decide ~80 % de los casos)
Si tu código está en GitHub y tu equipo se autentica con GitHub, GitHub Actions parte con una ventaja que casi nada compensa. Si está en GitLab, lo mismo con GitLab CI. No es pereza: es que usar un CI externo implica, para siempre:
- Una integración de permisos que mantener y que se rompe cuando alguien rota un token.
- Sincronización de identidades: quién puede desplegar hay que definirlo dos veces, y las dos definiciones divergen.
- Dos sitios donde mirar cuando algo falla, y un salto de contexto en cada incidente.
- Checks que llegan desde fuera y una protección de rama que depende de una integración.
Ese coste es permanente y silencioso. La ventaja técnica que lo justifique tiene que ser grande y concreta. Este criterio no es un empate a romper: es el punto de partida, y las demás herramientas tienen que ganárselo.
Corolario incómodo: si tu código está en GitHub y estás evaluando cinco herramientas de CI, probablemente estás resolviendo el problema equivocado. Empieza por la integrada, identifica qué te falta con nombres concretos y solo entonces mira fuera.
Criterio 2 — Restricciones de cumplimiento y datos (decide, cuando aplica, sin discusión)
Si existe una restricción legal o contractual real, manda sobre todo lo demás. Las preguntas que hay que hacer antes de nada:
- ¿El código fuente puede salir de nuestra red? ¿Y los logs, que a menudo contienen más de lo que parece?
- ¿Los datos de prueba contienen información personal o regulada?
- ¿Hay obligación de retención de auditoría, con quién aprobó qué y cuándo?
- ¿Se exige separación de funciones —que quien escribe el cambio no sea quien lo aprueba—?
- ¿Hay requisito de residencia de datos en una jurisdicción concreta?
Aviso importante y frecuente: un runner autoalojado de un SaaS no satisface una restricción estricta. El trabajo corre en tu red, sí, pero el plano de control, la orquestación, los logs y a menudo los secretos siguen en un tercero. Si la exigencia es literal, la respuesta es autoalojar la plataforma entera: Jenkins o GitLab autoalojado. Y la primera acción no es técnica: es leer el contrato o la norma, porque la mitad de las veces la restricción es menos estricta de lo que el equipo asume, y la otra mitad es más.
Criterio 3 — Qué sabe operar el equipo hoy
Una herramienta que nadie sabe operar es peor que una menos capaz que el equipo domina. Un Jenkins sin dueño se degrada solo (06-01); un clúster de Kubernetes mal operado es peor que ECS (06-05).
Preguntas concretas, con nombres y apellidos:
- ¿Quién actualiza esto? ¿Qué deja de hacer mientras?
- ¿Quién responde a las tres de la mañana si el CI cae durante una incidencia?
- ¿Quién restaura la copia de seguridad, y cuándo se ensayó por última vez?
- ¿Qué pasa cuando esa persona se va de vacaciones o de la empresa?
Si no hay respuesta a alguna, la opción autoalojada no está sobre la mesa por mucho que técnicamente convenza. Para Reservalia —Marta, Diego y Nuria— la respuesta es evidente y no requiere análisis: SaaS.
Criterio 4 — Necesidades de hardware y plataforma
macOS para compilar iOS (05-02), GPU para modelos, ARM nativo, dispositivos físicos, licencias atadas a una máquina, mucha memoria. Aquí el orden se invierte: si hay una necesidad de hardware que solo cubre una opción, esa opción entra sí o sí, aunque sea solo para esa parte del pipeline. El patrón habitual y sensato es híbrido: la herramienta principal para todo, y una pieza específica donde el hardware lo obliga.
Criterio 5 — Presupuesto y su forma
No solo cuánto, también de qué tipo:
| Forma del coste | Herramientas | Implicaciones |
|---|---|---|
| Opex variable (por minuto/crédito) | Actions, CircleCI, GitLab SaaS | Crece con la actividad; sin inversión inicial; sorpresas si nadie vigila |
| Opex por usuario | GitLab, en parte CircleCI | Predecible; castiga a colaboradores ocasionales |
| Capex + opex de personas | Jenkins, GitLab autoalojado | Coste inicial y personas fijas; predecible; independiente de la actividad |
Este criterio se cruza con el 3: el coste de las personas es real aunque no aparezca en ninguna factura, y es precisamente el que más se olvida en las hojas de cálculo que comparan "X euros al mes de SaaS" con "una máquina que ya tenemos".
Criterio 6 — Madurez del equipo en CI/CD
Un equipo que empieza se beneficia de una herramienta opinada, con valores por defecto sensatos y mucha documentación. Un equipo maduro con necesidades particulares valora el control. Adoptar Jenkins con Shared Libraries y agentes en Kubernetes siendo tres personas que nunca hicieron CI es garantía de abandono; adoptar una herramienta muy opinada teniendo requisitos raros es garantía de pelear contra ella cada semana.
El resumen del orden
1. Restricciones no negociables → si las hay, filtran primero 2. Dónde vive el código → decide el 80 % de lo que queda 3. Quién opera → descarta opciones, no las elige 4. Hardware → añade piezas híbridas 5. Presupuesto y su forma → afina entre las supervivientes 6. Madurez → decide cuánta cuerda darse
Nótese que la calidad técnica de la herramienta no aparece en la lista. No porque dé igual, sino porque todas las supervivientes de los seis filtros son suficientemente buenas, y a esas alturas la decisión ya está tomada.
- Un árbol de decisión
flowchart TD
A["Elegir herramienta de CI/CD"] --> B{"Hay restriccion legal o contractual<br/>que impida usar un SaaS?"}
B -->|"Si"| C{"Quien opera la plataforma?"}
C -->|"Nadie con tiempo"| D["Resolver eso primero:<br/>no hay opcion viable sin operador"]
C -->|"Hay equipo"| E{"Se quiere plataforma completa<br/>o solo motor de automatizacion?"}
E -->|"Plataforma"| F["GitLab autoalojado"]
E -->|"Motor"| G["Jenkins"]
B -->|"No"| H{"Donde vive el codigo?"}
H -->|"GitHub"| I["GitHub Actions<br/>punto de partida"]
H -->|"GitLab"| J["GitLab CI/CD<br/>punto de partida"]
H -->|"Varios o Bitbucket"| K["CircleCI u otro SaaS<br/>independiente"]
I --> L{"Falta algo concreto<br/>con nombre?"}
J --> L
L -->|"No"| M["Quedarse. Invertir en el pipeline,<br/>no en elegir herramienta"]
L -->|"Velocidad de suite grande"| N["Evaluar CircleCI<br/>o mejorar lo actual primero"]
L -->|"Hardware especial"| O["Hibrido: runners propios<br/>o Jenkins solo para esa pieza"]
L -->|"Muchos servicios en Kubernetes"| P["Anadir GitOps: Argo CD o Flux<br/>no cambiar de CI"]
Dos ramas merecen comentario porque son las que más se equivocan en la práctica.
"Falta algo concreto con nombre": la exigencia de nombrarlo es deliberada. "Nos gustaría algo mejor" no es un requisito. "El job de e2e tarda 14 minutos por reparto desigual y no tenemos histórico de tiempos" sí lo es, y —fíjate— probablemente se arregla sin cambiar de herramienta.
"Muchos servicios en Kubernetes" lleva a añadir GitOps, no a cambiar de CI. Es un error muy común: el problema es el modelo de despliegue (06-05), no el motor de CI, y cambiar el segundo no arregla el primero.
- Coste total de propiedad, con números
Comparar "20 euros al mes" con "una máquina que ya tenemos" es la forma más habitual de equivocarse. El ejercicio correcto incluye las personas.
Escenario: equipo de 12 desarrolladores, 40 ejecuciones de pipeline al día, 12 minutos de cómputo por ejecución en 4 jobs paralelos ≈ 35 minutos-máquina por ejecución.
| Concepto | SaaS por minuto | Autoalojado |
|---|---|---|
| Cómputo | 29.400 min × tarifa por minuto | 3 máquinas siempre encendidas |
| Almacenamiento (artefactos, caché) | Facturado por GB | Discos y copias |
| Licencias | Incluido o por usuario × 12 | Según herramienta y nivel |
| Operación | ~0 h/mes | 8-16 h/mes: actualizaciones, plugins, agentes, incidencias |
| Guardia | 0 | Parte de una rotación, o alguien de facto |
| Puesta en marcha | Horas | 2-6 semanas de una persona |
| Coste de indisponibilidad | Del proveedor | Tuyo, y el equipo parado mientras dura |
La fórmula que hay que usar, y el número que casi siempre decide:
TCO_autoalojado = infraestructura + licencias
+ (horas_operación/mes × coste_hora_cargado)
+ amortización(puesta_en_marcha)
+ riesgo(indisponibilidad × frecuencia)
TCO_saas = cómputo + almacenamiento + licencias_por_usuario
+ horas_gestión_ligeraCon un coste cargado por hora de una persona de plataforma —salario más impuestos, herramientas y espacio—, 10 horas al mes de operación suelen superar por sí solas la factura completa de un SaaS para un equipo de este tamaño. Ese es el resultado que sorprende y el que hay que llevar a la conversación con quien decide. Y el punto de equilibrio se desplaza con el tamaño: con 200 desarrolladores y un uso muy intensivo, las mismas 10-20 horas mensuales se reparten entre mucho más consumo y lo autoalojado puede ganar con claridad.
Tres avisos para que el cálculo sea honesto:
- No inventes tarifas. Las de cada proveedor cambian por plan, región y tipo de máquina; consúltalas el día que hagas el cálculo y anota la fecha.
- Cuenta los multiplicadores. macOS y máquinas grandes no cuestan lo mismo por minuto; un pipeline con mucho macOS (05-02) cambia el resultado por completo.
- Incluye lo que el SaaS te ahorra en integraciones. Si la alternativa exige mantener sincronización de identidades y webhooks, eso son horas que van en la columna del autoalojado, no en ninguna.
- El coste de cambiar de herramienta y cómo reducirlo
Una migración de CI/CD en un repositorio real es de semanas, no de días, y el reparto del esfuerzo es sistemáticamente el mismo:
| Parte del pipeline | Coste de migrar | Proporción típica |
|---|---|---|
| Lógica de build, test, despliegue | Bajo si está en scripts; alto si está en el YAML | 40-60 % del contenido |
| Orquestación (jobs, dependencias, matriz, disparadores) | Reescritura mecánica | 20-30 % |
| Integraciones (acciones/orbs/plugins de terceros) | Reconstrucción | 10-20 % |
| Secretos e identidad federada | Reconfigurar y rotar | 5-10 % |
| Aprendizaje del equipo | Semanas de menor fluidez | Difuso y real |
La palanca que de verdad mueve ese número la anticipó la 06-04 y la merece repetir: saca la lógica del YAML y déjalo como orquestador delgado.
# Frágil: 60 líneas de lógica dentro del YAML de una herramienta concreta
- run: |
npm ci --prefer-offline
npx prettier --check .
npm run lint -- --max-warnings 0
npx tsc --noEmit
npm test -- --coverage --shard=${{ matrix.shard }}/4
node scripts/comprobar-cobertura.js --minimo 80# Makefile — interfaz estable, independiente de la herramienta
.PHONY: instalar calidad test build imagen
instalar:
npm ci --prefer-offline
calidad: instalar
npx prettier --check .
npm run lint -- --max-warnings 0
npx tsc --noEmit
test: instalar
npm test -- --coverage --shard=$(SHARD)/$(TOTAL)
node scripts/comprobar-cobertura.js --minimo 80
imagen:
docker buildx build --file apps/api/Dockerfile \
--cache-from type=registry,ref=$(ECR)/$(IMAGEN):cache \
--tag $(ECR)/$(IMAGEN):$(SHA) --push .# El YAML, en cualquier herramienta, se vuelve trivial
- run: make calidad
- run: make test SHARD=${{ matrix.shard }} TOTAL=4Beneficios, y este es el argumento importante: no dependen de que llegues a migrar.
- El desarrollador ejecuta exactamente lo mismo en local. Desaparece la clase entera de fallos "solo pasa en CI", que es de las que más tiempo consumen.
- La lógica es código revisable y testeable, no una cadena dentro de un YAML que nadie lee en el PR.
- El pipeline se vuelve legible: un
ci.ymlconmake calidadymake testse entiende de un vistazo. - Y sí, migrar pasa de semanas a días.
El límite honesto: no todo sale del YAML. Disparadores, matrices, permisos, entornos, aprobaciones, concurrencia y caché son propios de cada herramienta, y abstraerlos exige una capa de indirección que cuesta más de lo que ahorra. El objetivo razonable no es portabilidad total, sino que el grueso del esfuerzo de migración sea reescribir orquestación, no reconstruir lógica.
- Migración entre herramientas, por fases
Cuando la migración está decidida, el patrón que funciona es el mismo de la 05-04: incrementos con valor propio y sin congelar al equipo.
| Fase | Qué se hace | Cuándo pasar a la siguiente | Riesgo |
|---|---|---|---|
| 1. Inventario | Todos los workflows, qué hace cada uno, quién depende de él, qué secretos usa, qué integraciones tiene. Y qué está muerto | Cuando esté escrito y revisado | Ninguno; omitirla es el error clásico |
| 2. Pipeline paralelo | El nuevo se ejecuta junto al viejo en cada PR, sin ser obligatorio. Se comparan resultados | 2-3 semanas con resultados coincidentes | Coste doble de cómputo temporal |
| 3. Cambio de la señal obligatoria | El check obligatorio pasa a ser el nuevo; el viejo queda informativo | Cuando nadie mire ya el viejo | El más alto: aquí se descubre lo que faltaba |
| 4. Migrar el CD | Despliegue al final, y por entornos: primero staging, luego producción | Cuando staging lleve semanas estable | Alto: afecta a producción |
| 5. Retirada | Borrar el pipeline viejo, desactivar el servicio, revocar todos los secretos, actualizar documentación e insignias | — | Bajo, si las fases previas se hicieron |
Cuatro reglas que evitan los desastres habituales:
El CD se migra el último, siempre. El CI se puede duplicar sin consecuencias; un despliegue duplicado o a medias sí las tiene. Y dentro del CD, primero staging.
Nunca se migra todo a la vez en organizaciones con muchos repositorios. Se elige un repositorio piloto —representativo pero no crítico—, se aprende con él, se escribe una plantilla y se propaga.
Los secretos se rotan, no se copian. Es el momento natural para hacerlo y para descubrir cuáles ya no hacía falta que existieran. Y en la fase 5, revocar los del sistema viejo es parte de la migración, no un extra.
Qué no migrar, que es tan importante como qué migrar: workflows que nadie mira, jobs desactivados desde hace meses, integraciones con sistemas que ya no existen, matrices de versiones sin soporte, y la lógica que "estaba por si acaso". Una migración es la mejor ocasión que tendrás para borrar; desaprovecharla es trasladar la deuda intacta y añadirle el coste del traslado.
- Elegir por moda, o por lo que usaba tu antigua empresa
Dos sesgos que producen decisiones caras y que conviene nombrar en voz alta porque casi nunca se dicen.
El sesgo de la conferencia. Se ve una charla excelente sobre una herramienta en una empresa con 400 ingenieros, cinco personas de plataforma y un problema de escala que no tienes, y se concluye que es lo que hay que usar. La pregunta que lo desactiva: ¿qué problema mío, con nombre, resuelve esto que hoy no esté resuelto? Si no hay respuesta concreta, es admiración, no un requisito. Es la misma trampa que la 06-05 señalaba con Kubernetes, y la respuesta es idéntica: la complejidad se justifica con un problema, no con quién más la usa.
El sesgo del recién llegado. Alguien entra en el equipo desde una empresa donde usaban X y propone migrar a X. A veces tiene razón —trae experiencia real que el equipo no tiene—, pero el sesgo es predecible: conoce X en profundidad y la herramienta actual apenas, así que compara lo mejor de una con lo peor de la otra. La prueba que lo desactiva: pedirle que primero domine lo que hay y luego liste, con nombres, qué le falta. Si tras dos meses la lista sigue en pie y es concreta, la propuesta merece evaluación seria. La mayoría de las veces la lista se reduce a dos elementos, y ambos se resuelven configurando mejor lo que ya está.
Y una tercera trampa más sutil: cambiar de herramienta para no arreglar el pipeline. Un pipeline lento por flaky sin cuarentena, caché mal configurada y jobs sin timeout seguirá siendo lento en la herramienta nueva, con la diferencia de que ahora nadie sabe dónde mirar. Antes de evaluar alternativas, aplica lo de la 04-04: mide, separa cola de ejecución, y arregla lo tuyo. Si tras eso el problema persiste y es de la herramienta, ya tienes datos para la conversación.
Errores Comunes y Consejos
Comparar por lista de funcionalidades. Todas tienen casi todo. La decisión está en el contexto, no en la tabla.
Ignorar dónde vive el código. Es el criterio de más peso y el que más se subestima en las discusiones de equipo.
Contar solo la factura. Las horas de operación son coste real; en equipos medianos suelen superar al SaaS que se quería evitar.
Creer que un runner autoalojado satisface una restricción de cumplimiento. El plano de control sigue fuera. Lee la norma antes de diseñar.
Migrar el CD antes que el CI. El CI se duplica sin daño; un despliegue, no.
Migrar uno a uno sin aprovechar. Sin needs, sin arreglar la caché, sin borrar lo muerto: se traslada la deuda y se paga el traslado.
Copiar los secretos en vez de rotarlos. Y no revocar los del sistema viejo al terminar.
Elegir una herramienta que nadie va a operar. Un Jenkins sin dueño es peor que no tener CI, porque da una señal en la que la gente confía.
Confundir "más potente" con "mejor para nosotros". La potencia deja de ser el factor limitante muy pronto.
Consejo transversal que resume el módulo: invierte en entender el problema —artefacto inmutable, promoción por digest, puertas de calidad, feedback rápido, mínimo privilegio— y trata la herramienta como intercambiable. Quien domina el problema aprende una herramienta nueva en dos semanas; quien solo domina una sintaxis empieza de cero cada vez que cambia de trabajo.
Ejercicios
Ejercicio 1. Tres escenarios. Para cada uno, aplica los seis criterios en orden, recomienda una herramienta (o combinación) y justifica qué criterio fue decisivo y cuáles resultaron irrelevantes:
- (a) Startup de 6 personas, código en GitHub, aplicación web Node desplegada en Vercel y una API en ECS. Sin restricciones legales. Nadie quiere operar infraestructura.
- (b) Empresa de 300 personas en el sector sanitario. El código no puede salir de su red por contrato con sus clientes. Ya tienen Jenkins con 180 jobs freestyle. Equipo de plataforma de 4 personas. Quieren "modernizarse".
- (c) Empresa de producto de 40 personas, código en GitLab autoalojado, 12 microservicios en Kubernetes, aplicación móvil iOS y Android, y un equipo de plataforma de 2 personas que está desbordado.
Ejercicio 2. Calcula el TCO comparado para un equipo de 25 desarrolladores con 80 ejecuciones diarias de 15 minutos en 5 jobs paralelos. Compara SaaS por minuto frente a Jenkins autoalojado en máquinas propias. Enumera todas las partidas —incluidas las que no aparecen en ninguna factura— y explica qué supuesto tendría que cambiar para invertir el resultado.
Ejercicio 3. Marta te pide un plan: reducir la dependencia de Reservalia respecto a GitHub Actions sin migrar y sin parar el desarrollo. Propón las acciones concretas, su coste, su beneficio con independencia de que la migración llegue a ocurrir, y dónde está el punto en que dejar de invertir. Estima el antes y el después del coste de una migración hipotética.
Soluciones
Solución 1.
(a) Startup de 6 personas.
| Criterio | Resultado |
|---|---|
| 1. Restricciones | Ninguna → no filtra |
| 2. Código e identidad | GitHub → decisivo |
| 3. Quién opera | Nadie → descarta todo lo autoalojado |
| 4. Hardware | Nada especial → irrelevante |
| 5. Presupuesto | Repositorio privado, poco volumen: los minutos incluidos probablemente cubren |
| 6. Madurez | Baja: conviene lo opinado y bien documentado |
Recomendación: GitHub Actions, sin más análisis. Decisivos: criterios 2 y 3, que apuntan al mismo sitio. Irrelevantes: 4 y, casi, el 5. El consejo que acompaña a la recomendación es más valioso que ella: con 6 personas, el tiempo gastado en evaluar herramientas es tiempo robado al pipeline; usa lo integrado y dedica ese esfuerzo a poner puertas de calidad, despliegue automatizado y métricas DORA (01-05).
(b) Empresa sanitaria de 300 personas.
| Criterio | Resultado |
|---|---|
| 1. Restricciones | El código no sale de la red → decisivo, filtra primero: solo autoalojado |
| 2. Código e identidad | Depende de dónde esté; si es GitHub Enterprise Server o GitLab autoalojado, apunta a su CI integrado |
| 3. Quién opera | 4 personas: hay equipo. Viable |
| 4. Hardware | A verificar; en salud suele haber integraciones con sistemas antiguos |
| 5. Presupuesto | Capex + personas, ya asumido |
| 6. Madurez | Media-baja: 180 jobs freestyle indican prácticas de hace una década |
Recomendación: no elegir herramienta todavía. El diagnóstico es que "modernizarse" no significa cambiar de herramienta, significa pasar de freestyle a pipeline as code (04-05, 06-01), y eso se hace dentro de Jenkins, sin migrar nada. Plan por fases: (1) inventario de los 180 jobs, con la expectativa fundada de que un tercio está muerto; (2) Jenkinsfile en los 20 más usados, con pipeline paralelo al freestyle; (3) JCasC y agentes efímeros para acabar con la deriva de configuración; (4) Shared Library para lo repetido. Al terminar, si aún hay razones, se reevalúa GitLab autoalojado con datos reales sobre qué falta.
Decisivo: criterio 1, que descarta todo el SaaS. Irrelevante: cualquier comparación con GitHub Actions o CircleCI, que quedaron fuera en el primer filtro. Y la lección de método: la mayor mejora disponible aquí no requiere cambiar de herramienta, y proponer una migración habría gastado meses sin resolver el problema real, que es que la configuración vive en formularios de un servidor.
(c) Empresa de producto de 40 personas.
| Criterio | Resultado |
|---|---|
| 1. Restricciones | Ninguna declarada |
| 2. Código e identidad | GitLab autoalojado → GitLab CI es el punto de partida |
| 3. Quién opera | 2 personas desbordadas → el dato más importante |
| 4. Hardware | macOS para iOS → requiere solución específica |
| 5. Presupuesto | Ya pagan la instancia; el margen está en no añadir operación |
| 6. Madurez | Alta: 12 microservicios en Kubernetes |
Recomendación: quedarse en GitLab CI y no añadir ninguna herramienta, con tres acciones concretas. Para macOS, runners macOS gestionados por un tercero o el servicio SaaS de GitLab para esos jobs concretos: comprar máquinas Apple y operarlas con un equipo desbordado es exactamente lo que no se debe hacer (05-02). Para los 12 microservicios, include de un componente compartido anclado a versión, en vez de 12 ficheros divergentes (05-03, 04-05). Para Kubernetes, GitOps con Argo CD o Flux, que además saca las credenciales del clúster del CI (06-05).
Decisivo: criterio 3. El equipo de plataforma desbordado es la restricción que gobierna todas las decisiones, y cualquier recomendación que añada operación es incorrecta por definición, por buena que sea técnicamente. Irrelevante: comparar GitLab CI con CircleCI o Actions; ninguna ventaja compensaría añadir una integración externa a un equipo que no da abasto.
Solución 2.
Consumo: 80 × 21 × 15 × 5 = 126.000 minutos-máquina/mes ≈ 2.100 horas-máquina, que equivalen a unas 3 máquinas al 100 % de ocupación, y como la carga es en horario laboral, en la práctica hacen falta 5-6 máquinas para no tener cola en las horas punta.
| Partida | SaaS por minuto | Jenkins autoalojado |
|---|---|---|
| Cómputo | 126.000 min × tarifa vigente | 6 máquinas (ociosas por la noche y el fin de semana) |
| Almacenamiento | Artefactos y caché por GB | Discos, copias de seguridad, su almacenamiento |
| Red | Incluida | Tráfico de salida al descargar imágenes y dependencias |
| Licencias | Por usuario según plan | Jenkins es libre; sistema operativo y monitorización sí cuestan |
| Puesta en marcha | 1-2 días | 3-6 semanas de una persona |
| Operación mensual | 1-2 h (gestión ligera) | 12-20 h: actualizaciones, plugins, CVE, agentes, disco |
| Guardia | 0 | Parte de una rotación |
| Indisponibilidad | Del proveedor; sin control | Tuya; con 25 personas paradas mientras dura |
| Formación | Baja | Media: Groovy, plugins, JCasC |
| Ahorro nocturno | Automático (no se paga lo que no se usa) | Ninguno: las máquinas están encendidas igual |
Cálculo: con un coste cargado por hora de una persona de plataforma, 16 horas mensuales de operación suelen equivaler a una cifra del mismo orden que la factura entera del SaaS para este volumen, antes de contar máquinas, almacenamiento y puesta en marcha. Añadiendo la amortización de las 4-6 semanas iniciales durante el primer año, el autoalojado sale claramente por encima.
Qué supuestos invertirían el resultado:
- Un volumen mucho mayor. Con 500.000 minutos-máquina al mes, las horas de operación no crecen proporcionalmente y el coste por minuto propio baja mucho. Es la economía de escala que hace que las empresas muy grandes autoalojen.
- Hardware ya disponible y amortizado, con capacidad ociosa real y personal que ya lo opera para otras cosas.
- Una restricción de cumplimiento que haga irrelevante la comparación: entonces no es una decisión económica.
- Máquinas mucho más potentes o especializadas —GPU, mucha memoria— donde el multiplicador del SaaS es alto y una máquina propia se amortiza rápido.
- Jobs muy largos y continuos que mantengan las máquinas ocupadas también fuera del horario laboral, eliminando la ventaja de pagar solo por uso.
Conclusión defendible: para 25 desarrolladores y este volumen, SaaS, y el argumento decisivo no es la factura de cómputo —que puede incluso ser mayor— sino las 12-20 horas mensuales de una persona que no hay que dedicar a operar CI. Ese es el número que hay que llevar a la reunión.
Solución 3.
Objetivo bien planteado: no es "poder migrar", es reducir el acoplamiento a cambio de beneficios que rinden desde el primer día. Si una acción solo aporta valor en caso de migración, no entra en el plan.
| # | Acción | Coste | Beneficio inmediato (aunque nunca migremos) | Reducción del coste de migrar |
|---|---|---|---|---|
| 1 | Mover la lógica de los run largos a scripts/*.sh y npm scripts, con un Makefile como interfaz (make calidad, make test, make imagen) |
3 días | Ejecutable en local: desaparecen los fallos "solo en CI"; lógica revisable y testeable; ci.yml legible |
Alta |
| 2 | Sustituir acciones de terceros que solo envuelven una CLI por la CLI directa; fijar por SHA las que queden y documentar por qué está cada una | 2 días | Menos superficie de suministro (04-03); menos roturas por cambios ajenos | Media-alta |
| 3 | Documentar el contrato de despliegue: qué recibe desplegar.sh (digest, entorno), qué garantiza, cómo se verifica |
1 día | Cualquiera del equipo puede desplegar de emergencia sin el pipeline; es también el plan B de la 03-05 | Media |
| 4 | Registro de decisiones del pipeline: por qué OIDC, por qué Environments, por qué esta caché | 0,5 días | Onboarding y revisiones más rápidas; evita replantear lo mismo cada trimestre | Media |
| 5 | Prueba periódica: ejecutar make ci en una máquina limpia sin GitHub Actions |
0,5 días | Verifica que la portabilidad es real y no teórica; detecta dependencias ocultas del entorno del runner | Alta |
| — | Capa de abstracción sobre disparadores, entornos y permisos | Semanas | Ninguno | Baja |
Dónde parar: después del punto 5. La última fila es la frontera, y el criterio es explícito: una capa de abstracción sobre lo específico de la herramienta cuesta más que la migración que evitaría y añade indirección permanente que empeora la legibilidad —justo lo que la 04-05 advertía sobre extraer abstracciones prematuras—.
Antes y después:
| Hoy | Tras el plan (7 días de trabajo) | |
|---|---|---|
| Lógica en el YAML | ~55 % | ~10 % |
| Acciones de terceros | 11 | 4, fijadas por SHA y justificadas |
| Reproducible en local | Parcial | Sí, verificado periódicamente |
| Migración hipotética | 3-4 semanas | 5-8 días |
La frase para Marta, que es lo que hay que decir en la reunión: "Siete días de trabajo. La migración pasaría de un mes a una semana, pero eso es el efecto secundario: lo que compramos de verdad es que el equipo pueda ejecutar el pipeline en su portátil, que la lógica se revise como código y que el ci.yml se entienda de un vistazo. Si nunca migramos, sigue siendo rentable. Y no vamos más allá: construir una capa de abstracción sobre GitHub Actions costaría más que la migración que evitaría."
Conclusión y cierre del módulo
La conclusión del módulo se sostiene sobre una comprobación empírica que has hecho seis veces: el mismo pipeline de Reservalia cabe en todas las herramientas, porque el problema es el mismo en todas partes. Instalar de forma reproducible, verificar en paralelo con feedback rápido, construir un artefacto inmutable, escanearlo, publicarlo identificado por su contenido, promocionarlo por digest a través de una puerta y poder volver atrás. Lo que cambia es la sintaxis, el nombre de las piezas y qué te regala la plataforma. Por eso la tabla de equivalencias del apartado 3 vale más que cualquier tutorial de una herramienta concreta: te permite leer un .gitlab-ci.yml o un Jenkinsfile el primer día de un trabajo nuevo.
Lo que cada herramienta enseñó, y que se lleva uno aunque no vuelva a tocarla: Jenkins, que el control total se paga con operación real y que un motor de propósito general integra cualquier cosa a cambio de no traer nada resuelto. GitLab, que una plataforma integrada regala trazabilidad, credenciales y entornos, y cobra en acoplamiento. CircleCI, que la velocidad de un pipeline es un problema de ingeniería con soluciones concretas —reparto por tiempos, caché explícita, clases de recurso— y que la separación entre workspace, caché y artefactos aclara una confusión que dura años. Travis, que el modelo de fases fijas basta para CI y no para CD, que el negocio de tu proveedor puede cambiar bajo tus pies, y que un secreto confiado a un tercero es un secreto cuya seguridad no controlas. Docker y Kubernetes, que el sustrato importa tanto como el orquestador, que el digest manda sobre el tag, y que la complejidad se justifica con un problema y no con quién más la usa. Y GitHub Actions, que la herramienta que usas todos los días también tiene límites, asimetrías peligrosas y una superficie de suministro que hay que vigilar.
Los criterios, en el orden que importa: las restricciones no negociables filtran primero; dónde viven el código y la identidad deciden el 80 % de lo que queda; quién va a operar descarta opciones; el hardware añade piezas híbridas; el presupuesto y su forma afinan; y la madurez del equipo decide cuánta cuerda darse. La calidad técnica no aparece, porque a esas alturas ya está decidido. Y el coste que casi nadie calcula —las horas de personas— es el que suele invertir el resultado de la hoja de cálculo.
Con esto se cierra el módulo 6 y, con él, la parte conceptual del curso. Has recorrido los principios (módulos 1 a 4), cuatro contextos reales (módulo 5) y la maquinaria (módulo 6). Lo que queda es hacerlo tú. El módulo 7 es enteramente práctico: cinco ejercicios guiados que construyen, paso a paso, un pipeline de extremo a extremo —el pipeline básico, las pruebas automatizadas, el despliegue en producción, el monitoreo y la retroalimentación, y el endurecimiento con seguridad y secretos— y un proyecto final donde montas el tuyo completo, con las puertas, el artefacto inmutable, el despliegue con rollback y las métricas para saber si está funcionando. Ahí es donde todo lo anterior deja de ser lectura. Empieza por el Ejercicio 1: Pipeline Básico, que arranca justo donde arrancó la 02-02, pero esta vez lo escribes tú.
Curso de CI/CD: Integración y Despliegue Continuo
Módulo 1: Introducción a CI/CD
- Conceptos Básicos de CI/CD
- Beneficios de CI/CD
- Herramientas Populares de CI/CD
- El Proyecto del Curso: la Aplicación que Vamos a Automatizar
- Métricas DORA: Cómo se Mide la Entrega de Software
Módulo 2: Integración Continua (CI)
- Introducción a la Integración Continua
- Configuración de un Entorno de CI
- Automatización de la Construcción
- Pruebas Automatizadas
- Calidad de Código y Análisis Estático
- Artefactos, Versionado y Promoción
- Integración con Control de Versiones
Módulo 3: Despliegue Continuo (CD)
- Introducción al Despliegue Continuo
- Automatización del Despliegue
- Infraestructura como Código y Entornos Reproducibles
- Estrategias de Despliegue
- Feature Flags, Rollback y Recuperación ante Fallos
- Monitoreo y Retroalimentación
Módulo 4: Prácticas Avanzadas de CI/CD
- Pipelines de CI/CD
- Gestión de Dependencias
- Seguridad en CI/CD
- Escalabilidad y Rendimiento
- Pipeline as Code: Plantillas, Reutilización y Pruebas del Pipeline
- Bases de Datos en el Pipeline: Migraciones Seguras
Módulo 5: Implementación de CI/CD en Proyectos Reales
- Caso de Estudio: Proyecto Web
- Caso de Estudio: Aplicación Móvil
- Caso de Estudio: Microservicios
- Caso de Estudio: Modernizar un Proyecto Legacy
Módulo 6: Herramientas y Tecnologías
- Jenkins
- GitLab CI/CD
- CircleCI
- Travis CI
- Docker y Kubernetes
- GitHub Actions a Fondo
- Comparativa y Criterios para Elegir Herramienta
Módulo 7: Ejercicios Prácticos
- Ejercicio 1: Configuración de un Pipeline Básico
- Ejercicio 2: Integración de Pruebas Automatizadas
- Ejercicio 3: Despliegue en un Entorno de Producción
- Ejercicio 4: Monitoreo y Retroalimentación
- Ejercicio 5: Endurecer el Pipeline con Seguridad y Secretos
- Proyecto Final: Pipeline Completo de Extremo a Extremo
