|

Reducir costos en CI/CD: Guía completa 2026

La reducción de costos en CI/CD puede alcanzar 85% migrando de GitHub-hosted runners a instancias spot de AWS orquestadas con Actions Runner Controller en Kubernetes, bajando el costo mensual de USD 7,680 a USD 960 por 2,000 horas de build. Punto.

En 30 segundos

  • GitHub-hosted runners facturan USD 0,064 por minuto. Self-hosted en spot instances cuesta USD 0,008/min: 87% más barato.
  • Las instancias spot de AWS son capacidad excedente vendida con 70-90% de descuento. AWS avisa con 2 minutos antes de terminarlas.
  • Actions Runner Controller (ARC) es el operador oficial de GitHub para orquestar runners en Kubernetes. Escala dinámicamente según la cola de jobs.
  • Con caché persistente de Gradle y Docker, los siguientes builds reutilizan capas. Ganancia real: 40-60% menos tiempo por compilación.
  • Sin dashboards de cost-per-build en Prometheus/Grafana, nunca validás si el ahorro real fue de 85% o se erosionó en overhead operacional.

CI/CD Cost Engineering es la práctica de optimizar la infraestructura de integración y despliegue continuo para minimizar gastos operacionales sin sacrificar velocidad ni confiabilidad. En este artículo, mostramos cómo lograrlo migrando runners de GitHub Actions a instancias spot en Kubernetes.

El problema de costos en CI/CD: de USD 7.680 a USD 960 por mes

Ponele que tu equipo ejecuta 2,000 horas de build-time cada mes. Usás GitHub-hosted runners con 4 vCPUs. GitHub te cobra USD 0,064 por minuto, lo que sale a USD 7,680 mensuales. No hay descuento por volumen. No hay forma de negociar. Así funciona.

Entonces alguien del equipo pregunta: “¿Y si nos pasamos a self-hosted?” Buena pregunta. El tema es que decidir es difícil porque hay tres opciones y cada una tiene trade-offs distintos.

La realidad es que la mayoría de los equipos ni siquiera sabe cuánto gastan realmente en CI. Ven la factura de GitHub y dicen “bueno, es lo que hay”. Pero si alguna vez configuraste runners propios en Kubernetes, sabés que el ahorro puede ser brutal (spoiler: hablamos de 85%).

Comparativa: hosted vs self-hosted vs spot instances

Acá viene lo bueno. Tres opciones, tres precios, tres realidades operacionales.

OpciónvCPU/RAMCosto por minutoCosto mensual (2K horas)Overhead operacional
GitHub-hosted4 / 16GBUSD 0,064USD 7,680Cero. GitHub gestiona todo.
Self-hosted on-demand (c6a.xlarge)4 / 8GBUSD 0,025USD 3,000Mediano. Tenés que mantener nodos, updates, networking.
Self-hosted spot (c6a.xlarge)4 / 8GBUSD 0,008USD 960Alto. Manejar preemptions, failover, persistencia de caché.
reducción de costos en ci/cd diagrama explicativo

La tercera fila es donde viven los ahorros reales. Pero ojo: USD 960 es el costo de infraestructura. Hay que sumarle mantenimiento, monitoreo, debugging cuando algo se rompe a las 3 de la mañana.

¿Vale la pena? Depende. Si ejecutás 2,000 horas mensuales, USD 6,720 de ahorro (75%) probablemente justifique 8-10 horas mensuales de trabajo operacional. Si solo ejecutás 200 horas, no tiene sentido complicarse. Cubrimos ese tema en detalle en ejecutar agentes locales sin API.

Instancias spot de AWS: cómo ahorran 85% en costos

Las instancias spot son capacidad excedente de AWS. Cuando tienen mucha demanda, alguien más paga el precio full. Vos comprás a descuento. Ganancia del jugador: AWS vende capacidad ociosa, vos ahorras dinero.

El truco (y por qué pocos la usan) es que AWS se la puede llevar en cualquier momento. La realidad es menos dramática: AWS avisa con 2 minutos antes de terminar la instancia. No se corta al voleo.

Esos 2 minutos son suficientes si tu orquestador sabe qué hacer. En Kubernetes, cuando recibís la notificación de preemption, sacás el runner de la cola, esperás a que terminen los builds en marcha, y migrás a una instancia nueva. Los builds pendientes se reencolan. Ninguno se pierde.

El descuento típico de spot es 70-90%, dependiendo de la zona y el tipo de instancia. Para c6a.xlarge en us-east-1, estamos hablando de USD 0,03-0,04 en on-demand vs USD 0,008-0,012 en spot. Eso es el 85% de reducción de costo que mencionamos.

Actions Runner Controller: orquestación de runners en Kubernetes

GitHub mantiene una herramienta llamada Actions Runner Controller (ARC). No es un tercer proyecto comunitario. Es oficial, mantenido por GitHub, con actualizaciones constantes.

ARC funciona así: definís un custom resource Kubernetes llamado RunnerScaleSet. ARC mira la cola de jobs pendientes en tu repositorio (vía API de GitHub), y genera pods efímeros (uno por job) en tu cluster. Cada pod es un runner. Cuando termina el job, el pod se borra. Es el ciclo de vida perfecto para spot instances.

Soporta EKS (AWS), GKE (Google Cloud), clusters on-prem, cualquier Kubernetes. Escalado dinámico. Si hay 50 jobs en cola, genera 50 pods en segundos. Si no hay nada, escala a cero (y pagas cero).

Configuración mínima necesaria: token de GitHub con permisos de administración de runners, acceso a la API de GitHub Actions, y un cluster Kubernetes con permiso para crear node pools. Nada sofisticado. Tema relacionado: alternativas de CI/CD según privacidad.

Implementación práctica: setup EKS/GKE + ARC + spot instances

El primer paso es crear un node pool dedicado a runners. No querés que un pod de CI consuma recursos de tu aplicación en producción. Tascos de CI son noisy neighbors.

En EKS, creás un node pool con taints específicas para runners. En GKE, igual. Cualquier workload en ese pool tiene que tolerar esas taints. ARC lo sabe y scheduleea ahí.

Instalás ARC con Helm. Es literalmente helm install actions-runner-controller oci://ghcr.io/actions/actions-runner-controller/actions-runner-controller. Con un par de valores: token de GitHub, scale set name, número de replicas máximas.

Luego declarás un RunnerScaleSet (un CRD que ARC proporciona) especificando límites de CPU/memoria, tolerancias a preemptions, y configuración de caché. El ejemplo del blog de MVP Factory muestra un setup completo:

Primer build: tarda 5 minutos (descarga dependencias, compila, tests).

Segundo build: con caché persistente, tarda 2 minutos (reutiliza capas de Gradle y Docker).

Si ejecutás 100 builds al mes, eso es 5 * 50 + 2 * 50 = 350 minutos. Sin caché serían 500. Ganancia: 150 minutos ahorrados, que en dinero es USD 12 (a USD 0,008/min). Parece poco, pero multiplícalo por mil equipos.

Caché persistente: multiplicar el ahorro con Gradle y Docker

Sin caché, cada build es from scratch. Gradle recompila, Docker rebuildeea capas que no cambiaron, npm reinstala paquetes. Eso es dinero quemándose en ciclos de CPU. Lo explicamos a fondo en herramientas IA para optimizar pipelines.

Con ARC + EBS o GCS como persistent storage, el caché vive más allá del ciclo de vida del pod. Siguiente build reutiliza el volumen. Buildkit de Docker, si está bien configurado, skippea capas sin cambios.

Implementación: volumeClaimTemplate en el RunnerScaleSet apunta a un StorageClass que usa EBS (AWS) o GCPersistentDisk (GCP). Gradle usa un directorio en ese volumen. Docker buildkit también. El ahorro real en tiempo es 40-60%, según la fuente oficial del blog de MVP Factory.

Monitoreo y dashboards: validar ahorros reales con cost-per-build

Acá viene lo que casi nadie hace. Implementás ARC, bajas costos a USD 960, y después…

El overhead operacional te devora. Tenés que mantener el cluster, patchear nodos, debuguear preemptions que no se manejaron correctamente, limpiar storage lleno de cachés viejos. Nadie mide nada. En 6 meses, los costos vuelven a USD 4,000 sin que nadie sepa por qué.

Prometheus + Grafana son la solución. Instrumentá ARC para exportar métricas: cantidad de jobs completados, failures, preemptions manejadas vs no manejadas, tiempo total de ejecución, utilización de nodos. Después calculá cost-per-build: (gastos de infraestructura / cantidad de builds) = costo unitario.

Si bajó a USD 0,10 por build, bárlalo. Si subió a USD 1,50, algo está roto: probablemente mucho overhead, runners mal configurados, o preemptions no manejadas que fuerzan reintentos.

Errores comunes al implementar ARC

1. No configurar Node Affinity para spot instances

Si tu cluster tiene nodos on-demand y spot juntos, ARC va a scheduleear runners en cualquier lado. Los on-demand son mucho más caros. Solución: nodeSelectorTerms en el RunnerScaleSet para forzar spot, o usar taints+tolerations. Complementá con comparar plataformas de CI/CD.

2. Ignorar el handling de preemptions

AWS termina un nodo, el pod muere, el job se pierde. Parece que tu CI se colgó. Realidad: nunca configuraste el lifecycle hook para graceful shutdown. Solución: agregar un sidecar que escuche interruptions de spot, y notifique a GitHub para reencolar el job.

3. Caché sin límite de storage

Después de 100 builds, el volumen persistente tiene 500GB de caché acumulado. Estás pagando USD 50/mes solo en storage. Nadie lo limpió. Solución: retention policy. Después de 30 días sin acceso, borrá el caché. Herramienta: kubelet janitor o un CronJob que ejecute limpieza.

Preguntas Frecuentes

¿Cuánto cuesta una pipeline de CI/CD con GitHub Actions?

GitHub-hosted cuesta USD 0,064 por minuto (Linux 4-core). A 2,000 horas mensuales, USD 7,680. No hay descuentos por volumen. Self-hosted en spot instances baja el costo a USD 960 mensuales, con overhead operacional de mantenimiento.

¿Qué es Actions Runner Controller?

Es un operador Kubernetes oficial de GitHub que orquesta runners en tu cluster. Mira la cola de jobs, genera pods efímeros, escala dinámicamente. Soporta cualquier Kubernetes: EKS, GKE, on-prem. Se integra nativamente con GitHub Actions.

¿Cuál es el riesgo de usar instancias spot?

AWS las puede terminar con 2 minutos de aviso. Si tu orquestador maneja preemptions correctamente (lifecycle hooks, reencolar jobs), el riesgo es cero. Si ignorás preemptions, los jobs simplemente fallan sin reintento.

¿Cuánto ahorro real se logra con caché persistente?

Reducción de tiempo por build: 40-60% según el artículo de MVP Factory. Si un build sin caché tarda 5 minutos, con caché tarda 2-3. En dinero, es más o menos 40-60% de reducción en costo de infraestructura por build.

¿Se necesita Kubernetes para usar ARC?

Sí. Si no tenés un cluster Kubernetes, ARC no serve. En ese caso, alternativa: runners autoalojados en EC2 on-demand, sin orquestación. Costo sigue siendo mucho menor que GitHub-hosted (USD 3,000 vs USD 7,680), pero perdés escalado dinámico.

Conclusión

La reducción de costos en CI/CD de 85% es real, pero tiene precio: operacional, no en dinero. Necesitás un cluster Kubernetes, conocimiento para configurar ARC, y disciplina en monitoreo con dashboards de cost-per-build.

Si tu equipo ejecuta 2,000+ horas mensuales de builds, el ahorro de USD 6,720 (de USD 7,680 a USD 960) casi seguro justifica las 8-10 horas mensuales de trabajo. Si solo ejecutás 200 horas, no vale la pena complicarse.

El punto crítico: sin medir cost-per-build en Prometheus/Grafana, nunca sabés si el 85% se mantuvo o se erosionó a 50%. Implementá dashboards desde el día uno. Ahí está la diferencia entre cost engineering y simplemente “bajamos costos”.

Fuentes

Similar Posts