Configurar GitLab CI Runner self‑hosted con Docker y caché remoto para acelerar builds: tutorial práctico

Deploy & DevOps · Por · Publicado el · Actualizado el · 8 min de lectura

Contenedores marítimos coloridos apilados bajo un cielo azul
Metáfora visual para contenedores Docker y registros de imágenes Foto: Jan van der Wolf / Pexels

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/CD

Ver también