⚠ Vigencia por confirmar. Esta guía se solapa con CI/CD con runners self-hosted y con Despliegue de EcommerceV2Backend, y contradice a la primera respecto de dónde van las SSH keys del runner (acá: directorio de trabajo del runner; allá:
~/.sshdel usuario del servicio). Confirmar cuál aplica antes de seguirla.
Guía de Despliegue Automatizado¶
Este documento describe el setup completo de CI/CD para desplegar Medusa en staging y producción mediante GitHub Actions con runners self-hosted.
Arquitectura¶
Push a rama
↓
├─ staging: Auto-deploy a servidor de staging
│ └─ Runner self-hosted en servidor de staging
│ └─ Ejecuta ./deploy.sh con tag staging-*
│
└─ main: Deploy a producción CON APROBACIÓN
└─ Requiere aprobación en GitHub
└─ Runner self-hosted en servidor de producción
└─ Ejecuta ./deploy.sh con tag sha-*
Prerrequisitos¶
- GitHub repository:
CompulandiaTI/EcommerceV2Backend - Servidor de staging con Docker instalado
- Servidor de producción con Docker instalado
- Acceso administrativo a ambos servidores
- Acceso a la configuración del repositorio en GitHub
Paso 1: Configurar Runners Self-Hosted¶
Los runners permiten que GitHub Actions ejecute jobs en tus servidores privados (sin exponer credenciales).
1.1 En el servidor de STAGING¶
# 1. Crear directorio de trabajo
mkdir -p /opt/github-runner-staging
cd /opt/github-runner-staging
# 2. Descargar el runner (usa la versión más reciente desde GitHub)
curl -o actions-runner-linux-x64.tar.gz -L https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz
tar xzf ./actions-runner-linux-x64.tar.gz
rm actions-runner-linux-x64.tar.gz
# 3. En GitHub: Settings → Actions → Runners → New runner self-hosted
# Selecciona: Linux, x64
# Copia el token de configuración (válido 1 hora)
# 4. Ejecutar configuración (pega el token de GitHub)
./config.sh --url https://github.com/CompulandiaTI/EcommerceV2Backend --token <PASTE_TOKEN_HERE>
# Preguntas:
# - name: staging
# - work folder: _work
# - labels: staging (importante: label debe coincidir con runs-on: [self-hosted, staging])
# 5. Instalar como servicio systemd (para que arranque automáticamente)
sudo ./svc.sh install
sudo systemctl start actions-runner
sudo systemctl enable actions-runner
# 6. Verificar que está corriendo
sudo systemctl status actions-runner
1.2 En el servidor de PRODUCCIÓN¶
Repite lo anterior pero:
- Directorio: /opt/github-runner-production
- Name: production
- Labels: production
- Los comandos systemd son iguales
Después de configurar, ambos runners aparecerán en GitHub → Settings → Actions → Runners como "Idle" y green.
Paso 2: Configurar SSH para Git (Deploy Keys)¶
El runner necesita poder hacer git fetch del repositorio para actualizar archivos de despliegue.
En ambos servidores:
# IMPORTANTE: La SSH key debe estar en el WORKING DIRECTORY del runner,
# NO en /home/username/.ssh/
# El runner en staging corre desde: /opt/github-runner-staging
# El runner en producción corre desde: /opt/github-runner-production
# 1. Generar SSH key en el directorio de trabajo del runner
# Reemplaza RUNNER_DIR según tu servidor (staging o producción)
RUNNER_DIR=/opt/github-runner-staging
USER=_svc_actions_staging
sudo mkdir -p $RUNNER_DIR/.ssh
sudo ssh-keygen -t rsa -f $RUNNER_DIR/.ssh/id_rsa -N "" -C "$USER@runner"
# 2. Permisos correctos
sudo chown -R $USER:$USER $RUNNER_DIR/.ssh
sudo chmod 700 $RUNNER_DIR/.ssh
sudo chmod 600 $RUNNER_DIR/.ssh/id_rsa
# 3. Copiar la public key
sudo cat $RUNNER_DIR/.ssh/id_rsa.pub
En GitHub:
- Ir a repo → Settings → Deploy Keys
- Click "Add deploy key"
- Title:
staging-runner(oproduction-runner) - Key: (pega el contenido de
id_rsa.pub) - ✅ Allow write access (si el runner necesita hacer push)
- Click "Add key"
Verificar:
# En el servidor, probar que SSH funciona
RUNNER_DIR=/opt/github-runner-staging
USER=_svc_actions_staging
# Test 1: Autenticación SSH
sudo -u $USER ssh -T git@github.com
# Debería responder: "Hi CompulandiaTI/EcommerceV2Backend! You've successfully authenticated..."
# Test 2: Git clone
sudo -u $USER git clone git@github.com:CompulandiaTI/EcommerceV2Backend.git /tmp/test-clone
rm -rf /tmp/test-clone
# Debería clonar sin pedir contraseña
Paso 3: Autenticar Acceso a GHCR (Image Registry)¶
El servidor necesita poder hacer pull de la imagen privada en GHCR.
En ambos servidores:
# 1. Crear un Personal Access Token (PAT) en GitHub
# GitHub → Settings → Developer settings → Personal access tokens (classic)
# Permisos: read:packages
# Copia el token (ej. ghp_xxxxx...)
# 2. En el servidor, hacer login a GHCR
echo "ghp_xxxxx..." | docker login ghcr.io -u TU_USUARIO_GITHUB --password-stdin
# Esto guarda las credenciales en ~/.docker/config.json
# Verificar: docker logout ghcr.io && docker login ghcr.io (debería funcionar sin pedir token)
Paso 3: Configurar GitHub Environment (Producción con Aprobación)¶
En GitHub, los "environments" permiten requerir aprobación antes de ejecutar ciertos jobs.
En GitHub:
1. Ir a repo → Settings → Environments
2. Click "New environment"
3. Nombre: production
4. Click "Add protection rules" (opcional, pero recomendado)
- ✅ Require reviewers: Selecciona quién puede aprobar (ej. tu usuario o equipo)
- ✅ Restrict deployments to deployment branches: main (solo desde main se despliega)
- Save
A partir de ahora, cuando un workflow intente acceder al environment production, requerirá aprobación de una de las personas configuradas.
Paso 4: El Workflow en Acción¶
Ahora el setup está listo. Así funciona:
Push a staging:¶
git push origin staging
En GitHub → Actions → Workflows:
1. Build corre en GitHub runners → publica imagen con tags staging-latest y staging-sha-abc123
2. Deploy-staging corre automáticamente en el runner de staging
- Ejecuta ./deploy.sh con MEDUSA_TAG=staging-sha-abc123
- Hace pg_dump previo
- Publica la imagen
- Verifica health check
- Si falla, auto-rollback a versión anterior
Push a main:¶
git push origin main
En GitHub → Actions → Workflows:
1. Build corre en GitHub runners → publica imagen con tags latest y sha-abc123
2. Deploy-prod espera aprobación:
- En GitHub UI: Actions → Workflow run → "Review deployments"
- Aprueba o rechaza
- Si aprueba: corre en runner de producción
- Ejecuta ./deploy.sh con MEDUSA_TAG=sha-abc123
- Hace pg_dump + deploy + health check + rollback si falla
Paso 5: Verificar que Funciona¶
Prueba 1: Verificar runners registrados¶
En GitHub → Settings → Actions → Runners:
- Debes ver dos runners: staging y production (ambos "Idle" en verde)
Prueba 2: Primer push a staging¶
# En development local
git checkout staging
git pull
# Hacer un cambio trivial (ej. comentario en README)
git add .
git commit -m "test: verificar workflow"
git push origin staging
En GitHub → Actions:
- El workflow "Build, Test & Deploy" debería ejecutarse
- "Build" completa ✅
- "Deploy-staging" ejecuta automáticamente ✅
- Revisar logs para confirmar que ./deploy.sh corrió
Si pasa health check:
✅ Despliegue OK (tag: staging-sha-abc123)
Prueba 3: Push a main (requiere aprobación)¶
git checkout main
git pull
git merge staging
git push origin main
En GitHub → Actions: - "Build" completa ✅ - "Deploy-prod" se queda en "waiting" (amarillo) - Click en el workflow → "Review deployments" - Selecciona "production" environment - Click "Approve" - El job se ejecuta en el runner de producción
Paso 6: Rollback Manual¶
Si necesitas revertir a una versión anterior (sin esperar a un nuevo push):
# En el servidor de producción
MEDUSA_TAG=staging-sha-abc123 ./deploy.sh
Los tags disponibles están en GHCR (GitHub → repo → Packages).
Operación Normal¶
Deploy a staging:¶
git push origin staging # Auto-deploy, sin aprobación
Deploy a producción:¶
git checkout main
git merge staging # Fusiona cambios probados de staging
git push origin main # Dispara workflow
# En GitHub UI: aprueba el deployment
Solución de Problemas¶
Runner no se conecta a GitHub¶
# En el servidor, revisar logs
sudo journalctl -u actions-runner -f
# Reiniciar el runner
sudo systemctl restart actions-runner
Deploy falla con "permission denied" al ejecutar ./deploy.sh¶
# En el servidor, asegurar que deploy.sh es ejecutable
chmod +x /path/to/repo/deploy.sh
docker login falla en el runner¶
- El runner corre como usuario específico. Verifica que ese usuario pueda acceder a
~/.docker/config.json - O ejecuta
docker logincomo el mismo usuario que corre el runner:sudo -u _svc_actions docker login ghcr.io # si el runner corre como _svc_actions
No ve el runner en GitHub¶
- Verifica que la URL del repo sea correcta (https://github.com/CompulandiaTI/EcommerceV2Backend)
- Revisa que el token no haya expirado (válido 1 hora durante config)
- Rerun
./config.shcon un token nuevo
Archivos clave¶
.github/workflows/build-deploy.yml— El workflow completodeploy.sh— Script de despliegue en cada servidordocker-compose.yml— Parametrizado con${MEDUSA_TAG}Dockerfile— Multi-stage, genera imagen para GHCR
Convenciones de Tags en GHCR¶
| Tag | Rama | Cuándo |
|---|---|---|
staging-latest |
staging | Última versión en staging |
staging-sha-abc123 |
staging | Commit específico en staging |
latest |
main | Última versión en producción |
sha-abc123 |
main | Commit específico en producción |
Ejemplo de rollback manual:
# Revertir a un commit anterior
MEDUSA_TAG=sha-def456 ./deploy.sh
¿Preguntas o aclaraciones necesarias?