Configurar GitLab CI Runner self‑hosted con Docker y caché remoto para acelerar builds: tutorial práctico
Deploy & DevOps · Por Kevin Marcondes · Publicado el · Actualizado el · 8 min de lectura
Este tutorial muestra, paso a paso, cómo desplegar un GitLab Runner en Docker, registrarlo en GitLab, habilitar caché S3/MinIO y usar BuildKit con caché en el registry. Incluye un .gitlab-ci.yml de ejemplo y comandos para verificar que todo funciona.
Arquitectura y elecciones de caché
Ejecutarás el GitLab Runner dentro de un contenedor usando el ejecutor Docker, que aísla los jobs en contenedores. Usaremos dos mecanismos de caché para reducir el tiempo de pipeline y el tráfico: el caché de archivos del runner y el caché de capas de imagen vía BuildKit en el registry. La combinación cubre dependencias de la aplicación y capas del Dockerfile.
- Caché del Runner (S3/MinIO): guarda dependencias y directorios temporales (node_modules, vendor, .m2) entre jobs.
- Caché de capas Docker (BuildKit para el registry): reaprovecha capas de imagen entre builds en el Container Registry.
| Recurso | Caché del Runner (S3/MinIO) | Caché Docker registry (BuildKit) |
|---|---|---|
| Qué almacena | Dependencias y directorios temporales (node_modules, vendor, .m2) | Capas de imagen del Dockerfile |
| Ámbito | Por job/proyecto; puede compartirse | Por Dockerfile/tag; compartido por refs |
| Cuándo actúa | Antes/después del job (restore/save) | Durante el docker buildx build |
| Infra necesaria | Bucket S3/compatible (p. ej.: MinIO) | Registry (p. ej.: GitLab Container Registry) |
| Beneficio típico | Acelera gestores de paquetes y builds de apps | Acelera rebuilds de imágenes y push/pull de capas |
Requisitos previos
Asegúrate de estos elementos antes de empezar. Necesitarás privilegios administrativos en el servidor del runner.
- Instancia de GitLab accesible y token de registro del runner.
- Un servidor Linux con acceso root y salida a Internet.
- Docker instalado en el host. Si lo necesitas, sigue: Cómo instalar Docker y Docker Compose en Linux.
- Opcional para caché del runner: bucket S3/MinIO accesible desde el servidor.
- Acceso al GitLab Container Registry del proyecto para caché de capas vía BuildKit.
Levantar y registrar el GitLab Runner (executor Docker)
Crearemos el volumen de configuración, levantaremos el contenedor del Runner y lo registraremos. El executor será Docker, con acceso al socket para crear contenedores de jobs. Guarda el token de registro de forma segura. El registro que sigue es no interactivo; ajusta la URL de GitLab, el token, el nombre del runner y las versiones según tu entorno.
# 1) Preparar diretório de configuração
sudo mkdir -p /srv/gitlab-runner/config
# 2) Subir o container do GitLab Runner
sudo docker run -d --name gitlab-runner \
--restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:alpine
# 3) Registrar o runner (ajuste URL e token)
sudo docker run --rm -it \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:alpine register \
--non-interactive \
--url "https://gitlab.example.com/" \
--registration-token "REG_TOKEN" \
--name "runner-docker" \
--executor "docker" \
--docker-image "docker:24.0" \
--docker-privileged \
--docker-volumes "/cache"
Ajustar config.toml para Docker y BuildKit
Tras el registro, edita el config.toml para habilitar BuildKit y definir volúmenes. BuildKit acelera los builds y mejora el caché de capas. Mantenemos el executor en modo privilegiado para escenarios que requieren DinD. Para optimizar las capas de tu imagen, consulta Imágenes Docker ligeras con multistage y estrategias de caché en BuildKit y caché remoto en CI.
concurrent = 2
check_interval = 0
[session_server]
session_timeout = 1800
[[runners]]
name = "runner-docker"
url = "https://gitlab.example.com/"
token = "TOKEN_GERADO_NO_REGISTRO"
executor = "docker"
environment = [
"DOCKER_DRIVER=overlay2",
"DOCKER_TLS_CERTDIR=",
"DOCKER_BUILDKIT=1",
"BUILDKIT_PROGRESS=plain"
]
[runners.docker]
image = "docker:24.0"
privileged = true
tls_verify = false
disable_cache = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
Habilitar caché remoto S3/MinIO para el Runner
Configura ahora el caché remoto para restaurar y guardar dependencias más rápido. Si usas MinIO, habilita Insecure si no hay TLS en el endpoint interno. Crea un usuario dedicado con permisos restringidos para el bucket. Inserta el bloque siguiente dentro del [[runners]] en config.toml y ajusta endpoint, región, bucket y credenciales según tu proveedor.
[runners.cache]
Type = "s3"
Shared = true
[runners.cache.s3]
ServerAddress = "minio.internal:9000"
BucketName = "gitlab-cache"
BucketLocation = "us-east-1"
AccessKey = "MINIO_ACCESS_KEY"
SecretKey = "MINIO_SECRET_KEY"
Insecure = true
Pipeline (.gitlab-ci.yml) con BuildKit y caché en el registry
El ejemplo siguiente construye y publica la imagen en el GitLab Container Registry usando BuildKit con caché en el propio registry. Esto reaprovecha capas entre builds y reduce el tiempo en pasos repetidos del Dockerfile. El servicio docker:dind expone el daemon en 2375 sin TLS. Usa esto solo en entornos controlados. Las credenciales del registry provienen de variables estándar de GitLab CI.
image: docker:24.0
services:
- name: docker:24.0-dind
command: ["--registry-mirror=", "--mtu=1460"]
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
DOCKER_DRIVER: overlay2
DOCKER_BUILDKIT: "1"
BUILDKIT_PROGRESS: plain
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
CACHE_REF: $CI_REGISTRY_IMAGE:buildcache
stages: [build]
build-image:
stage: build
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
- docker buildx create --use --name builder || docker buildx use builder
script:
- docker buildx build \
--push -t "$IMAGE" \
--cache-from type=registry,ref="$CACHE_REF" \
--cache-to type=registry,ref="$CACHE_REF",mode=max \
-f Dockerfile .
rules:
- if: $CI_COMMIT_BRANCH
Verificación y solución de problemas comunes
Ejecuta los comandos siguientes para validar logs y conectividad. El primer build puede tardar más; los siguientes deberían descargar menos dependencias y saltarse etapas del Dockerfile.
- Si el runner no aparece en GitLab, revisa token y URL.
- Si el caché S3 no funciona, valida endpoint, claves y política del bucket.
- Si buildx falla, comprueba la versión de Docker y del servicio dind.
# Ver logs do runner
sudo docker logs --tail=200 gitlab-runner
# Verificar conectividade e estado do runner
sudo docker exec -it gitlab-runner gitlab-runner verify --delete
# Conferir se o bloco de cache está ativo no config
echo "--- cache config ---" && \
sudo docker exec -it gitlab-runner \
grep -A4 "\[runners.cache\]" /etc/gitlab-runner/config.toml
Operación, seguridad y mantenimiento
Mantén el runner actualizado y dimensionado según tu infraestructura. Las limpiezas agresivas pueden borrar capas y cachés útiles: prográmalas con cuidado. Para criterios de dimensionado y observabilidad, consulta materiales publicados anteriormente.
- Actualiza el contenedor del runner periódicamente y vuelve a subirlo usando el mismo volumen.
- Limita la concurrencia (concurrent) a lo que el host soporta. Criterios en Cómo elegir el tamaño de VPS.
- Monitorea CPU, RAM y disco. Instrumenta con Prometheus y Grafana con Docker Compose.
- Cuidado al ejecutar prune: puede borrar imágenes y cachés útiles; hazlo fuera del horario pico.
# Atualizar imagem do runner e inspecionar estado
sudo docker pull gitlab/gitlab-runner:alpine
sudo docker exec -it gitlab-runner gitlab-runner list
sudo docker exec -it gitlab-runner gitlab-runner status
# Limpeza com cautela (pode remover camadas e caches)
sudo docker system prune -af --volumes
Preguntas frecuentes
¿Necesito usar Docker-in-Docker o el socket del host?
Para el ejecutor Docker es común montar el socket del host en el contenedor del runner. Evita el overhead de DinD y suele ser más simple. Usa DinD cuando quieras aislar totalmente el daemon de Docker por job, aceptando mayor consumo de recursos.
¿Cuál es la diferencia entre el caché del Runner y el caché de Docker (BuildKit)?
El caché del Runner guarda archivos del job, como dependencias de lenguajes. El caché de Docker guarda capas de imagen creadas en el build. Se complementan: el primero acelera tareas de la aplicación; el segundo acelera rebuilds del Dockerfile.
¿Dónde quedan los archivos de caché del Runner?
Con S3/MinIO configurado, los artefactos de caché se envían al bucket definido. Sin S3, el caché queda local en el host del runner, lo que dificulta compartirlo y puede perderse al recrear el contenedor.
¿Cómo limitar la cantidad de jobs concurrentes?
En config.toml ajusta la clave concurrent para definir el número máximo de jobs simultáneos por servicio de runner. Equílibralo con la capacidad del servidor. Observa CPU, memoria y I/O para encontrar el punto óptimo sin generar contención.
¿Puedo usar el mismo caché entre proyectos diferentes?
Sí, si pones Shared = true en el bloque de caché del Runner y usas claves de caché compatibles en los jobs. Evita claves genéricas para no filtrar datos. Buckets separados y prefijos ayudan a aislar proyectos.
¿Cómo rotar credenciales de S3/MinIO de forma segura?
Crea un usuario dedicado con permisos mínimos para el bucket y rota las claves periódicamente. Evita commitear credenciales. Prefiere variables de entorno en el contenedor del runner o mecanismos de secretos del entorno.
¿Quieres acelerar tu CI con seguridad?
Si necesitas ayuda para diseñar el runner self‑hosted, configurar caché remoto y optimizar Dockerfiles y pipelines, podemos conversar y evaluar tu caso.
Hablar sobre tu CI/CDVer también
- Tutorial: implementar Canary releases con Traefik en Docker Compose usando headers y weighted routing para despliegues graduales de aplicaciones PHP
- Tutorial: configurar HAProxy con Let's Encrypt y healthchecks para balanceo de tráfico entre contenedores Docker en VPS (paso a paso)
- Tutorial práctico: implementar mTLS entre Nginx y microservicios usando smallstep CA en Docker Compose
- Tutorial: configurar cgroup v2 y systemd ResourceControl para limitar CPU, memoria e I/O de contenedores Docker en Debian