Infraestructura de canalización CI/CD en servidores dedicados

Infraestructura de canalización CI/CD en servidores dedicados

Los servicios CI compartidos se ralentizan en el peor momento posible. El nivel gratuito de GitHub Actions pone en cola los trabajos cuando se producen picos de uso simultáneo. Los runners compartidos de GitLab agotan el tiempo de espera en compilaciones que duran más de una hora. Los niveles de pago se acumulan rápidamente: GitHub Actions cobra 0,008 $ por minuto por los runners de Linux, lo que significa que una compilación de 20 minutos que se ejecuta 50 veces al día cuesta 240 $ al mes, sin contar las suites de pruebas paralelas más grandes.

Un servidor dedicado que ejecuta Jenkins o ejecutores GitLab autohospedados cambia por completo la economía. Coste mensual fijo. Sin facturación por minutos. Sin esperas en cola durante las horas punta. Y en el almacenamiento NVMe, el almacenamiento en caché de la capa Docker y las lecturas de artefactos de prueba se ejecutan a velocidades que marcan una diferencia apreciable en la duración total del proceso.

Por qué una infraestructura de CI dedicada tiene sentido a gran escala

El problema de la cola

Los servicios CI compartidos funcionan con colas de uso justo. Cuando tu equipo envía 15 confirmaciones simultáneamente antes de un lanzamiento, esos trabajos se ponen en cola uno detrás de otro. En un servidor dedicado de 16 núcleos que ejecuta Jenkins con 16 ejecutores paralelos, los 15 trabajos se inician simultáneamente. El tiempo real desde la última confirmación hasta el resultado final de la compilación se reduce drásticamente.

Esa compresión es más importante durante los ciclos de revisión de código, donde el tiempo de espera de los desarrolladores afecta directamente al número de iteraciones de revisión que se realizan al día. Los equipos que reducen el tiempo de espera de CI de 15 a 3 minutos suelen obtener un mayor rendimiento de PR y ciclos de fusión más rápidos.

Facturación por minuto frente a coste fijo

Un equipo de ingeniería de tamaño medio que ejecuta 200 compilaciones al día con una duración media de 15 minutos cada una acumula 3000 minutos de compilación diarios. Con el precio de GitHub Actions de 0,008 $ por minuto para Linux, eso supone 24 $ al día, aproximadamente 720 $ al mes. En el nivel Premium de GitLab, con minutos de ejecución adicionales adquiridos, se aplican costes similares.

Un servidor dedicado InMotion Hosting por 99,99 $ al mes ejecuta los mismos 3000 minutos de compilación diarios con capacidad de sobra. En el nivel Advanced, la paralelización de pruebas en 64 GB de RAM permite ejecutar conjuntos de pruebas completos sin presión sobre la memoria.

Jenkins: Topología maestro/agente en hardware dedicado

Configuración de un solo servidor

Para equipos que ejecutan menos de 500 compilaciones al día, lo más práctico es utilizar un único servidor dedicado que ejecute tanto el maestro Jenkins como los agentes de compilación. El proceso maestro de Jenkins es ligero: se encarga de la programación, la gestión de complementos y la interfaz de usuario web. Los agentes de compilación realizan el trabajo real.

Configura Jenkins con 12-14 ejecutores de compilación en un servidor de 16 núcleos, dejando 2 núcleos para el proceso maestro y la sobrecarga del sistema operativo. Cada ejecutor ejecuta un trabajo de compilación. Con 14 ejecutores en paralelo, una cola de 14 trabajos se borra en el tiempo que tarda un solo trabajo.

Multiservidor para equipos más grandes

Cuando el volumen de compilación supera los 500 trabajos diarios, o cuando es necesario aislar diferentes entornos de compilación (Python 3.9 frente a 3.12, diferentes versiones del demonio Docker), una topología maestro-agente en varios servidores dedicados proporciona una separación más clara. El maestro Jenkins se ejecuta en un servidor más pequeño (el nivel Essential es suficiente). Los agentes de compilación se ejecutan en servidores de mayores prestaciones que se ajustan a los requisitos de la carga de trabajo.

Los servidores agentes se conectan al maestro a través de SSH o JNLP. Esto permite añadir capacidad de forma incremental: un segundo servidor dedicado avanzado duplica el rendimiento de compilación sin necesidad de reconfigurar el maestro.

GitLab Runners en hardware dedicado

Los runners autohospedados de GitLab se registran en una instancia de GitLab (ya sea gitlab.com o autohospedada) y ejecutan trabajos de pipeline. Cada proceso runner puede gestionar un trabajo a la vez; la ejecución de múltiples procesos runner en un servidor de 16 núcleos permite lograr el paralelismo.

Configuración del ejecutor de GitLab para obtener el máximo paralelismo en un servidor Extreme:

  • concurrent = 16 ( en /etc/gitlab-runner/config.toml; establece el número máximo de trabajos en paralelo en todos los runners registrados)
  • ejecutor = docker ( el ejecutor Docker aísla cada trabajo en un contenedor nuevo, lo que evita la pérdida de estado entre trabajos)
  • pull_policy = if-not-present ( utiliza imágenes de Docker almacenadas en caché localmente en lugar de descargarlas en cada trabajo; fundamental para aprovechar las ventajas de rendimiento NVMe )

Con el ejecutor Docker y el almacenamiento en caché de imágenes locales en NVMe, las ejecuciones posteriores de la misma canalización omiten por completo la extracción de imágenes. Una imagen de Python 3.12 que tarda 45 segundos en extraerse de Docker Hub se ejecuta desde NVMe local en menos de 2 segundos.

NVMe : donde más mejora el rendimiento de la infraestructura de canal

Almacenamiento en caché de capas de Docker

Las compilaciones de Docker están organizadas en capas. Cuando una compilación solo cambia el código de la aplicación, pero no las dependencias, Docker reutiliza las capas almacenadas en caché para los pasos de instalación de las dependencias. Esta caché se almacena en el almacenamiento local del ejecutor. En SSD SATA, leer una capa almacenada en caché de 2 GB tarda aproximadamente 4 segundos. En NVMe 5 GB/s, la misma lectura tarda menos de medio segundo.

Para una compilación que ejecuta 20 trabajos de canalización al día, cada uno de ellos utilizando capas Docker almacenadas en caché, la diferencia se acumula hasta alcanzar varios minutos de tiempo real ahorrado al día. En un equipo de 20 desarrolladores, eso es significativo.

Almacenamiento de artefactos de prueba

Los conjuntos de pruebas generan una gran cantidad de artefactos: informes de cobertura, capturas de pantalla de pruebas de navegadores, binarios compilados, archivos XML con resultados de pruebas. En un servidor de CI muy activo, se producen cientos de escrituras de artefactos por hora en la capa de almacenamiento. NVMe esta carga de escritura sin que se acumulen esperas de E/S en los registros de compilación.

Configura Jenkins o GitLab para almacenar artefactos en el NVMe local durante la compilación y, a continuación, carga los artefactos finales en el almacenamiento de objetos o en un repositorio compartido al finalizar el proceso. Este enfoque en dos fases mantiene la rapidez de la compilación y conserva los artefactos más allá de la capacidad local del servidor.

Paralelización de pruebas y espacio temporal

Los marcos de pruebas modernos distribuyen las pruebas entre múltiples procesos. pytest-xdist, el indicador –maxWorkers de Jest y la gema parallel_tests de RSpec escriben archivos temporales en el almacenamiento local durante la ejecución de pruebas en paralelo. En NVMe, 16 trabajadores de pruebas en paralelo que escriben archivos temporales simultáneamente no crean conflictos de E/S. En SSD SATA SSD almacenamiento en red, lo hacen con frecuencia.

Configura los directorios temporales de prueba para que apunten explícitamente al NVMe :nvme para ejecutores de pruebas basados en shell, o configuración de directorios temporales específicos del marco. Se trata de un cambio de una sola línea que elimina una fuente común de fallos en las pruebas paralelas.

Desarrolla estrategias de almacenamiento en caché

Cachés de dependencia

El paso más costoso en la mayoría de los procesos de CI es la instalación de dependencias: npm install, pip install, resolución de dependencias de Maven. Estos pasos extraen paquetes de Internet y los escriben en directorios de caché locales.

  • npm: Almacenar en caché node_modules y el directorio de caché de npm entre compilaciones utilizando el almacenamiento temporal de Jenkins o la clave de caché de GitLab.
  • pip: Almacena en caché la caché de descargas de pip (~/.cache/pip) y utiliza –find-links para servir desde NVMe local.
  • Maven: Almacena en caché ~/.m2/repository entre compilaciones para evitar volver a descargar las dependencias JAR.
  • Gradle: Almacena en caché ~/.gradle entre compilaciones; la caché de compilación de Gradle también almacena en caché los resultados de las tareas.

En un servidor dedicado con NVMe , estas cachés persisten entre trabajos de forma natural. El reto de los servicios de CI compartidos es que las cachés deben cargarse y descargarse entre cada trabajo, lo que añade una sobrecarga. En tu propio servidor, la caché siempre es local.

Entornos de pruebas automatizadas

Docker Compose para pruebas de integración

Las pruebas de integración suelen necesitar servicios externos: bases de datos, colas de mensajes, API simuladas. Docker Compose activa estas dependencias de servicio por cada ejecución de prueba. En un servidor dedicado con 192 GB de RAM y 16 núcleos, ejecutar PostgreSQL, Redis y un servidor API simulado en Docker junto con el conjunto de pruebas real añade una sobrecarga mínima.

Configura Docker Compose para utilizar volúmenes con nombre respaldados por el NVMe para los datos del servicio. PostgreSQL un volumen con nombre en NVMe una base de datos de prueba en menos de 1 segundo, frente a los 5-8 segundos que tarda en un almacenamiento más lento.

Pruebas del navegador

Las pruebas de Playwright y Cypress Browser consumen muchos recursos: cada contexto del navegador utiliza entre 200 y 400 MB de RAM y una cantidad significativa de tiempo de CPU para el renderizado. En un ejecutor de CI compartido, las pruebas del navegador suelen agotarse o producir resultados poco fiables debido a la presión de la memoria. En un servidor dedicado con 192 GB de RAM que ejecuta 8 trabajadores de pruebas de navegador en paralelo, cada trabajador dispone de memoria suficiente y no hay presión externa sobre la asignación de recursos.

Comparación: CI compartido frente a servidor dedicado

ConfiguraciónTrabajos paralelosEsperar en la colaLimite de minutos de construcción
Equipo de GitHub Actions (minutos ilimitados)20 simultáneosSí, durante los picos.Limitado a gran escala
GitLab Premium + minutos de ejecución adicionalesVariableSí, corredores compartidos.2000 minutos incluidos
InMotion Essential + Jenkins14 simultáneosNingunoSin límites
InMotion Advanced + Jenkins16 simultáneosNingunoSin límites
InMotion Extreme + ejecutores GitLab16 simultáneosNingunoSin límites

Elegir el nivel adecuado de InMotion para CI/CD

  • Aspire: equipos pequeños con menos de 50 compilaciones al día, validación básica del proceso. Limitado a entre 4 y 6 ejecutores paralelos.
  • Imprescindible: equipos que ejecutan entre 50 y 200 compilaciones diarias. 64 GB de RAM permiten gestionar cómodamente compilaciones basadas en Docker con cachés de dependencias.
  • Avanzado: Equipos que ejecutan entre 200 y 500 compilaciones diarias o conjuntos completos de pruebas de integración que requieren contenedores de servicios de gran tamaño.
  • Extremo: organizaciones de ingeniería que ejecutan más de 500 compilaciones diarias, pruebas paralelas intensivas en navegadores o entrenamiento de modelos de aprendizaje automático como parte de los procesos de integración continua.

Cómo empezar

La mayoría de los equipos descubren en el primer ciclo de facturación que su gasto anterior por minuto en CI superaba el coste del servidor dedicado. La mejora del rendimiento en los tiempos de compilación suele ser igualmente significativa: las duraciones de los procesos que antes tardaban 20 minutos en una infraestructura compartida, ahora suelen completarse en 4-6 minutos en hardware dedicado NVMe con ejecución paralela real.

Comparte este artículo

Deja una respuesta

Tu dirección de correo electrónico no se publicará. Los campos obligatorios están marcados con *.