Marcio Cunha

Cómo eliminar el tiempo de build en Docker usando caché remoto

Aprende a configurar registries remotos de caché en Docker para acelerar los pipelines de entrega continua y eliminar esperas en builds.

Marcio Cunha•5 min
También disponible en:PortuguêsEnglish
Resumen
  • El almacenamiento en caché de capas en Docker evita reprocesar instrucciones intactas
  • Los registries remotos comparten caché entre diferentes servidores de CI/CD
  • Herramientas como BuildKit optimizan el transporte de capas a través de la red
  • El orden correcto del Dockerfile maximiza el aprovechamiento del caché existente
  • Prácticas avanzadas de DevOps reducen drásticamente el tiempo total del pipeline

Por qué los builds de Docker tardan tanto en la nube

Cuando configuramos un entorno de integración continua (CI/CD), que son los sistemas automatizados responsables de probar y empaquetar nuestro software, Docker suele ser el motor principal. Sin embargo, si el servidor de CI carece del historial local de imágenes anteriores, tiene que descargar todo desde cero o reconstruir cada línea de su archivo de instrucciones, el famoso Dockerfile. En la práctica, esto significa perder minutos preciosos instalando bibliotecas básicas que no han cambiado en meses.

Para entender la gravedad de esto, piense en una obra de construcción donde los trabajadores tienen que fabricar sus propios ladrillos cada vez que llegan, en lugar de usar los que ya están apilados en el patio. En el universo de los contenedores, el caché local funciona como esta pila de ladrillos listos. Cuando el servidor pierde este estado local —lo que ocurre con frecuencia en entornos efímeros en la nube—, el tiempo de espera se dispara y la productividad del equipo se desploma.

El gran villano de esta historia es la falta de persistencia compartida entre los nodos de ejecución. En plataformas como GitHub Actions o GitLab CI, cada ejecución de build suele ocurrir en una máquina limpia y aislada. Como esta máquina no sabe qué pasó en la ejecución anterior, trata todo como una novedad absoluta. Aquí es exactamente donde entra la estrategia de caché remoto, permitiendo que los artefactos ya construidos se guarden en un lugar accesible para cualquier máquina de su infraestructura.

Cómo funciona el almacenamiento en caché de capas en BuildKit

BuildKit es el motor moderno de construcción de imágenes de Docker, diseñado para ser más rápido, seguro y eficiente que el constructor heredado. Cuando procesa un archivo de configuración, divide el proceso en pasos llamados capas, evaluando si el código o comando de cada línea ha cambiado en comparación con lo procesado anteriormente. Si nada ha cambiado, BuildKit simplemente reutiliza el resultado anterior al instante.

Para llevar esta inteligencia más allá de la máquina local, BuildKit introdujo soporte para exportadores e importadores de caché remotos. Esto significa que, en lugar de guardar el resultado solo en el disco duro local, el sistema puede enviar estas capas comprimidas directamente a un registry de contenedores, como Docker Hub, GitHub Packages o un repositorio privado como Harbor. Así, el próximo build puede descargar solo las piezas faltantes a través de la red, ahorrando ancho de banda y tiempo de procesamiento.

Para garantizar que el proceso ocurra sin cuellos de botella, vale la pena integrar estas mejoras con estrategias complementarias de entrega, como las analizadas en nuestro artículo sobre cómo eliminar el tiempo de inactividad en despliegues Blue-Green. Al fin y al cabo, de nada sirve acelerar la creación de la imagen si el momento de ponerla en marcha sigue causando interrupciones para los usuarios finales.

Configurando Docker Buildx con caché en registry

Para poner manos a la obra y activar esta magia en su pipeline, necesitamos utilizar el comando docker buildx, que habilita las funciones avanzadas de BuildKit. El primer paso consiste en crear e iniciar un constructor dedicado que admita múltiples controladores de almacenamiento y exportación de datos por la red, asegurando que el caché se envíe correctamente a su repositorio remoto.

A continuación se muestra un ejemplo práctico de comando que inicializa el constructor y activa el proceso de creación de la imagen, enviando el caché generado directamente a un registry compatible:

docker buildx create --name mi-builder --use
docker buildx build \
  --builder mi-builder \
  --cache-from type=registry,ref=miregistry.com/mi-app:cache \
  --cache-to type=registry,ref=miregistry.com/mi-app:cache,mode=max \
  --tag miregistry.com/mi-app:latest \
  --push .

En este ejemplo, el parámetro --cache-from le indica a Docker dónde buscar capas existentes antes de comenzar el trabajo pesado, mientras que --cache-to define a dónde enviar las nuevas capas generadas durante el proceso. El uso de mode=max asegura que todos los pasos intermedios se almacenen, maximizando la reutilización en ejecuciones futuras.

Buenas prácticas para organizar su Dockerfile

Configurar el registry remoto es solo la mitad del camino; la otra mitad depende de cómo escriba su Dockerfile. Docker evalúa el caché de forma secuencial: si una línea del archivo cambia, todas las líneas siguientes pierden el derecho al caché y deben ejecutarse de nuevo. Por lo tanto, el orden de los comandos importa mucho para la eficiencia general de su pipeline de entrega continua.

Una práctica fundamental es separar la copia de archivos de dependencias del resto del código fuente de la aplicación. En proyectos Node.js, por ejemplo, debe copiar solo el archivo package.json y package-lock.json antes de ejecutar el comando de instalación de paquetes, dejando la copia del código principal para un momento posterior. Así, si cambia solo un archivo de texto en su aplicación, Docker no necesitará descargar y reinstalar todas las bibliotecas externas de nuevo.

Además, mantener sus herramientas de desarrollo e infraestructura organizadas evita cuellos de botella operativos en otros frentes, asegurando que el flujo de trabajo permanezca fluido y predecible. En entornos de desarrollo complejos, optimizaciones similares de velocidad y rendimiento, como las aplicadas en el artículo sobre base de datos lenta y cómo hallar cuellos de botella de IOPS, muestran que cada capa del sistema necesita un seguimiento cercano para evitar pérdidas ocultas de productividad.

Consideraciones finales sobre la ganancia de velocidad en CI/CD

Eliminar el tiempo de build en contenedores dejó de ser un lujo y pasó a ser un requisito básico para los equipos que buscan alta frecuencia de entrega y retroalimentación rápida. La combinación de BuildKit con registries remotos de caché transforma por completo la dinámica de los servidores de integración continua, eliminando esperas innecesarias y optimizando el consumo de recursos computacionales en la nube.

Al aplicar una estructura inteligente en su Dockerfile y configurar correctamente los parámetros de exportación de caché, su equipo gana agilidad para centrarse en lo que realmente importa: escribir código de calidad y entregar valor al usuario final con seguridad y previsibilidad.