Desplegar¶
Esta guía describe cómo desplegar Camarero-IA en producción: construcción de imágenes con Podman, arranque del pod con todos los servicios, configuración de variables de entorno y uso de los scripts de despliegue automatizado.
El despliegue de producción se realiza sobre Oracle Cloud (Oracle Linux 9, Podman 5.6+) mediante imágenes multi-stage y un pod de Podman que agrupa frontend, backend, base de datos y el proxy NVIDIA.
Dos scripts, dos ámbitos
scripts/build-podman.shse ejecuta en el servidor y gestiona el ciclo de vida local: construir imágenes, crear el pod y arrancar/parar/ver servicios.scripts/deploy-production.shse ejecuta desde tu máquina local y orquesta el despliegue remoto completo por SSH (sincronizar código, sincronizar variables, construir y reiniciar).
Arquitectura de despliegue¶
Todos los servicios viven dentro de un único pod de Podman llamado camarero-ia-pod, que comparte red (los contenedores se comunican por localhost).
| Contenedor | Imagen | Puerto publicado |
|---|---|---|
camarero-ia-postgres |
docker.io/library/postgres:15-alpine |
5432 |
camarero-ia-proxy |
localhost/camarero-ia-proxy:latest |
(interno) |
camarero-ia-backend |
localhost/camarero-ia-backend:latest |
8000 |
camarero-ia-frontend |
localhost/camarero-ia-frontend:latest |
3000 |
Orden de arranque (definido en deploy_pod() de scripts/build-podman.sh):
- PostgreSQL — con volumen persistente
postgres-data. - Proxy NVIDIA — debe arrancar antes que el backend para estar disponible cuando este lo sondee.
- Backend — FastAPI.
- Frontend — Next.js en modo
standalone.
El frontend usa una imagen multi-stage (frontend/Dockerfile) con tres etapas: deps (dependencias de producción), builder (compilación de Next.js) y runner (runtime mínimo, usuario no-root, HEALTHCHECK incluido).
Requisitos previos¶
En el servidor (Oracle Cloud):
- Oracle Linux 9 o compatible.
- Podman 5.6+ instalado.
- Firewall configurado (ver Firewall y red).
- Acceso SSH con clave.
En tu máquina local:
rsyncyscp(OpenSSH 9+).- Clave SSH configurada (por defecto
~/ssh-key-2026-03-21.key).
El proxy NVIDIA vive en una carpeta con espacio
El código del proxy está en ../kilo-nvidia-proxy copy (con un espacio literal en el nombre). Los scripts lo manejan citando la ruta y usando rsync -s / scp en modo SFTP. No renombres esa carpeta sin actualizar PROXY_LOCAL_DIR / PROXY_REMOTE_DIR en scripts/deploy-production.sh y PROXY_DIR en scripts/build-podman.sh.
Despliegue completo (recomendado)¶
Desde la raíz del repo en tu máquina local:
Este comando ejecuta deploy_all(), que encadena todos los pasos:
check_prerequisites— verifica clave SSH, directorio local yrsync.test_connection— comprueba la conexión SSH al servidor.sync_files— sincroniza el repo al servidor (excluyenode_modules,.next,.git,__pycache__,backend/venv,backend/.env.prod.local).sync_proxy_files— sincroniza el código del proxy NVIDIA (excluyedata,.env,.env.prod.local).sync_env_file— copiabackend/.env.prod.localy le aplicachmod 600.sync_proxy_env— copia el.env.prod.localdel proxy conchmod 600.sync_proxy_accounts— subedata/accounts.jsondel proxy solo si el remoto no tiene uno (no pisa las claves vivas).build_all— construye las tres imágenes (frontend + backend + proxy) en el servidor.deploy_services— reinicia el pod (build-podman.sh restart).verify_deployment— comprueba que el pod corre y que el frontend respondeHTTP 200; al final hacepodman image prune -f.
Migraciones desactivadas en el flujo completo
En deploy_all() el paso run_migrations está comentado. Para aplicar migraciones de base de datos, ejecútalo aparte (ver Migraciones).
Comandos parciales del script de producción¶
scripts/deploy-production.sh acepta subcomandos para operaciones puntuales:
| Comando | Acción |
|---|---|
deploy |
Despliegue completo (sincroniza, construye, reinicia, verifica). |
sync |
Solo sincroniza el código del repo (excluye .env). |
sync-env |
Solo sincroniza backend/.env.prod.local. |
sync-proxy |
Solo sincroniza el código del proxy NVIDIA. |
sync-proxy-env |
Solo sincroniza el .env.prod.local del proxy. |
sync-proxy-accounts |
Sube accounts.json solo si el remoto no tiene uno. |
migrate |
Ejecuta las migraciones de base de datos en el servidor. |
build |
Construye las tres imágenes. |
build-frontend |
Construye solo el frontend. |
build-backend |
Construye solo el backend. |
build-proxy |
Construye solo el proxy NVIDIA. |
restart |
Solo reinicia los servicios. |
status |
Muestra el estado del despliegue. |
logs |
Muestra los logs del frontend. |
help |
Muestra la ayuda. |
Ejemplos:
./scripts/deploy-production.sh sync-env # actualizar solo variables de entorno
./scripts/deploy-production.sh build-backend # reconstruir solo el backend
./scripts/deploy-production.sh status # ver estado actual
Construcción y gestión local (en el servidor)¶
scripts/build-podman.sh es el script que se ejecuta dentro del servidor (lo invocan los pasos de deploy-production.sh por SSH, pero también puedes usarlo directamente).
| Comando | Acción |
|---|---|
build |
Construye las tres imágenes (frontend + backend + proxy). |
frontend |
Construye solo la imagen del frontend. |
backend |
Construye solo la imagen del backend. |
proxy |
Construye solo la imagen del proxy NVIDIA. |
deploy |
Crea el pod y arranca todos los servicios. |
stop |
Para y elimina el pod. |
restart |
Para y vuelve a desplegar el pod. |
status |
Muestra el estado del pod y sus contenedores. |
logs <servicio> |
Muestra los logs de un servicio (frontend, backend, postgres, proxy). |
clean |
Limpia imágenes y contenedores sin usar (podman system prune -f). |
Las imágenes se etiquetan como ${REGISTRY_URL}/camarero-ia-{servicio}:${VERSION} (por defecto localhost/...:latest). Puedes sobreescribir el registry y la versión por entorno:
Variables de entorno de producción¶
Las variables sensibles no se versionan: viven en ficheros .env.prod.local que el script sincroniza con permisos 600.
- Backend:
backend/.env.prod.local→ se monta con--env-fileen el contenedor del backend. - Proxy NVIDIA:
<proxy>/.env.prod.local→ se monta con--env-fileen el contenedor del proxy; ademásdata/accounts.json(claves de NVIDIA) se bind-montea en/datapara que persista y sea editable desde el host.
Sin .env.prod.local se usan valores por defecto inseguros
Si backend/.env.prod.local no existe en el servidor, deploy_pod() arranca el backend con un SECRET_KEY de desarrollo y una DATABASE_URL por defecto. No despliegues a producción sin un .env.prod.local real.
Variables esenciales del backend (ver también la guía de configuración si existe):
DATABASE_URL=postgresql+asyncpg://camarero_user:camarero_password@localhost:5432/camarero_db
SECRET_KEY=clave_secreta_de_al_menos_32_caracteres
DEBUG=false
Variables del frontend (se inyectan en deploy_pod() al arrancar el contenedor):
NEXT_PUBLIC_API_URL=https://api.camarero-demo.n0idea.app/api/v1
NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1
DATABASE_URL usa asyncpg
El backend (SQLAlchemy 2.x async) requiere el driver asyncpg; el esquema de conexión debe ser postgresql+asyncpg://..., no postgresql://....
Migraciones de base de datos¶
Las migraciones (Alembic) no se ejecutan en el flujo deploy completo. Para aplicarlas:
El paso run_migrations:
- Comprueba que el
venvdel servidor usa Python 3.10+ (necesario por la sintaxis de tipos unión). Si es anterior, aborta con instrucciones para recrear el venv con Python 3.12. - Instala
alembicen el venv y ejecutapython -m alembic -c alembic.ini upgrade head.
# Recrear el venv en el servidor (si la versión de Python es < 3.10)
ssh opc@<servidor>
cd ~/camarero-ia/backend
rm -rf venv && python3.12 -m venv venv
source venv/bin/activate && pip install -r requirements.txt
Firewall y red¶
El frontend se publica en el puerto 3000. Hay que abrirlo tanto en el firewall del servidor como en los Security Groups de Oracle Cloud.
# Firewalld (servidor Oracle Linux)
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload
En Oracle Cloud Infrastructure, añade una regla de ingreso en las Security Lists:
- Source:
0.0.0.0/0 - Protocol: TCP
- Port:
3000
Verificación y operación¶
Tras desplegar, comprueba el estado y los logs:
# Estado del pod y contenedores (en el servidor)
./scripts/build-podman.sh status
# Logs en tiempo real
./scripts/build-podman.sh logs frontend
./scripts/build-podman.sh logs backend
./scripts/build-podman.sh logs postgres
./scripts/build-podman.sh logs proxy
Comprobaciones manuales útiles:
# Pods y contenedores
podman pod ps
podman ps --filter "pod=camarero-ia-pod"
# Respuesta del frontend
curl -s -o /dev/null -w '%{http_code}' http://localhost:3000 # esperado: 200
# Conexión a PostgreSQL
podman exec -it camarero-ia-postgres \
psql -U camarero_user -d camarero_db -c "SELECT version();"
URLs de producción¶
| Servicio | URL |
|---|---|
| Frontend | http://130.61.243.236:3000 (requiere Security Groups OCI) |
| API Backend | https://api.camarero-demo.n0idea.app |
| PostgreSQL | Interno al pod (puerto 5432) |
Solución de problemas¶
El frontend no es accesible desde fuera
Revisa firewall local y Security Groups de OCI: el puerto 3000 debe estar abierto en ambos.
Errores de compilación del frontend
Fuerza una reconstrucción limpia:
La base de datos no está disponible