¿Qué es un pipeline de CI/CD?
Un pipeline de CI/CD (Integración Continua / Despliegue Continuo) automatiza las etapas necesarias para llevar código desde el repositorio hasta producción. En GitLab, todo gira en torno al archivo .gitlab-ci.yml en la raíz del proyecto. Este archivo YAML define los stages (etapas), jobs (tareas) y scripts que se ejecutan automáticamente con cada push o merge request.
Un pipeline típico tiene tres stages: build (compilar y generar artefactos), test (ejecutar pruebas unitarias, linting, análisis de seguridad) y deploy (desplegar en desarrollo, staging o producción). GitLab ejecuta los stages en orden secuencial, pero los jobs dentro de un mismo stage pueden correr en paralelo si no hay dependencias.
Estructura básica de .gitlab-ci.yml
Veamos un ejemplo completo para un proyecto Node.js que construye, prueba y despliega:
stages:
- build
- test
- deploy
variables:
NODE_VERSION: "20-alpine"
APP_NAME: "mi-app"
cache:
paths:
- node_modules/
build-app:
stage: build
image: node:${NODE_VERSION}
script:
- npm install
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
only:
- main
- develop
test-lint:
stage: test
image: node:${NODE_VERSION}
script:
- npm install
- npm run lint
only:
- main
- develop
- merge_requests
test-unit:
stage: test
image: node:${NODE_VERSION}
script:
- npm install
- npm run test:ci
artifacts:
reports:
junit: junit.xml
only:
- main
- develop
- merge_requests
deploy-staging:
stage: deploy
image: alpine:3.19
script:
- apk add --no-cache openssh rsync
- rsync -avz --delete dist/ deploy@staging-server:/var/www/${APP_NAME}/
environment:
name: staging
url: https://staging.midominio.com
only:
- develop
when: manual
deploy-production:
stage: deploy
image: alpine:3.19
script:
- apk add --no-cache openssh rsync
- rsync -avz --delete dist/ deploy@prod-server:/var/www/${APP_NAME}/
environment:
name: production
url: https://midominio.com
only:
- main
when: manual
Variables de CI/CD: protegidas, enmascaradas y por entorno
Nunca pongas credenciales en duro en el archivo YAML. GitLab permite definir variables desde la interfaz web en Settings > CI/CD > Variables:
# Ejemplo de variables definidas en Settings > CI/CD SSH_PRIVATE_KEY: # Tipo: File (protegida, enmascarada) DEPLOY_USER: # Tipo: Variable DEPLOY_SERVER: # Tipo: Variable SLACK_WEBHOOK_URL: # Tipo: Variable (enmascarada) DATABASE_URL: # Tipo: Variable (enmascarada, solo entorno staging) # Puedes usarlas directamente en scripts del .gitlab-ci.yml before_script: - echo "Desplegando en $DEPLOY_SERVER con usuario $DEPLOY_USER" - which ssh-agent || (apk add --no-cache openssh) - eval $(ssh-agent -s) - echo "$SSH_PRIVATE_KEY" | ssh-add -
Las variables protegidas solo están disponibles en ramas o tags protegidos. Las enmascaradas ocultan su valor en los logs del pipeline. Puedes también asignar diferentes valores por entorno (staging, producción) para evitar mezclar configuraciones.
Deploy con rsync y SSH
Para despliegues simples, rsync sobre SSH sigue siendo el método más fiable. El setup requiere configurar las claves SSH como variables protegidas:
.deploy_template: &deploy_template
image: alpine:3.19
before_script:
- apk add --no-cache openssh rsync
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | ssh-add -
- mkdir -p ~/.ssh
- echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
script:
- rsync -avz --delete --exclude='.env' dist/ ${DEPLOY_USER}@${DEPLOY_SERVER}:/var/www/${APP_NAME}/
- echo "✅ Despliegue completado en $(date)"
deploy-prod:
<<: *deploy_template
stage: deploy
environment:
name: production
only:
- main
when: manual
variables:
APP_NAME: "mi-app-prod"
El bloque when: manual convierte el job en un botón que debe pulsarse manualmente desde la interfaz de GitLab. Esto es ideal para evitar despliegues accidentales a producción.
Pipelines programados
Además de ejecutar pipelines con cada push, GitLab permite programarlos con cron. Esto es útil para tareas como limpiar logs, regenerar sitemaps o ejecutar pruebas nocturnas:
# Desde la interfaz: CI/CD > Schedules
# Crear nuevo schedule:
# Description: "Daily cleanup"
# Interval pattern: 0 3 * * * (3:00 AM todos los días)
# Target branch: main
# Variables (opcional):
# CRON_JOB: cleanup
# En el .gitlab-ci.yml:
cleanup-old-logs:
stage: test
script:
- echo "Limpiando logs anteriores a 30 días..."
- find /var/log -name "*.log" -mtime +30 -delete
only:
variables:
- $CRON_JOB == "cleanup"
Combinando pipelines manuales, programados y automáticos, cubres todos los escenarios posibles de un flujo DevOps moderno. GitLab lo hace todo desde una única plataforma, eliminando la necesidad de integrar Jenkins, Ansible Tower y otras herramientas por separado.