GitLab Runner: Crear imágenes Docker
Compila y publica imágenes Docker de forma eficiente desde tus pipelines de GitLab CI/CD utilizando los runners de Stackhero y Docker-in-Docker
👋 ¡Bienvenido a la documentación de Stackhero!
Stackhero ofrece una solución sencilla de GitLab Runner en la nube que facilita la ejecución de sus trabajos de GitLab CI/CD de manera eficiente y sin complicaciones. Esto es lo que puede esperar:
- Minutos ilimitados de CI/CD: ejecute sus pipelines tantas veces como necesite, sin facturación por minuto ni cargos inesperados.
- Varios trabajos concurrentes: acelere su desarrollo ejecutando varios trabajos en paralelo.
- El ejecutor Docker con soporte para Docker-in-Docker: construya y publique fácilmente imágenes de contenedores como parte de su proceso CI/CD.
- Funciona perfectamente tanto con GitLab.com como con instancias de GitLab autogestionadas.
- Una infraestructura privada y dedicada con almacenamiento NVMe/SSD rápido garantiza un rendimiento de compilación estable y predecible.
- Disponible en las regiones de 🇪🇺 Europa y 🇺🇸 USA para adaptarse a las necesidades de su equipo.
Ahorre tiempo: puede conectar su primer GitLab Runner y empezar a ejecutar pipelines en solo unos minutos.
Introducción
Con un Stackhero GitLab Runner, cada job se ejecuta dentro de un contenedor nuevo utilizando el ejecutor Docker. Puedes construir tus propias imágenes Docker directamente en tu pipeline habilitando Docker-in-Docker (DinD). Esta configuración lanza un daemon Docker junto a tu job, lo que te permite ejecutar los comandos docker build y docker push como parte de tu proceso CI/CD.
Cada ejecución se beneficia de minutos CI/CD ilimitados: puedes compilar tantas veces como necesites, sin preocuparte por límites de uso. Tu caché de compilación se almacena en el disco dedicado del runner, lo que significa que las compilaciones repetidas pueden reutilizar capas anteriores. Esto reduce significativamente los tiempos de compilación y ayuda a que tus pipelines terminen más rápido.
Crear una imagen Docker con Docker-in-Docker
Puedes añadir el siguiente ejemplo de .gitlab-ci.yml a tu repositorio. Esta configuración compila el Dockerfile que se encuentra en la raíz de tu proyecto:
build-image:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
before_script:
- docker info
script:
# Sustituye "my-image" por el nombre que desees:
- docker build -t my-image .
# Opcionalmente, ejecuta una prueba rápida sobre la imagen construida:
# - docker run --rm my-image /path/to/tests
En este ejemplo estamos usando la versión 29 de la imagen Docker. Puedes utilizar una versión más reciente si está disponible. Puedes consultar las etiquetas más recientes en la página oficial de la imagen Docker.
En esta configuración, el servicio docker:29-dind inicia un daemon Docker junto a tu job, y DOCKER_HOST: "tcp://docker:2375" indica al CLI de docker que lo utilice. Debes establecer siempre DOCKER_HOST cuando declares un servicio docker:dind: si no lo haces, el CLI se conecta silenciosamente a otro daemon, por lo que tu compilación puede pasar incluso si el servicio está mal configurado, ocultando problemas reales (y rompiendo herramientas como Testcontainers que dependen del servicio). DOCKER_TLS_CERTDIR: "" conecta a través del puerto interno sin TLS 2375 en la red interna del job.
Como alternativa más sencilla, puedes omitir el bloque services y ambas variables: el runner de Stackhero también expone un daemon Docker listo para usar a través de un socket montado, por lo que un simple docker build funciona sin configuración adicional.
Ejecutar tus tests con Testcontainers
Testcontainers es una biblioteca de testing, disponible para Java, Go, Node.js, Python, .NET y otros lenguajes, que inicia servicios reales como contenedores Docker desechables mientras se ejecutan tus tests. En lugar de simular una base de datos o un broker de mensajes, tus tests de integración se comunican con una instancia real de PostgreSQL, MySQL, Redis o Kafka, creada antes de los tests y eliminada justo después. Es especialmente popular en proyectos Java y Spring.
Testcontainers necesita un daemon Docker, por lo que funciona exactamente con la misma configuración de Docker-in-Docker que la anterior. No se necesita ninguna variable adicional:
test:
stage: test
# Utiliza la imagen que necesiten tus tests (aquí un JDK), no necesariamente la imagen docker:
image: gradle:jdk21
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
script:
- gradle test
Testcontainers lee DOCKER_HOST para encontrar el daemon, y reutiliza ese mismo hostname docker para acceder a los puertos publicados por los contenedores que inicia. Ambos funcionan por sí solos, ya que el alias docker se resuelve en la red de tu job.
Mantén
DOCKER_HOSTen tus jobs que usen Testcontainers. Si no lo haces, Testcontainers recurre al socket Docker montado por el runner y luego intenta acceder a tus contenedores de test a través de la dirección IP del host, a la que tu job no puede conectarse. El síntoma habitual es que el contenedor auxiliar Ryuk falla conWait strategy failed. Container is removed, oTimed out waiting for log output matching '.*Started.*'.
Publicar en el registro de contenedores de GitLab
GitLab proporciona variables predefinidas (CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD, CI_REGISTRY_IMAGE) para que tu pipeline pueda autenticarse y publicar imágenes en el registro de contenedores de tu proyecto de forma segura. No se requieren secretos adicionales.
Aquí tienes un ejemplo de job que construye y publica tu imagen:
build-and-push:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
script:
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
# Si estás en la rama principal, también puedes etiquetar y publicar "latest":
- |
if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
docker tag "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE:latest"
docker push "$CI_REGISTRY_IMAGE:latest"
fi
Para publicar tus imágenes en otro registro (como Docker Hub o un registro privado), puedes almacenar las credenciales como variables CI/CD y usarlas con docker login de la misma manera.
Acelerar compilaciones repetidas
El disco de tu runner se mantiene entre pipelines, lo que te permite reutilizar las capas de imagen como caché de compilación. Esto puede hacer que las compilaciones repetidas sean mucho más rápidas. Aquí tienes un ejemplo de configuración:
build-cached:
stage: build
image: docker:29
services:
- name: docker:29-dind
alias: docker
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_TLS_CERTDIR: ""
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
script:
# Descarga la última imagen para inicializar la caché (si existe):
- docker pull "$CI_REGISTRY_IMAGE:latest" || true
- docker build --cache-from "$CI_REGISTRY_IMAGE:latest" -t "$CI_REGISTRY_IMAGE:latest" .
- docker push "$CI_REGISTRY_IMAGE:latest"
Este enfoque permite que tus compilaciones aprovechen la caché de capas de Docker, por lo que solo se reconstruyen las capas nuevas o modificadas.
Ejecutar jobs en paralelo
Tu plan determina cuántos jobs pueden ejecutarse de forma concurrente. Los jobs en la misma etapa se inician juntos, hasta el límite de concurrencia que tengas. Esto significa que varios jobs independientes pueden ejecutarse en paralelo y finalizar tan pronto como termine el más lento, en lugar de esperar a que cada uno termine en secuencia.
Ejemplo:
stages:
- test
unit:
stage: test
image: node:22
script: npm run test:unit
integration:
stage: test
image: node:22
script: npm run test:integration
e2e:
stage: test
image: node:22
script: npm run test:e2e
Si configuras tu concurrencia en 1 o superior, los jobs unit, integration y e2e se ejecutarán al mismo tiempo.
Para más detalles sobre cómo construir imágenes Docker en pipelines de GitLab CI/CD, puedes consultar la documentación oficial de GitLab sobre el uso de Docker builds.