GitLab CI/CD es una plataforma de integración y entrega continua integrada directamente en GitLab. A diferencia de las herramientas de CI externas que requieren configuración separada y webhooks, GitLab CI/CD lee un único archivo .gitlab-ci.yml de tu repositorio y ejecuta los pipelines automáticamente en cada push. Esta integración estrecha significa que tu código, issues, merge requests y pipelines de despliegue viven todos en un mismo lugar.
Esta guía recorre la configuración de pipelines desde cero: etapas, trabajos, runners, caché, artefactos, variables, entornos y estrategias de despliegue que funcionan en producción real.
Requisitos Previos
- Una cuenta de GitLab (gitlab.com o instancia propia)
- Un repositorio Git alojado en GitLab
- Conocimientos básicos de sintaxis YAML
- Docker instalado (para runners con executor Docker)
- Familiaridad con conceptos de CI/CD (build, test, deploy)
Estructura de un Pipeline de GitLab CI/CD
Un pipeline se compone de etapas que se ejecutan en secuencia y trabajos dentro de cada etapa que corren en paralelo. Esta es la estructura fundamental:
# .gitlab-ci.yml
stages:
- build
- test
- deploy
build-app:
stage: build
image: node:20
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
unit-tests:
stage: test
image: node:20
script:
- npm ci
- npm run test:unit
coverage: '/Lines\s+:\s+(\d+\.?\d*)%/'
integration-tests:
stage: test
image: node:20
services:
- postgres:15
variables:
POSTGRES_DB: test_db
POSTGRES_USER: runner
POSTGRES_PASSWORD: testing
DATABASE_URL: "postgresql://runner:testing@postgres:5432/test_db"
script:
- npm ci
- npm run test:integration
deploy-staging:
stage: deploy
script:
- ./scripts/deploy.sh staging
environment:
name: staging
url: https://staging.example.com
rules:
- if: $CI_COMMIT_BRANCH == "develop"
La etapa build se ejecuta primero. Cuando termina con éxito, ambos trabajos de test corren en paralelo (están en la misma etapa). Solo si todos los tests pasan continúa el despliegue.
Configuración de GitLab Runners
Los runners ejecutan los trabajos del pipeline. Tienes dos opciones:
Runners Compartidos (Inicio Rápido)
GitLab.com ofrece runners compartidos de forma gratuita. Están disponibles de inmediato, sin configuración adicional. Ve a Settings → CI/CD → Runners para verificar que están habilitados.
Runners Propios (Producción)
Para mayor rendimiento y control, instala tu propio runner:
# Instalar GitLab Runner en Ubuntu
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
# Registrar el runner
sudo gitlab-runner register \
--url "https://gitlab.com/" \
--registration-token "YOUR_TOKEN" \
--executor "docker" \
--docker-image "alpine:latest" \
--description "production-runner" \
--tag-list "docker,linux" \
--run-untagged="true"
Comparativa de Executors
| Executor | Aislamiento | Velocidad | Caso de Uso |
|---|---|---|---|
| Docker | Alto (contenedor por trabajo) | Rápido | Opción predeterminada para la mayoría |
| Shell | Ninguno (corre en el host) | Más rápido | Scripts simples, apps legadas |
| Docker Machine | Alto + autoescalado | Variable | Runners con autoescalado en la nube |
| Kubernetes | Alto (pod por trabajo) | Medio | Despliegues nativos en Kubernetes |
| VirtualBox | VM completa | Lento | Cuando se necesita aislamiento total de SO |
Configuración Avanzada de Pipelines
Caché de Dependencias
El caché evita descargar dependencias en cada ejecución del pipeline:
variables:
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm"
cache:
key:
files:
- package-lock.json
paths:
- .npm/
- node_modules/
policy: pull-push
La directiva key.files genera una clave de caché a partir de package-lock.json. Cuando cambian las dependencias, el caché se invalida automáticamente.
Artefactos Entre Etapas
Pasa los resultados de compilación de una etapa a la siguiente:
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
expire_in: 1 week
Reglas del Pipeline y Ejecución Condicional
Controla cuándo se ejecutan los trabajos con rules:
deploy-production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
when: manual
- when: never
Este trabajo solo aparece en tags de versión (v1.2.3) y requiere aprobación manual.
Trabajos en Matriz Paralela
Prueba en múltiples versiones simultáneamente:
test:
stage: test
image: node:${NODE_VERSION}
parallel:
matrix:
- NODE_VERSION: ["18", "20", "22"]
DATABASE: ["postgres", "mysql"]
script:
- npm ci
- npm run test
Esto crea 6 trabajos en paralelo (3 versiones de Node × 2 bases de datos).
Variables de CI/CD y Secretos
Almacena valores sensibles de forma segura:
deploy:
stage: deploy
script:
- echo "$DEPLOY_KEY" > key.pem
- chmod 600 key.pem
- scp -i key.pem dist/* user@server:/var/www/
after_script:
- rm -f key.pem
Escenario real: Tu equipo despliega una aplicación Node.js en tres entornos: desarrollo, staging y producción. Cada entorno tiene distintas credenciales de base de datos, API keys y direcciones de servidor. Almacenas estos valores como variables de GitLab CI/CD con alcance por entorno. El mismo YAML del pipeline gestiona todos los despliegues; solo cambian las variables. Cuando un desarrollador hace push a develop, el pipeline despliega automáticamente en staging. El despliegue a producción se activa únicamente con tags y requiere aprobación manual del líder técnico.
Tipos y Alcance de Variables
| Alcance | Configurado En | Disponible Para |
|---|---|---|
| Project | Settings → CI/CD → Variables | Todos los pipelines del proyecto |
| Group | Group → Settings → CI/CD | Todos los proyectos del grupo |
| Instance | Admin → CI/CD → Variables | Todos los proyectos de la instancia |
| Environment | Settings → CI/CD → Variables (filtro de entorno) | Trabajos que apuntan a ese entorno |
| Job | variables: en .gitlab-ci.yml | Solo ese trabajo específico |
Marca las variables como Protected (disponibles solo en ramas/tags protegidas) y Masked (ocultas en los logs) para las credenciales.
Entornos de Despliegue y Estrategias
Review Apps (Entornos Dinámicos)
Crea un entorno temporal para cada merge request:
review:
stage: deploy
script:
- deploy_review_app "$CI_MERGE_REQUEST_IID"
environment:
name: review/$CI_MERGE_REQUEST_IID
url: https://$CI_MERGE_REQUEST_IID.review.example.com
on_stop: stop-review
rules:
- if: $CI_MERGE_REQUEST_IID
stop-review:
stage: deploy
script:
- teardown_review_app "$CI_MERGE_REQUEST_IID"
environment:
name: review/$CI_MERGE_REQUEST_IID
action: stop
rules:
- if: $CI_MERGE_REQUEST_IID
when: manual
Despliegue a Producción con Rollback
deploy-production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
auto_stop_in: never
rules:
- if: $CI_COMMIT_TAG
when: manual
allow_failure: false
GitLab CI/CD vs Otras Plataformas de CI
| Característica | GitLab CI/CD | GitHub Actions | Jenkins | CircleCI |
|---|---|---|---|---|
| Archivo de Config | .gitlab-ci.yml | .github/workflows/*.yml | Jenkinsfile | .circleci/config.yml |
| Registro Integrado | Sí (contenedor + paquetes) | Sí (contenedor) | No | No |
| Opción Self-hosted | Sí (GitLab completo) | Sí (solo runners) | Sí | No |
| Review Apps | Nativo | Configuración manual | Manual | Manual |
| Pipelines DAG | Sí (keyword needs) | Sí (nativo) | Sí | Sí |
| Auto DevOps | Sí | No | No | No |
| Minutos Gratuitos | 400 min/mes | 2.000 min/mes | Ilimitado (self-host) | 6.000 min/mes |
| Curva de Aprendizaje | Media | Baja | Alta | Baja |
GitLab CI/CD destaca cuando quieres todo integrado: código, CI, registro de contenedores, entornos y monitoreo en una sola plataforma. GitHub Actions gana en amplitud de ecosistema gracias a su marketplace.
Errores Comunes y Casos Especiales
-
Los anchors YAML no funcionan con
include: Si usas anchors YAML (&anchor/*anchor) en archivos incluidos, no se resolverán entre archivos distintos. Usa la palabra claveextendsen su lugar. -
El caché no está garantizado: Los cachés de GitLab son de tipo best-effort. Los runners pueden no compartir cachés entre sí. Diseña siempre pipelines que funcionen sin caché (aunque más lentos).
-
Red de servicios: Los contenedores de servicio (como
postgres:15) son accesibles mediante el nombre de la imagen como hostname. Usapostgres, nolocalhost. Esto confunde a muchos desarrolladores. -
only/exceptvsrules: La sintaxis heredadaonly/exceptes incompatible conrules. Nunca los mezcles en el mismo trabajo. Prefiererules; es más potente y es el enfoque recomendado. -
El timeout de trabajos es 1 hora por defecto: Los trabajos de larga duración, como pruebas E2E o compilaciones grandes, fallan silenciosamente al alcanzar el timeout. Define
timeout: 2hexplícitamente para trabajos que sabes que duran más. -
Variables de ramas protegidas: Las variables marcadas como “Protected” no están disponibles en ramas de funcionalidades. Si un trabajo necesita credenciales en ramas no protegidas, usa una variable separada sin el flag de protección.
Solución de Problemas
| Problema | Causa | Solución |
|---|---|---|
| Pipeline atascado en “Pending” | No hay runners disponibles con las etiquetas correctas | Revisa las etiquetas del runner o define tags: [] para usar cualquiera |
| ”Cache not found” en la primera ejecución | El caché aún no se ha creado | La primera ejecución descarga todo; el caché se llena para las siguientes |
| Servicios no accesibles | Hostname incorrecto en la cadena de conexión | Usa el nombre de la imagen del servicio como hostname (p. ej., postgres, no localhost) |
| “Variable is not set” en trabajos | La variable está protegida y la rama no lo está | Desmarca “Protected” o haz push a una rama protegida |
| Artefactos faltantes en la siguiente etapa | artifacts.paths no coincide con la salida | Verifica las rutas exactas; usa ls -la en el script para depurar |
Resumen
- GitLab CI/CD lee
.gitlab-ci.ymlde tu repositorio y ejecuta pipelines automáticamente, sin necesidad de configurar herramientas externas - Las etapas se ejecutan en secuencia mientras que los trabajos dentro de una etapa corren en paralelo, combinando orden y velocidad
- Los runners propios con executor Docker ofrecen el mejor rendimiento y control para equipos en producción
- El caché de dependencias y los artefactos entre etapas reducen drásticamente el tiempo de ejecución del pipeline
- Las variables de entorno con enmascaramiento, protección y alcance por entorno mantienen los secretos seguros en todos los despliegues
- Las review apps crean entornos temporales por merge request, permitiendo revisión visual antes de hacer merge