Un martes por la mañana, GitHub se negó a iniciar un solo job de Actions para nuestra organización. La anotación decía que nuestros pagos habían fallado o que había que subir nuestro límite de gasto. Ninguna de las dos cosas era cierta: no había nada vencido, la tarjeta registrada acababa de ser autorizada y no había ningún límite de gasto que subir. Soporte no respondió ese día.
Decidimos interpretarlo de la forma más caritativa. GitHub nos estaba diciendo con delicadeza que ya habíamos superado sus runners y que deberíamos buscar los nuestros. Así que lo hicimos, esa misma noche.
Una retención solo afecta a las máquinas de GitHub
Una retención por facturación rechaza jobs en los runners alojados por GitHub. No toca los runners que traes tú. Lo descubrimos al registrar un runner en una Mac de laboratorio y ver cómo un job de prueba se ejecutaba mientras todos los jobs alojados de la organización seguían rechazados. Así que la salida más rápida no era discutir con facturación. Era dejar de pedirle máquinas a GitHub.
"Trae tu propio runner" solía significar un fin de semana de infraestructura. Ya no.
Los presets existen
Hay toda una categoría de proveedores que se conectan a Actions como runners autoalojados: instalas una GitHub App, cambias una etiqueta en tu workflow y cada job recibe una máquina virtual efímera que se destruye cuando el job termina. Elegimos Blacksmith para Linux: el más barato por minuto de los que comparamos, una microVM por job y la misma imagen base que los runners de GitHub, así que las herramientas de las que dependían nuestros jobs ya estaban ahí. Para los carriles de Apple ya teníamos una Mac de laboratorio, así que ejecuta las suites de iOS y macOS sin costo por minuto.
Un interruptor, no una migración
El cambio del que estamos más orgullosos es lo pequeño que es. Cada job de Linux y de Apple que alimenta nuestro gate obligatorio lee su runner de una variable del repositorio, con la antigua etiqueta de GitHub como respaldo:
runs-on: ${{ vars.LINUX_CI_RUNS_ON || 'ubuntu-latest' }}
Defines la variable y los jobs se mueven. La borras y vuelven, sin necesidad de pull request. Una pequeña prueba de guardia hace fallar el build si algún job del gate de Linux deja de usar la variable.
No movimos todo. Los despliegues del producto, las promociones de versiones y cualquier cosa que tenga una clave estática de la nube se quedaron en las máquinas en las que ya confiábamos, porque para esos jobs el runner forma parte del límite de confianza. Ese endurecimiento se hace a nuestro ritmo, no la noche de una caída.
Del lado del proveedor: unos diez minutos de tiempo de ingeniería y un pull request, que se validó solo porque un pull request ejecuta su propio workflow. Del lado de la Mac: una tarde.
Los números
Las últimas veinte ejecuciones alojadas en nuestra rama principal frente a las primeras ejecuciones en la nueva flota:
| Job | Alojado | Nueva flota |
|---|---|---|
| Pruebas y lint del frontend | 13.5 min | 6.1 min |
| Pruebas del backend, 8 núcleos | 11.6 min | 5.0 min |
| Regresión visual | 2.1 min | 0.9 min |
| Pruebas unitarias de iOS | 14 min | 2 a 4 min |
| Gate completo | unos 14 min | unos 7 min |
Los minutos de Linux facturados para el mismo conjunto de jobs bajaron de 46.7 a 21.8 por ejecución. Con el precio por minuto más bajo, eso proyecta nuestra factura de CI de Linux de unos $730 al mes a entre $350 y $400; lo comprobaremos con la primera factura completa. macOS había sido la partida más grande, con unos $1,600 al mes en bruto, y además se comía la mayor parte de nuestros minutos incluidos, ya que macOS cuenta diez a uno contra ellos. Ahora se ejecuta en una Mac que ya tenemos.
Una advertencia: la aceleración es real para suites limitadas por CPU con cachés calientes; nuestros jobs de guardia de menos de un minuto no se volvieron más rápidos. Mide los minutos facturados, no la cifra de marketing.
La versión corta: el gate termina en aproximadamente la mitad del tiempo (de 13.8 a 7 minutos, medido), y las suites de Linux y macOS que costaban unos $2,600 al mes en bruto en runners alojados tienen un costo proyectado de $350 a $400 en la nueva flota, alrededor de un 85 por ciento menos. El carril de Windows y un puñado de jobs de despliegue y promoción siguen alojados por ahora y quedan fuera de esa cifra.
Si tienes un equipo pequeño
- Pon el interruptor antes de necesitarlo. Una etiqueta controlada por variable con respaldo alojado no cuesta nada y convierte la próxima caída en un cambio de diez minutos.
- Lee lo que hará el asistente de migración de un proveedor antes de hacer clic. El nuestro habría fijado etiquetas del proveedor en cada workflow, despliegues incluidos, sin respaldo.
- Mantén los jobs que manejan credenciales en máquinas en las que ya confías, y endurece la forma en que reciben sus claves antes de moverlos.
La retención de GitHub seguía activa cuando hicimos merge de lo último. Nunca recibimos respuesta. Simplemente ya no importaba.