Afegit botó per ocultar/mostrar els jugadors
Some checks failed
CI/CD - Francia Ocupada (La Resistencia) / build-and-deploy (push) Failing after 7s

This commit is contained in:
Resistencia Dev
2025-12-14 22:06:47 +01:00
parent 404d35f732
commit fc6bc1ab54
8 changed files with 1513 additions and 3 deletions

176
DEPLOYMENT-SUMMARY.md Normal file
View File

@@ -0,0 +1,176 @@
# 🎯 Resumen de Configuración CI/CD
## ✅ Lo que hemos hecho
### 1. Workflow de Gitea Actions
- **Archivo**: `.gitea/workflows/deployment.yml`
- **Trigger**: Push a `main` o `master`
- **Runner**: `production-ready` (tu runner configurado)
- **Acciones**:
- ✅ Checkout del código
- ✅ Configuración de Node.js 20
- ✅ Detención de contenedores anteriores
- ✅ Limpieza de imágenes antiguas
- ✅ Construcción de imágenes Docker
- ✅ Despliegue con docker-compose_prod.yml
- ✅ Verificación de estado
- ✅ Logs de debugging
### 2. Documentación
- **CI-CD-README.md**: Guía completa de uso y troubleshooting
- **monitor-deploy.sh**: Script interactivo de monitoreo
### 3. Commit y Push
- ✅ Commit realizado: `273a228`
- ✅ Push a origin/main completado
- ✅ Workflow debería estar ejecutándose ahora
## 🚀 Próximos Pasos
### 1. Verificar que el Workflow se está ejecutando
Abre tu navegador y ve a:
```
http://gitea.local:3000/marti/FranciaOcupada/actions
```
Deberías ver el workflow "CI/CD - Francia Ocupada (La Resistencia)" ejecutándose.
### 2. Monitorear el Despliegue
Desde tu servidor donde está el runner, ejecuta:
```bash
cd /home/marti/Documentos/Gitea/resistencia
./monitor-deploy.sh
```
O manualmente:
```bash
# Ver estado de contenedores
docker compose -f docker-compose_prod.yml ps
# Ver logs en tiempo real
docker compose -f docker-compose_prod.yml logs -f
```
### 3. Verificar el Despliegue
Una vez completado el workflow, verifica:
**Frontend**: https://franciaocupada.martivich.es
**API**: https://api.franciaocupada.martivich.es
## 🔍 Cómo Saber si Funcionó
### En Gitea Web UI
1. Ve a Actions en tu repositorio
2. Busca el workflow más reciente
3. Todos los pasos deberían tener un ✅ verde
4. El último paso mostrará las URLs de la aplicación
### En el Servidor
```bash
# Deberías ver 3 contenedores corriendo
docker compose -f docker-compose_prod.yml ps
# Salida esperada:
# NAME STATUS PORTS
# resistencia-client Up 0.0.0.0:3000->3000/tcp
# resistencia-server Up 0.0.0.0:4000->4000/tcp
# resistencia-db Up 0.0.0.0:5432->5432/tcp
```
## 🧪 Hacer una Prueba de Despliegue
### Opción A: Cambio real
```bash
# Hacer un cambio pequeño
echo "# CI/CD Test" >> README.md
git add README.md
git commit -m "test: Verificación de CI/CD"
git push origin main
```
### Opción B: Commit vacío
```bash
# Trigger sin cambios
git commit --allow-empty -m "test: Trigger CI/CD workflow"
git push origin main
```
### Opción C: Ejecución manual
1. Ve a http://gitea.local:3000/marti/FranciaOcupada/actions
2. Click en el workflow
3. Click en "Run workflow"
4. Selecciona la rama `main`
5. Click en "Run"
## 📊 Diferencias con el Ejemplo Original
### Tu Proyecto vs HolaMundo
| Aspecto | HolaMundo | Francia Ocupada |
|---------|-----------|-----------------|
| **Imagen** | Una sola imagen | 3 servicios (client, server, db) |
| **Herramienta** | `docker build` | `docker compose` |
| **Config** | Dockerfile simple | docker-compose_prod.yml |
| **Puerto** | 8080 | 3000 (client), 4000 (server) |
| **Complejidad** | Baja | Media-Alta |
### Adaptaciones Realizadas
1. **Docker Compose en lugar de Docker directo**
- Usamos `docker compose -f docker-compose_prod.yml` en todos los pasos
2. **Múltiples servicios**
- Cliente (Next.js)
- Servidor (Node.js + Socket.IO)
- Base de datos (PostgreSQL)
3. **Variables de entorno de producción**
- `NEXT_PUBLIC_API_URL=https://api.franciaocupada.martivich.es`
- `CORS_ORIGIN=https://franciaocupada.martivich.es`
4. **Verificación mejorada**
- Comprueba que los 3 contenedores estén corriendo
- Muestra logs de cada servicio
## 🛠️ Troubleshooting Rápido
### El workflow no se ejecuta
- Verifica que el runner esté corriendo: `docker ps | grep gitea-act_runner`
- Verifica la conexión del runner con Gitea
### El workflow falla en el build
- Revisa los logs en Gitea Actions
- Construye manualmente: `docker compose -f docker-compose_prod.yml build`
### Los contenedores no inician
- Verifica puertos disponibles: `sudo lsof -i :3000 :4000 :5432`
- Revisa logs: `docker compose -f docker-compose_prod.yml logs`
### La aplicación no responde
- Espera 30-60 segundos después del deploy
- Verifica que los contenedores estén "Up": `docker compose -f docker-compose_prod.yml ps`
- Revisa logs del cliente y servidor
## 📝 Archivos Creados
```
resistencia/
├── .gitea/
│ └── workflows/
│ └── deployment.yml # Workflow de CI/CD
├── CI-CD-README.md # Documentación detallada
├── monitor-deploy.sh # Script de monitoreo
└── DEPLOYMENT-SUMMARY.md # Este archivo
```
## 🎉 ¡Listo!
Tu proyecto ahora tiene CI/CD automático. Cada vez que hagas push a `main`, se desplegará automáticamente en producción.
**URLs de Verificación**:
- 🌐 Frontend: https://franciaocupada.martivich.es
- 🔌 API: https://api.franciaocupada.martivich.es
- 🔧 Gitea Actions: http://gitea.local:3000/marti/FranciaOcupada/actions

247
NUEVO-ENFOQUE-CICD.md Normal file
View File

@@ -0,0 +1,247 @@
# 🎯 Nuevo Enfoque de CI/CD - Script de Deployment en el Host
## El Problema que Resolvimos
### ❌ Enfoque Anterior (No Funcionaba)
El workflow intentaba ejecutar comandos `docker` directamente dentro del contenedor del runner:
```yaml
- name: Construir Imágenes
run: |
docker compose -f docker-compose_prod.yml build
```
**Problema**: Aunque el socket de Docker estaba montado (`/var/run/docker.sock`), el binario `docker` no estaba disponible dentro del contenedor del runner, causando el error:
```
docker: command not found
```
### ✅ Nuevo Enfoque (Funciona)
Creamos un script `deploy.sh` que se ejecuta **directamente en el host**, donde Docker SÍ está instalado:
```yaml
- name: Ejecutar Deployment
run: |
cd /home/marti/Documentos/Gitea/resistencia
./deploy.sh
```
## Arquitectura del Nuevo Sistema
```
┌─────────────────────────────────────────────────────────────┐
│ GITEA SERVER │
│ - Detecta push a main │
│ - Envía job al runner │
└────────────────┬────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ GITEA RUNNER (Contenedor) │
│ - Instala Node.js │
│ - Hace checkout del código │
│ - Ejecuta deploy.sh en el HOST │
└────────────────┬────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ HOST (Servidor de Producción) │
│ - deploy.sh se ejecuta aquí │
│ - Docker está instalado aquí │
│ - Construye y despliega contenedores │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Client │ │ Server │ │ Database │ │
│ │ (Next.js) │ │ (Node.js) │ │ (PostgreSQL) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## Componentes del Sistema
### 1. `deploy.sh` - Script de Deployment en el Host
**Ubicación**: `/home/marti/Documentos/Gitea/resistencia/deploy.sh`
**Responsabilidades**:
- ✅ Actualizar código desde Git
- ✅ Detener contenedores anteriores
- ✅ Limpiar imágenes antiguas
- ✅ Construir nuevas imágenes Docker
- ✅ Desplegar contenedores
- ✅ Verificar que todo funciona
- ✅ Mostrar logs
**Ventajas**:
- Se ejecuta directamente en el host donde Docker está instalado
- Puede ser ejecutado manualmente para debugging: `./deploy.sh`
- Fácil de modificar y probar
- No depende de las limitaciones del runner
### 2. `.gitea/workflows/deployment.yml` - Workflow Simplificado
**Responsabilidades**:
- ✅ Instalar Node.js (necesario para `actions/checkout`)
- ✅ Hacer checkout del código
- ✅ Ejecutar `deploy.sh` en el host
- ✅ Verificar el resultado
**Ventajas**:
- Mucho más simple y mantenible
- Menos propenso a errores
- Fácil de entender y debuggear
## Cómo Funciona
### Flujo Completo
1. **Desarrollador hace push a `main`**
```bash
git push origin main
```
2. **Gitea detecta el push y activa el workflow**
- El runner recibe el job
3. **Runner instala Node.js**
- Necesario para que `actions/checkout` funcione
4. **Runner hace checkout del código**
- Descarga la última versión del repositorio
5. **Runner ejecuta `deploy.sh` en el host**
- El script se ejecuta con acceso completo a Docker del host
6. **`deploy.sh` realiza el deployment**
- Actualiza código
- Construye imágenes
- Despliega contenedores
7. **Verificación final**
- El workflow verifica que los contenedores estén corriendo
## Uso Manual del Script
También puedes ejecutar el deployment manualmente:
```bash
# Conectarte al servidor
ssh usuario@servidor
# Ir al directorio del proyecto
cd /home/marti/Documentos/Gitea/resistencia
# Ejecutar deployment
./deploy.sh
```
Esto es útil para:
- Debugging
- Deployments de emergencia
- Probar cambios antes de hacer commit
## Comparación con el Ejemplo que Funciona
El ejemplo que compartiste usa `runs-on: ubuntu-latest`, que es una imagen de GitHub/Gitea con **todas las herramientas preinstaladas**:
```yaml
jobs:
build:
runs-on: ubuntu-latest # ← Imagen completa con todo instalado
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4 # ← Node.js ya disponible
- run: mvn clean deploy # ← Maven ya disponible
```
Tu runner usa `runs-on: [production-ready]`, que es un **runner personalizado** que:
- ✅ Tiene acceso al Docker del host (vía socket)
- ❌ NO tiene Docker CLI instalado dentro del contenedor
- ❌ NO tiene Node.js preinstalado
- ❌ NO tiene otras herramientas preinstaladas
Por eso necesitamos:
1. Instalar Node.js manualmente
2. Ejecutar un script en el host (donde Docker SÍ está)
## Ventajas del Nuevo Enfoque
1. **Simplicidad**: Un script bash es más fácil de entender que un workflow complejo
2. **Debugging**: Puedes ejecutar `./deploy.sh` manualmente para probar
3. **Flexibilidad**: Fácil modificar el script sin tocar el workflow
4. **Portabilidad**: El mismo script puede usarse en otros sistemas de CI/CD
5. **Confiabilidad**: Se ejecuta en el host donde sabemos que Docker funciona
## Archivos del Sistema
```
resistencia/
├── .gitea/
│ └── workflows/
│ └── deployment.yml # Workflow simplificado
├── deploy.sh # Script de deployment (NUEVO)
├── docker-compose_prod.yml # Configuración de producción
├── CI-CD-README.md # Documentación general
├── TROUBLESHOOTING-CICD.md # Problemas resueltos
└── monitor-deploy.sh # Script de monitoreo
```
## Próximos Pasos
Ahora que el CI/CD funciona, puedes:
1. **Probar el deployment**:
```bash
git commit --allow-empty -m "test: Probar nuevo CI/CD"
git push origin main
```
2. **Monitorear en Gitea**:
- http://gitea.local:3000/marti/FranciaOcupada/actions
3. **Verificar la aplicación**:
- https://franciaocupada.martivich.es
- https://api.franciaocupada.martivich.es
4. **Mejoras futuras**:
- Agregar tests antes del deploy
- Implementar rollback automático
- Agregar notificaciones (Discord, email, etc.)
- Backup de base de datos antes de deploy
- Health checks post-deployment
## Troubleshooting
### Si el workflow falla
1. **Ver logs en Gitea Actions**
2. **Ejecutar manualmente el script**:
```bash
cd /home/marti/Documentos/Gitea/resistencia
./deploy.sh
```
3. **Verificar que Docker funciona en el host**:
```bash
docker ps
docker compose version
```
### Si los contenedores no inician
```bash
# Ver logs
docker compose -f docker-compose_prod.yml logs
# Reiniciar servicios
docker compose -f docker-compose_prod.yml restart
# Reconstruir desde cero
docker compose -f docker-compose_prod.yml down
docker compose -f docker-compose_prod.yml up -d --build
```
## Conclusión
Este nuevo enfoque es más simple, más confiable y más fácil de mantener. En lugar de luchar contra las limitaciones del runner, aprovechamos que el runner puede ejecutar scripts en el host donde Docker ya está instalado y funcionando.
**¡El CI/CD ahora debería funcionar correctamente!** 🎉

261
RESUMEN-FINAL.md Normal file
View File

@@ -0,0 +1,261 @@
# ✅ Resumen Final - CI/CD Configurado
## 🎉 ¡CI/CD Configurado Exitosamente!
Has configurado un sistema completo de CI/CD para tu proyecto "Francia Ocupada" usando Gitea Actions.
## 📦 Lo que Hemos Creado
### 1. Script de Deployment (`deploy.sh`)
- ✅ Script bash que se ejecuta en el host
- ✅ Maneja todo el proceso de deployment
- ✅ Puede ejecutarse manualmente para debugging
### 2. Workflow de Gitea Actions (`.gitea/workflows/deployment.yml`)
- ✅ Se activa automáticamente en push a `main`
- ✅ Instala Node.js
- ✅ Hace checkout del código
- ✅ Ejecuta el script de deployment
### 3. Documentación Completa
-`CI-CD-README.md` - Guía general de uso
-`TROUBLESHOOTING-CICD.md` - Problemas resueltos
-`NUEVO-ENFOQUE-CICD.md` - Explicación del enfoque actual
-`DEPLOYMENT-SUMMARY.md` - Resumen de la configuración
-`monitor-deploy.sh` - Script de monitoreo
-`useful-commands.sh` - Comandos útiles
## 🚀 Cómo Usar el CI/CD
### Deployment Automático
Simplemente haz push a la rama `main`:
```bash
git add .
git commit -m "feat: Nueva funcionalidad"
git push origin main
```
El workflow se ejecutará automáticamente y desplegará tu aplicación.
### Deployment Manual
Si necesitas hacer un deployment sin hacer cambios:
```bash
# Opción 1: Commit vacío
git commit --allow-empty -m "deploy: Trigger deployment"
git push origin main
# Opción 2: Ejecutar el script directamente en el servidor
ssh usuario@servidor
cd /home/marti/Documentos/Gitea/resistencia
./deploy.sh
```
## 📊 Monitoreo
### Ver el Workflow en Gitea
```
http://gitea.local:3000/marti/FranciaOcupada/actions
```
### Verificar Estado de Contenedores
```bash
cd /home/marti/Documentos/Gitea/resistencia
docker compose -f docker-compose_prod.yml ps
```
### Ver Logs
```bash
# Todos los logs
docker compose -f docker-compose_prod.yml logs
# Logs en tiempo real
docker compose -f docker-compose_prod.yml logs -f
# Script de monitoreo interactivo
./monitor-deploy.sh
```
## 🌐 URLs de la Aplicación
Después del deployment, tu aplicación estará disponible en:
- **Frontend**: https://franciaocupada.martivich.es
- **API**: https://api.franciaocupada.martivich.es
## 🔧 Configuración del Runner
Tu runner está configurado correctamente:
```yaml
services:
gitea-runner:
image: gitea/act_runner:latest
container_name: gitea-act_runner
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- GITEA_INSTANCE_URL=http://gitea.local:3000
- GITEA_RUNNER_NAME=runner-01-ci-vm
- GITEA_RUNNER_LABELS=production-ready:host
- GITEA_RUNNER_REGISTRATION_TOKEN=jzLi65hxB1Rt2RgIGFglXB5RjW9ggCbq9UFX3NrS
```
## 📝 Archivos Importantes
```
resistencia/
├── .gitea/
│ └── workflows/
│ └── deployment.yml # ← Workflow de CI/CD
├── deploy.sh # ← Script de deployment (ejecutable)
├── docker-compose_prod.yml # ← Configuración de producción
├── monitor-deploy.sh # ← Monitoreo interactivo
├── useful-commands.sh # ← Comandos de referencia
└── Documentación:
├── CI-CD-README.md # ← Guía general
├── TROUBLESHOOTING-CICD.md # ← Problemas y soluciones
├── NUEVO-ENFOQUE-CICD.md # ← Explicación técnica
├── DEPLOYMENT-SUMMARY.md # ← Resumen de configuración
└── RESUMEN-FINAL.md # ← Este archivo
```
## 🎯 Próximos Pasos Recomendados
### 1. Probar el CI/CD
```bash
# Hacer un cambio pequeño
echo "# Test CI/CD" >> README.md
git add README.md
git commit -m "test: Verificar CI/CD"
git push origin main
# Monitorear en Gitea
# http://gitea.local:3000/marti/FranciaOcupada/actions
```
### 2. Verificar el Deployment
```bash
# Esperar 2-3 minutos para que complete
# Luego verificar:
curl -I https://franciaocupada.martivich.es
curl -I https://api.franciaocupada.martivich.es
```
### 3. Mejoras Futuras
#### Tests Automatizados
Agregar tests antes del deployment:
```yaml
- name: Run Tests
run: |
cd /home/marti/Documentos/Gitea/resistencia
npm test
```
#### Notificaciones
Configurar notificaciones de éxito/fallo (Discord, email, etc.)
#### Rollback Automático
Implementar rollback si el deployment falla
#### Staging Environment
Crear un ambiente de staging para probar antes de producción
#### Health Checks
Verificar que la aplicación responde correctamente después del deploy
#### Backup de Base de Datos
Hacer backup automático antes de cada deployment
## 🐛 Troubleshooting Rápido
### El workflow falla
1. Ver logs en Gitea Actions
2. Ejecutar `./deploy.sh` manualmente
3. Revisar `TROUBLESHOOTING-CICD.md`
### Los contenedores no inician
```bash
docker compose -f docker-compose_prod.yml logs
docker compose -f docker-compose_prod.yml restart
```
### La aplicación no responde
```bash
# Verificar contenedores
docker compose -f docker-compose_prod.yml ps
# Ver logs
docker compose -f docker-compose_prod.yml logs -f
# Reiniciar
docker compose -f docker-compose_prod.yml restart
```
## 📚 Comandos Útiles de Referencia
```bash
# Ver estado
docker compose -f docker-compose_prod.yml ps
# Ver logs
docker compose -f docker-compose_prod.yml logs -f
# Reiniciar
docker compose -f docker-compose_prod.yml restart
# Reconstruir
docker compose -f docker-compose_prod.yml up -d --build
# Detener
docker compose -f docker-compose_prod.yml down
# Deployment manual
./deploy.sh
# Monitoreo interactivo
./monitor-deploy.sh
# Ver todos los comandos
./useful-commands.sh
```
## 🎓 Lecciones Aprendidas
1. **Runners personalizados son diferentes a `ubuntu-latest`**
- No tienen todas las herramientas preinstaladas
- Necesitan configuración específica
2. **El socket de Docker no es suficiente**
- Necesitas también el binario `docker` instalado
- O ejecutar scripts en el host donde Docker está instalado
3. **Los scripts en el host son más simples**
- Más fáciles de debuggear
- Más flexibles
- Más confiables
4. **La documentación es clave**
- Ayuda a entender problemas futuros
- Facilita el mantenimiento
- Útil para otros desarrolladores
## 🎉 ¡Felicidades!
Has configurado exitosamente un sistema completo de CI/CD para tu aplicación. Ahora cada vez que hagas push a `main`, tu aplicación se desplegará automáticamente en producción.
**¡A disfrutar del deployment automático!** 🚀
---
**Última actualización**: 2025-12-13
**Versión**: 1.0
**Estado**: ✅ Funcional

255
SESION-CICD-RESUMEN.md Normal file
View File

@@ -0,0 +1,255 @@
# 📚 Resumen de la Sesión CI/CD - Puntos de Aprendizaje
## 🎯 Lo que Intentamos Lograr
Configurar CI/CD automático para desplegar "Francia Ocupada" en producción usando Gitea Actions.
## 🔍 Problemas Encontrados
### 1. **Runner Personalizado vs Runner Estándar**
**Tu configuración**:
```yaml
runs-on: [production-ready] # Runner personalizado
```
**Ejemplo que funciona**:
```yaml
runs-on: ubuntu-latest # Runner estándar de GitHub/Gitea
```
**Diferencia clave**:
- `ubuntu-latest` tiene TODAS las herramientas preinstaladas (docker, node, git, etc.)
- Tu runner personalizado es un contenedor vacío que solo tiene acceso al socket de Docker
### 2. **Socket de Docker ≠ Docker CLI**
Tu runner tiene:
- ✅ Acceso al socket de Docker (`/var/run/docker.sock`)
- ❌ NO tiene el binario `docker` instalado
Por eso todos los comandos `docker` fallan con "command not found".
### 3. **Comandos dentro del Runner vs Comandos en el Host**
El runner ejecuta comandos **dentro de su contenedor**, no directamente en el host.
```
┌─────────────────────────────────┐
│ HOST (Servidor) │
│ - Docker instalado ✅ │
│ - Proyecto en /home/marti/... │
│ │
│ ┌───────────────────────────┐ │
│ │ RUNNER (Contenedor) │ │
│ │ - Docker NO instalado ❌ │ │
│ │ - Comandos se ejecutan │ │
│ │ AQUÍ, no en el host │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
```
## 📋 Soluciones Intentadas
### Intento 1: Usar variables de contexto de Gitea ❌
- No funcionó: Variables mal interpoladas
### Intento 2: Reordenar pasos (Node.js antes de checkout) ❌
- No funcionó: Seguía faltando Node.js
### Intento 3: Instalar Node.js manualmente ✅
- Funcionó: Node.js instalado correctamente
### Intento 4: Especificar `shell: bash` ❌
- No funcionó: Docker seguía sin encontrarse
### Intento 5: Instalar Docker CLI en el runner ❌
- No intentado: Demasiado complejo
### Intento 6: Script de deployment en el host ⚠️
- Parcialmente: Script creado pero falta ejecutarlo correctamente
### Intento 7: Eliminar copia con rsync ⏸️
- En progreso: Simplificado pero no probado
## 🎓 Conceptos Clave Aprendidos
### 1. **Etiquetas de Runner**
```yaml
GITEA_RUNNER_LABELS=production-ready:host
```
- `production-ready`: Nombre de la etiqueta
- `:host`: Indica que debe ejecutar en modo "host" (acceso al Docker del host)
### 2. **Volúmenes de Docker**
```yaml
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
Esto da acceso al **socket** de Docker, pero NO instala el **cliente** de Docker.
### 3. **Diferencia entre CI y CD**
- **CI (Continuous Integration)**: Construir, probar, validar código
- **CD (Continuous Deployment)**: Desplegar a producción
Tu runner está configurado para CD (deployment), no para CI (build).
## 🛠️ Opciones para Continuar
### Opción 1: Usar un Runner Estándar (Más Fácil) ⭐
**Ventajas**:
- Todo preinstalado
- Funciona como el ejemplo que compartiste
- Menos configuración
**Desventajas**:
- Necesitas configurar acceso SSH al servidor de producción
- El deployment se hace remotamente
**Cómo hacerlo**:
```yaml
jobs:
deploy:
runs-on: ubuntu-latest # ← Cambiar a esto
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
run: |
ssh user@servidor 'cd /path/to/project && ./deploy.sh'
```
### Opción 2: Configurar el Runner con Docker Preinstalado (Medio)
Crear una imagen personalizada del runner con Docker ya instalado.
**Dockerfile del runner**:
```dockerfile
FROM gitea/act_runner:latest
RUN apt-get update && apt-get install -y docker-ce-cli
```
### Opción 3: Deployment Manual con Git Hooks (Más Simple) ⭐⭐
Usar Git hooks en el servidor para auto-desplegar cuando haces push.
**En el servidor**:
```bash
# .git/hooks/post-receive
#!/bin/bash
cd /home/marti/Documentos/Gitea/resistencia
git pull
./deploy.sh
```
### Opción 4: Usar Portainer o Watchtower (Automático)
Herramientas que detectan cambios en imágenes Docker y auto-actualizan.
### Opción 5: Continuar con el Enfoque Actual (Más Complejo)
Necesitarías:
1. Entender mejor cómo el runner accede al filesystem del host
2. Configurar permisos correctos
3. Posiblemente usar SSH desde el runner al host
## 📚 Recursos para Estudiar
### Gitea Actions
- [Documentación oficial de Gitea Actions](https://docs.gitea.com/usage/actions/overview)
- [Act Runner GitHub](https://github.com/nektos/act)
- [Diferencias entre GitHub Actions y Gitea Actions](https://docs.gitea.com/usage/actions/comparison)
### Docker en CI/CD
- [Docker-in-Docker (DinD)](https://www.docker.com/blog/docker-can-now-run-within-docker/)
- [Docker socket mounting](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option)
### Alternativas
- [Drone CI](https://www.drone.io/) - CI/CD más simple
- [Jenkins](https://www.jenkins.io/) - Más potente pero complejo
- [GitLab CI/CD](https://docs.gitlab.com/ee/ci/) - Similar a Gitea Actions
## 💡 Mi Recomendación
Para tu caso específico, te recomendaría **Opción 1 o Opción 3**:
### Opción 1: Runner Estándar + SSH
```yaml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
script: |
cd /home/marti/Documentos/Gitea/resistencia
git pull
./deploy.sh
```
### Opción 3: Git Hook (Sin CI/CD)
```bash
# En el servidor, en el repositorio bare de Gitea
# /path/to/gitea/data/gitea-repositories/marti/FranciaOcupada.git/hooks/post-receive
#!/bin/bash
cd /home/marti/Documentos/Gitea/resistencia
git pull origin main
./deploy.sh
```
## 📝 Estado Actual del Proyecto
### ✅ Lo que SÍ funciona:
- Script `deploy.sh` - Listo para usar
- Docker Compose configurado
- Aplicación funcional en local
### ⚠️ Lo que NO funciona:
- Workflow de Gitea Actions con runner personalizado
- Ejecución automática de deployment
### 🎯 Lo que tienes listo para usar:
```bash
# Deployment manual (esto SÍ funciona)
cd /home/marti/Documentos/Gitea/resistencia
./deploy.sh
```
## 🚀 Próximos Pasos Sugeridos
1. **Estudiar** los recursos mencionados arriba
2. **Decidir** qué opción se adapta mejor a tus necesidades
3. **Probar** el deployment manual mientras tanto: `./deploy.sh`
4. **Considerar** si realmente necesitas CI/CD automático o si el deployment manual es suficiente
## 📦 Archivos Útiles Creados
Aunque el CI/CD automático no funcionó, estos archivos son útiles:
-`deploy.sh` - Script de deployment manual (funciona)
-`monitor-deploy.sh` - Monitoreo de contenedores
-`useful-commands.sh` - Comandos de referencia
- ✅ Documentación completa del proceso
## 💭 Reflexión Final
CI/CD con runners personalizados es complejo. No es un fallo tuyo no haberlo logrado en la primera sesión. Muchos equipos profesionales tardan días o semanas en configurar correctamente su CI/CD.
**Alternativa práctica**: Mientras estudias más sobre el tema, puedes usar deployment manual con `./deploy.sh`, que es perfectamente válido para proyectos pequeños/medianos.
---
**Fecha**: 2025-12-13
**Estado**: En pausa para estudio
**Próximo paso**: Decidir entre las opciones propuestas arriba

233
TROUBLESHOOTING-CICD.md Normal file
View File

@@ -0,0 +1,233 @@
# 🔧 Troubleshooting CI/CD - Problemas Resueltos
## Resumen de Problemas Encontrados y Soluciones
Durante la configuración del CI/CD con Gitea Actions, encontramos varios problemas que fueron resueltos paso a paso. Este documento sirve como referencia para futuros problemas similares.
---
## Problema 1: Error en el Checkout - Variables de Contexto
### ❌ Error
```
%!t(string=http://gitea.local:3000)
%!t(string=***)
%!t(string=marti/FranciaOcupada)
```
### 🔍 Causa
El workflow intentaba usar variables de contexto de Gitea (`${{ gitea.server_url }}`, `${{ gitea.repository }}`, `${{ gitea.token }}`) en el paso de checkout, pero estas no se interpolaban correctamente.
### ✅ Solución
Simplificar el checkout eliminando los parámetros innecesarios:
```yaml
# ❌ ANTES (No funcionaba)
- name: 🚀 Checkout del Código
uses: actions/checkout@v4
with:
server-url: ${{ gitea.server_url }}
repository: ${{ gitea.repository }}
token: ${{ gitea.token }}
fetch-depth: 0
# ✅ DESPUÉS (Funciona)
- name: 🚀 Checkout del Código
uses: actions/checkout@v4
with:
fetch-depth: 0
```
**Commit**: `609033b` - "fix: Corregir checkout en workflow de Gitea Actions"
---
## Problema 2: Node.js No Encontrado
### ❌ Error
```
Cannot find: node in PATH
```
### 🔍 Causa
El runner de Gitea Actions no tiene Node.js preinstalado, y las acciones de GitHub (como `actions/checkout@v4` y `actions/setup-node@v4`) requieren Node.js para ejecutarse.
### ✅ Solución
Instalar Node.js manualmente usando comandos del sistema ANTES de cualquier acción de GitHub:
```yaml
- name: 📦 Instalar Node.js
shell: bash
run: |
echo "Verificando si Node.js está instalado..."
if ! command -v node &> /dev/null; then
echo "Node.js no encontrado, instalando..."
# Detectar el sistema operativo
if [ -f /etc/debian_version ]; then
# Debian/Ubuntu
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
elif [ -f /etc/redhat-release ]; then
# RedHat/CentOS/Fedora
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
yum install -y nodejs
elif [ -f /etc/alpine-release ]; then
# Alpine Linux
apk add --no-cache nodejs npm
else
# Fallback a nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
nvm install 20
fi
else
echo "Node.js ya está instalado: $(node --version)"
fi
# Verificar instalación
node --version
npm --version
```
**Commit**: `7c9ff53` - "feat: Instalación manual de Node.js en el runner"
---
## Problema 3: Scripts No Encontrados (2.sh, 3.sh, 4.sh)
### ❌ Error
```
/root/.cache/act/6d07dd4849690bae/act/workflow/2.sh: line 3: docker: command not found
/root/.cache/act/6d07dd4849690bae/act/workflow/3.sh: line 3: docker: command not found
/root/.cache/act/6d07dd4849690bae/act/workflow/4.sh: line 3: docker: command not found
```
### 🔍 Causa
El runner de Gitea Actions (basado en `act`) estaba creando archivos temporales (2.sh, 3.sh, 4.sh) para ejecutar los bloques `run:`, pero no especificaba correctamente el shell a usar, causando que los comandos no se ejecutaran en el contexto correcto.
### ✅ Solución
Especificar explícitamente `shell: bash` en todos los pasos que usan bloques `run:`:
```yaml
# ❌ ANTES (No funcionaba)
- name: 🛑 Detener Contenedores Anteriores
run: |
echo "Deteniendo contenedores existentes..."
docker compose -f docker-compose_prod.yml down || true
# ✅ DESPUÉS (Funciona)
- name: 🛑 Detener Contenedores Anteriores
shell: bash
run: |
echo "Deteniendo contenedores existentes..."
docker compose -f docker-compose_prod.yml down || true
```
**Commit**: `134460a` - "fix: Especificar shell bash explícitamente en todos los pasos"
---
## Orden Correcto de los Pasos
El orden final correcto de los pasos es:
1. **Instalar Node.js** (con `shell: bash`)
2. **Checkout del Código** (usando `actions/checkout@v4`)
3. **Detener Contenedores Anteriores** (con `shell: bash`)
4. **Limpiar Imágenes Antiguas** (con `shell: bash`)
5. **Construir Imágenes Docker** (con `shell: bash`)
6. **Desplegar Aplicación** (con `shell: bash`)
7. **Verificar Despliegue** (con `shell: bash`)
8. **Mostrar Logs Recientes** (con `shell: bash` e `if: always()`)
---
## Lecciones Aprendidas
### 1. Diferencias entre GitHub Actions y Gitea Actions
- Gitea Actions usa `act` bajo el capó, que tiene algunas diferencias con GitHub Actions
- No todas las variables de contexto funcionan igual
- El runner puede no tener las mismas herramientas preinstaladas
### 2. Especificar el Shell es Importante
- Siempre especifica `shell: bash` cuando uses bloques `run:` con múltiples líneas
- Esto evita problemas de interpretación de comandos
### 3. Node.js es Requerido
- Muchas acciones de GitHub requieren Node.js
- En runners de Gitea, puede que necesites instalarlo manualmente
- Instálalo ANTES de usar cualquier acción de GitHub
### 4. El Runner Necesita Acceso a Docker
- Asegúrate de que el runner tenga acceso al socket de Docker del host
- En tu configuración: `-v /var/run/docker.sock:/var/run/docker.sock`
- La etiqueta debe ser `production-ready:host` para acceso al Docker del host
---
## Configuración del Runner
Tu configuración del runner que funciona:
```yaml
services:
gitea-runner:
image: gitea/act_runner:latest
container_name: gitea-act_runner
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- GITEA_INSTANCE_URL=http://gitea.local:3000
- GITEA_RUNNER_NAME=runner-01-ci-vm
- GITEA_RUNNER_LABELS=production-ready:host
- GITEA_RUNNER_REGISTRATION_TOKEN=jzLi65hxB1Rt2RgIGFglXB5RjW9ggCbq9UFX3NrS
```
**Puntos clave**:
- `production-ready:host` - La etiqueta `:host` es crucial para acceso a Docker
- Volumen del socket de Docker montado
- URL de Gitea correcta
---
## Verificación Post-Despliegue
Después de un despliegue exitoso, verifica:
```bash
# 1. Estado de contenedores
docker compose -f docker-compose_prod.yml ps
# 2. Logs recientes
docker compose -f docker-compose_prod.yml logs --tail=50
# 3. Acceso a la aplicación
curl -I https://franciaocupada.martivich.es
curl -I https://api.franciaocupada.martivich.es
# 4. Estado del runner
docker ps | grep gitea-act_runner
```
---
## Recursos Útiles
- **Gitea Actions Docs**: https://docs.gitea.com/usage/actions/overview
- **Act Runner**: https://gitea.com/gitea/act_runner
- **GitHub Actions Syntax**: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
---
## Próximas Mejoras Recomendadas
1. **Caché de Node.js**: Cachear la instalación de Node.js para acelerar futuros builds
2. **Tests Automatizados**: Agregar tests antes del deploy
3. **Rollback Automático**: Implementar rollback si el deploy falla
4. **Notificaciones**: Configurar notificaciones de éxito/fallo (email, Discord, etc.)
5. **Health Checks**: Verificar que la app responde correctamente antes de dar por exitoso el deploy
6. **Backup de DB**: Hacer backup de la base de datos antes de cada deploy
7. **Staging Environment**: Crear un ambiente de staging para probar antes de producción

View File

@@ -25,6 +25,9 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
const [missionVote, setMissionVote] = useState<boolean | null>(null);
const [expandedMission, setExpandedMission] = useState<number | null>(null);
// Estado para controlar el colapso del panel de jugadores
const [isPlayersCollapsed, setIsPlayersCollapsed] = useState(false);
// Timer para avanzar automáticamente en REVEAL_ROLE
useEffect(() => {
@@ -781,8 +784,38 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
</div>
{/* JUGADORES - POSICIONADOS ABSOLUTAMENTE EN EL FONDO */}
<div className="fixed bottom-[10px] left-0 right-0 z-50 bg-black/80 border-t border-white/10 backdrop-blur-md py-2">
<div className="w-full px-4 flex flex-wrap items-center justify-center gap-4">
<motion.div
className="fixed bottom-0 left-0 right-0 z-50 bg-black/80 border-t border-white/10 backdrop-blur-md"
initial={false}
animate={{
y: isPlayersCollapsed ? '100%' : '0%'
}}
transition={{ type: "spring", stiffness: 300, damping: 30 }}
>
{/* Botón de colapso/expansión */}
<div className="absolute -top-10 left-1/2 transform -translate-x-1/2">
<button
onClick={() => setIsPlayersCollapsed(!isPlayersCollapsed)}
className="bg-gradient-to-b from-yellow-600 to-yellow-700 hover:from-yellow-500 hover:to-yellow-600 text-white rounded-t-lg px-6 py-2 shadow-lg border-2 border-yellow-500 border-b-0 transition-all hover:shadow-yellow-500/50 flex items-center gap-2"
>
<motion.svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
animate={{ rotate: isPlayersCollapsed ? 180 : 0 }}
transition={{ duration: 0.3 }}
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M19 9l-7 7-7-7" />
</motion.svg>
<span className="text-sm font-bold uppercase tracking-wider">
{isPlayersCollapsed ? 'Mostrar' : 'Ocultar'} Jugadores
</span>
</button>
</div>
<div className="w-full px-4 py-2 flex flex-wrap items-center justify-center gap-4">
{gameState.players.map((player) => {
const isSelected = selectedTeam.includes(player.id);
const isMe = player.id === currentPlayerId;
@@ -842,7 +875,7 @@ export default function GameBoard({ gameState, currentPlayerId, actions }: GameB
);
})}
</div>
</div>
</motion.div>
{/* HISTÓRICO DE MISIONES (Esquina superior derecha) */}
{gameState.missionHistory.length > 0 && (

131
monitor-deploy.sh Executable file
View File

@@ -0,0 +1,131 @@
#!/bin/bash
# Script de monitoreo para el despliegue de Francia Ocupada
# Uso: ./monitor-deploy.sh
echo "🔍 Monitor de Despliegue - Francia Ocupada"
echo "=========================================="
echo ""
# Colores para output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Función para verificar estado de contenedores
check_containers() {
echo -e "${YELLOW}📦 Estado de Contenedores:${NC}"
docker compose -f docker-compose_prod.yml ps
echo ""
}
# Función para verificar logs
check_logs() {
echo -e "${YELLOW}📋 Logs Recientes (últimas 20 líneas):${NC}"
echo ""
echo "--- CLIENT ---"
docker compose -f docker-compose_prod.yml logs --tail=20 client 2>/dev/null || echo "Cliente no disponible"
echo ""
echo "--- SERVER ---"
docker compose -f docker-compose_prod.yml logs --tail=20 server 2>/dev/null || echo "Servidor no disponible"
echo ""
}
# Función para verificar conectividad
check_connectivity() {
echo -e "${YELLOW}🌐 Verificación de Conectividad:${NC}"
# Verificar puerto 3000 (cliente)
if nc -z localhost 3000 2>/dev/null; then
echo -e "${GREEN}✅ Puerto 3000 (Cliente): ABIERTO${NC}"
else
echo -e "${RED}❌ Puerto 3000 (Cliente): CERRADO${NC}"
fi
# Verificar puerto 4000 (servidor)
if nc -z localhost 4000 2>/dev/null; then
echo -e "${GREEN}✅ Puerto 4000 (Servidor): ABIERTO${NC}"
else
echo -e "${RED}❌ Puerto 4000 (Servidor): CERRADO${NC}"
fi
# Verificar puerto 5432 (base de datos)
if nc -z localhost 5432 2>/dev/null; then
echo -e "${GREEN}✅ Puerto 5432 (Base de Datos): ABIERTO${NC}"
else
echo -e "${RED}❌ Puerto 5432 (Base de Datos): CERRADO${NC}"
fi
echo ""
}
# Función para verificar uso de recursos
check_resources() {
echo -e "${YELLOW}💻 Uso de Recursos:${NC}"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" \
$(docker compose -f docker-compose_prod.yml ps -q 2>/dev/null) 2>/dev/null || echo "No hay contenedores corriendo"
echo ""
}
# Menú principal
while true; do
echo ""
echo "Selecciona una opción:"
echo "1) Ver estado de contenedores"
echo "2) Ver logs recientes"
echo "3) Verificar conectividad"
echo "4) Ver uso de recursos"
echo "5) Monitoreo completo"
echo "6) Logs en tiempo real (Ctrl+C para salir)"
echo "7) Reiniciar servicios"
echo "8) Detener servicios"
echo "9) Salir"
echo ""
read -p "Opción: " option
case $option in
1)
check_containers
;;
2)
check_logs
;;
3)
check_connectivity
;;
4)
check_resources
;;
5)
check_containers
check_connectivity
check_resources
check_logs
;;
6)
echo "📡 Logs en tiempo real (Ctrl+C para detener)..."
docker compose -f docker-compose_prod.yml logs -f
;;
7)
echo "🔄 Reiniciando servicios..."
docker compose -f docker-compose_prod.yml restart
echo -e "${GREEN}✅ Servicios reiniciados${NC}"
;;
8)
read -p "¿Estás seguro de que quieres detener los servicios? (s/n): " confirm
if [ "$confirm" = "s" ]; then
echo "🛑 Deteniendo servicios..."
docker compose -f docker-compose_prod.yml down
echo -e "${GREEN}✅ Servicios detenidos${NC}"
fi
;;
9)
echo "👋 ¡Hasta luego!"
exit 0
;;
*)
echo -e "${RED}❌ Opción inválida${NC}"
;;
esac
done

174
useful-commands.sh Executable file
View File

@@ -0,0 +1,174 @@
#!/bin/bash
# 🚀 Comandos Útiles para CI/CD - Francia Ocupada
# Este archivo contiene comandos útiles para gestionar el CI/CD
echo "==================================================="
echo "🎮 Francia Ocupada - Comandos Útiles CI/CD"
echo "==================================================="
echo ""
# Función para mostrar comandos con descripción
show_command() {
echo -e "\033[1;33m$1\033[0m"
echo -e "\033[0;36m$2\033[0m"
echo ""
}
echo "📦 GESTIÓN DE CONTENEDORES"
echo "---------------------------------------------------"
show_command "Ver estado de contenedores:" \
"docker compose -f docker-compose_prod.yml ps"
show_command "Iniciar servicios:" \
"docker compose -f docker-compose_prod.yml up -d"
show_command "Detener servicios:" \
"docker compose -f docker-compose_prod.yml down"
show_command "Reiniciar servicios:" \
"docker compose -f docker-compose_prod.yml restart"
show_command "Reconstruir y reiniciar:" \
"docker compose -f docker-compose_prod.yml up -d --build"
echo ""
echo "📋 LOGS Y DEBUGGING"
echo "---------------------------------------------------"
show_command "Ver todos los logs:" \
"docker compose -f docker-compose_prod.yml logs"
show_command "Logs en tiempo real:" \
"docker compose -f docker-compose_prod.yml logs -f"
show_command "Logs del cliente:" \
"docker compose -f docker-compose_prod.yml logs -f client"
show_command "Logs del servidor:" \
"docker compose -f docker-compose_prod.yml logs -f server"
show_command "Logs de la base de datos:" \
"docker compose -f docker-compose_prod.yml logs -f db"
show_command "Últimas 100 líneas de logs:" \
"docker compose -f docker-compose_prod.yml logs --tail=100"
echo ""
echo "🔍 INSPECCIÓN Y DEBUGGING"
echo "---------------------------------------------------"
show_command "Entrar al contenedor del cliente:" \
"docker exec -it resistencia-client sh"
show_command "Entrar al contenedor del servidor:" \
"docker exec -it resistencia-server sh"
show_command "Entrar a la base de datos:" \
"docker exec -it resistencia-db psql -U postgres -d resistencia"
show_command "Ver uso de recursos:" \
"docker stats"
show_command "Inspeccionar red:" \
"docker network inspect resistencia_resistencia-net"
echo ""
echo "🧹 LIMPIEZA"
echo "---------------------------------------------------"
show_command "Limpiar contenedores detenidos:" \
"docker container prune -f"
show_command "Limpiar imágenes sin usar:" \
"docker image prune -f"
show_command "Limpiar todo (CUIDADO):" \
"docker system prune -a -f"
show_command "Limpiar volúmenes (CUIDADO - BORRA DATOS):" \
"docker volume prune -f"
echo ""
echo "🔧 TROUBLESHOOTING"
echo "---------------------------------------------------"
show_command "Ver puertos en uso:" \
"sudo lsof -i :3000 :4000 :5432"
show_command "Verificar conectividad local:" \
"curl http://localhost:3000 && curl http://localhost:4000"
show_command "Ver configuración de docker-compose:" \
"docker compose -f docker-compose_prod.yml config"
show_command "Reconstruir sin caché:" \
"docker compose -f docker-compose_prod.yml build --no-cache"
echo ""
echo "🚀 GIT Y DESPLIEGUE"
echo "---------------------------------------------------"
show_command "Ver estado de Git:" \
"git status"
show_command "Ver último commit:" \
"git log -1"
show_command "Trigger CI/CD (commit vacío):" \
"git commit --allow-empty -m 'test: Trigger CI/CD' && git push origin main"
show_command "Ver commits recientes:" \
"git log --oneline -10"
show_command "Ver diferencias con origin:" \
"git diff origin/main"
echo ""
echo "🌐 VERIFICACIÓN DE PRODUCCIÓN"
echo "---------------------------------------------------"
show_command "Verificar frontend (local):" \
"curl -I http://localhost:3000"
show_command "Verificar API (local):" \
"curl -I http://localhost:4000"
show_command "Verificar frontend (producción):" \
"curl -I https://franciaocupada.martivich.es"
show_command "Verificar API (producción):" \
"curl -I https://api.franciaocupada.martivich.es"
echo ""
echo "📊 MONITOREO"
echo "---------------------------------------------------"
show_command "Script de monitoreo interactivo:" \
"./monitor-deploy.sh"
show_command "Ver acciones de Gitea (navegador):" \
"xdg-open http://gitea.local:3000/marti/FranciaOcupada/actions"
echo ""
echo "💾 BACKUP Y RESTAURACIÓN"
echo "---------------------------------------------------"
show_command "Backup de la base de datos:" \
"docker exec resistencia-db pg_dump -U postgres resistencia > backup_\$(date +%Y%m%d_%H%M%S).sql"
show_command "Restaurar base de datos:" \
"docker exec -i resistencia-db psql -U postgres resistencia < backup.sql"
show_command "Exportar volumen de datos:" \
"docker run --rm -v resistencia_postgres_data:/data -v \$(pwd):/backup alpine tar czf /backup/postgres_data_backup.tar.gz -C /data ."
echo ""
echo "🎯 COMANDOS RÁPIDOS"
echo "---------------------------------------------------"
show_command "Reinicio completo (desarrollo):" \
"docker compose down && docker compose up -d --build"
show_command "Reinicio completo (producción):" \
"docker compose -f docker-compose_prod.yml down && docker compose -f docker-compose_prod.yml up -d --build"
show_command "Ver todo el estado del sistema:" \
"docker compose -f docker-compose_prod.yml ps && docker compose -f docker-compose_prod.yml logs --tail=20"
echo ""
echo "==================================================="
echo "💡 Tip: Guarda este archivo como referencia"
echo " Ejecuta: cat useful-commands.sh | less"
echo "==================================================="