Pipeline CI/CD con GitLab para un proyecto Astro con despliegue en Docker
· 15min · gitlab, cicd, docker, astro, devops
Introducción
En este post se describe cómo configurar un pipeline CI/CD completo en GitLab para un proyecto Astro. El pipeline cubre todas las fases: compilación del proyecto, construcción y publicación de la imagen Docker en Docker Hub, y despliegue en un servidor remoto tanto con ficheros estáticos como con Docker Compose.
Estructura del pipeline
El fichero .gitlab-ci.yml define cuatro stages que se ejecutan en orden:
- build — compila el proyecto con Node.js
- build-image — construye y publica la imagen Docker en Docker Hub
- test — reservado para pruebas (no implementado en este ejemplo)
- deploy — despliega en el servidor remoto
stages:
- build
- build-image
- test
- deploy
También se configura caché entre jobs para acelerar las ejecuciones:
cache:
paths:
- node_modules
- package-lock.json
- dist
Stage 1: Build del proyecto
El job build-job usa la imagen oficial node:lts para instalar dependencias y compilar el proyecto Astro. El artefacto generado (carpeta dist) se pasa al siguiente stage.
build-job:
stage: build
image: node:lts
before_script:
- npm i
script:
- npm run build
artifacts:
paths:
- dist
expire_in: 1 hour
only:
- master
Stage 2: Construcción y publicación de la imagen Docker
El job build-docker-hub usa Docker-in-Docker (DinD) para construir la imagen y subirla a Docker Hub. Se aprovecha el caché de la imagen anterior para acelerar la construcción.
Las variables de entorno necesarias son:
DOCKER_HUB_PASSWORD— contraseña de Docker Hub (configurada como variable protegida en GitLab)CI_PROJECT_NAMEyCI_COMMIT_SHORT_SHA— variables predefinidas de GitLab
build-docker-hub:
stage: build-image
image: docker:latest
services:
- name: docker:dind
alias: docker
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ''
DOCKER_DRIVER: overlay2
IMAGE_TAG: '$CI_PROJECT_NAME:$CI_COMMIT_SHORT_SHA'
IMAGE_NAME: $CI_PROJECT_NAME
script:
- docker pull pepesan/$IMAGE_NAME:latest || true
- docker build --cache-from pepesan/$IMAGE_NAME:latest -t pepesan/$IMAGE_TAG .
- docker build --cache-from pepesan/$IMAGE_NAME:latest -t pepesan/$IMAGE_NAME:latest .
- echo "$DOCKER_HUB_PASSWORD" | docker login -u pepesan --password-stdin
- docker push pepesan/$IMAGE_NAME:latest
- docker push pepesan/$IMAGE_TAG
only:
- master
Stage 3: Despliegue
Hay dos variantes de despliegue.
Despliegue de ficheros estáticos
El job deploy-job copia la carpeta dist al servidor remoto vía SCP usando una clave SSH almacenada en base64 como variable de GitLab.
deploy-job:
image: cytopia/ansible:latest-aws
stage: deploy
before_script:
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- echo "StrictHostKeyChecking no" >> ~/.ssh/config
- ssh-add <(echo "$SSH_PRIVATE_KEY" | base64 -d)
script:
- ssh $SSH_USER@$SSH_HOST "rm -rf $DEPLOY_PATH/*"
- scp -r dist/* $SSH_USER@$SSH_HOST:$DEPLOY_PATH
- echo Successfully deployed!
only:
- master
Despliegue con Docker Compose
El job deploy-docker-job copia el fichero compose.yaml al servidor y levanta los contenedores con docker compose up -d. Se activa solo desde la rama deploy.
deploy-docker-job:
image: cytopia/ansible:latest-aws
stage: deploy
before_script:
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- echo "StrictHostKeyChecking no" >> ~/.ssh/config
- ssh-add <(echo "$SSH_PRIVATE_KEY_NEW" | base64 -d)
script:
- ssh $SSH_USER_NEW@$SSH_HOST_NEW "mkdir -p $DEPLOY_PATH_NEW"
- ssh $SSH_USER_NEW@$SSH_HOST_NEW "rm -rf $DEPLOY_PATH_NEW/*"
- scp compose.yaml $SSH_USER_NEW@$SSH_HOST_NEW:$DEPLOY_PATH_NEW
- ssh $SSH_USER_NEW@$SSH_HOST_NEW "docker compose -f $DEPLOY_PATH_NEW/compose.yaml up -d"
- echo Successfully deployed!
only:
- deploy
Variables de GitLab necesarias
Hay que configurar las siguientes variables en Settings > CI/CD > Variables del proyecto:
| Variable | Tipo | Descripción |
|---|---|---|
DOCKER_HUB_PASSWORD | Variable | Contraseña de Docker Hub |
SSH_PRIVATE_KEY | Variable | Clave SSH privada en base64 para el servidor de estáticos |
SSH_PRIVATE_KEY_NEW | Variable | Clave SSH privada en base64 para el servidor Docker |
SSH_USER / SSH_HOST | Variable | Usuario y host del servidor de estáticos |
SSH_USER_NEW / SSH_HOST_NEW | Variable | Usuario y host del servidor Docker |
DEPLOY_PATH / DEPLOY_PATH_NEW | Variable | Rutas de despliegue en cada servidor |
Cómo guardar la clave SSH privada en GitLab
Las claves SSH privadas son ficheros multilínea, y esto causa problemas al intentar guardarlas como variable de tipo Variable en GitLab: la interfaz web puede truncar los saltos de línea y corromper la clave.
Opción recomendada: tipo File
GitLab permite crear variables de tipo File. En este caso GitLab escribe el contenido en un fichero temporal y la variable contiene la ruta a ese fichero, preservando el formato multilínea intacto. El before_script queda así:
before_script:
- chmod 400 "$SSH_PRIVATE_KEY"
- eval $(ssh-agent -s)
- ssh-add "$SSH_PRIVATE_KEY"
- mkdir -p ~/.ssh
- echo "StrictHostKeyChecking no" >> ~/.ssh/config
Para crear la variable: en GitLab ve a Settings > CI/CD > Variables, añade una nueva variable, selecciona tipo File y pega directamente el contenido de ~/.ssh/id_rsa (incluyendo las líneas -----BEGIN y -----END).
Opción alternativa: base64 en variable de tipo Variable
Si necesitas una variable de tipo Variable, puedes codificar la clave en base64 para convertirla en una cadena de una sola línea sin espacios ni saltos de línea:
cat ~/.ssh/id_rsa | base64 -w0
Pega el resultado como valor de la variable. En el pipeline hay que decodificarla antes de usarla, que es lo que hace base64 -d en el before_script de este ejemplo. El inconveniente es que las variables con caracteres especiales no pueden enmascararse en GitLab, así que la clave quedará visible en los logs si se imprime accidentalmente.
Conclusión
Con este pipeline CI/CD en GitLab se automatiza completamente el ciclo de vida de un proyecto Astro: desde la compilación hasta el despliegue en producción, con soporte tanto para distribución de ficheros estáticos como para despliegue basado en contenedores Docker. La separación en stages y el uso de variables protegidas de GitLab permite mantener las credenciales seguras y el proceso reproducible.