El motor de despliegues de Odoo detras de LTC Labs

oci_management: de un formulario a un Odoo corriendo, sin tocar la consola

Intro

En el post anterior conté cómo elegir tu infraestructura (VPS, dedicado, cloud) y dónde deben vivir tus datos. Hoy toca la pieza que la hace útil: el motor de despliegue.

Si alquilas un dedicado vacío o un VPS en OVH, tienes hardware pero no tienes Odoo. Te faltan Docker, Postgres, nginx, OCA, l10n_es, verticales, traducciones, certificados SSL. Hacer eso a mano cada vez es una tarde entera. Y si tocas 3 clientes al mes, es una tarde semanal perdida.

Por eso existe oci_management. Es un módulo dentro de mi Odoo que describe un despliegue en un formulario y lo ejecuta con Claude por detrás.

S1. De una frase en una tarea a un módulo de Odoo

Hace unos meses abrí una tarea en mi Odoo interno y escribí esto:

task718-img1.png

Mejora este prompt: "Añade una nueva característica a oci_management. Dentro de oci.project, en la sección de Server Connection, añadir un nuevo selector: Tipo de instalación (Directa || Detrás de Proxmox). En caso de ser directa todo funciona como hasta ahora. En caso de Detrás de proxmox aparecerá un nuevo campo: Número de contenedor, en caso de Detrás de Proxmox habrá que incluir las llamadas al contenedor. (pct exec 116 ...) para lanzar el código dentro del contenedor. Tendrás que adaptar el código para esto."

Eso era todo lo que tenía claro: una frase, un caso de uso y ninguna idea de por dónde meter mano. No quería que Claude programase a ciegas, sino que convirtiese mi intención en un prompt decente. Abrí el skill oci-creator, le pedí que estudiase el código y reescribiese la petición.

La respuesta fue esta:

task718-img2.png

Claude me devolvió un prompt con contexto, cambios requeridos campo a campo, modelo y vista localizados, y _ssh_exec señalado como único punto donde había que envolver el comando en pct exec {ct_id} -- bash -c '...'. Añadió el ejemplo concreto de conversión del docker compose a su versión envuelta.

La segunda mitad cerraba con las restricciones:

task718-img3.png

NO tocar ningún otro método. Solo _ssh_exec necesita el wrapping. NO cambiar la firma de _ssh_exec (el wrapping es transparente para los callers). Modo 'direct' debe funcionar EXACTAMENTE igual que antes (sin regresión).

Ese bloque es lo que convierte un prompt en una especificación: archivos y líneas exactas, un único punto de cambio, no regresión en el modo directo y hasta el recordatorio de escapar comillas. Una vez aplicado, le pedí a Claude que persistiese lo aprendido en mis memorias, en el skill y en Obsidian:

task718-img4.png

Mejora este prompt: "Actualiza tus memorias, skills y obsidian con lo aprendido en esta sesión".

De esa conversación salió oci_management con soporte Proxmox. Sigue leyendo y te cuento cómo funciona.

S2. Qué hace oci_management en una frase

La idea es simple: en vez de abrir una consola y configurar Docker, Postgres, nginx, OCA y l10n_es a mano, abro un formulario en mi Odoo y describo el despliegue.

En ese formulario (el modelo se llama oci.project) pongo lo básico: el cliente, la versión de Odoo, las verticales que quiero (hostelería, servicios, e-commerce...), el host de destino con sus credenciales SSH y el tipo de instalación. Nada más. Dentro del proyecto engancho uno o varios servidores (oci.server), que son las instancias reales que van a correr: develop, staging, producción. Cada servidor tiene su dominio, su base de datos, sus workers y su modo de despliegue.

oci-project-tbp.png

Cuando pulso el botón, Claude con la skill oci-creator se conecta por SSH al host de destino, aprovisiona el contenedor LXC si hace falta, levanta Docker, resuelve las dependencias de OCA de forma recursiva (las transitivas también, que son las que siempre se olvidan), inicializa la base con l10n_es desde el arranque, aplica el checklist que usamos en producción (EUR en vez de USD, kg en vez de unidades, alérgenos, traducciones al español, debranding) y publica el repositorio custom en GitLab con su manifest generado a partir de las verticales.

Y yo me voy a tomar un café.

Una parte clave de todo esto viene de oca_management, que es el módulo hermano, el que se ocupa de las instalaciones baremetal. Lo veremos pronto en la serie; de hecho, sin él, oci_management no arranca. Y antes de entrar ahí, conviene ver qué formas de desplegar tengo hoy encima de la mesa.

S3. Las dos formas de desplegar (hoy)

Aquí conviene separar dos decisiones que parecen la misma pero no lo son:

  • Dónde se ejecuta el SSH lo decide oci.project.install_type (Directa o Detrás de Proxmox). En Directa, Claude abre una sesión SSH contra el host y ejecuta ahí. En Detrás de Proxmox, la misma sesión SSH entra al nodo Proxmox y cada comando se envuelve como pct exec {ct_id} -- bash -c '...' para que se ejecute dentro del LXC. Esto es la pieza que salió de la tarea del principio.
  • Qué se levanta en el destino lo decide oci.server.deploy_type y tiene dos modos:
  • Full Stack (Nginx + Odoo + DB). Despliegue completo: nginx, Odoo y Postgres viven juntos, orquestados por Docker Compose. Lo uso cuando quiero un Odoo en mi propia red, con nginx propio, SSL vía Let's Encrypt y todo dentro del mismo contenedor lógico. El módulo incluye una acción para pedir el certificado con Certbot cuando el dominio ya apunta al servidor.
  • Odoo + DB Only (External Proxy). Sin nginx interno: sólo Odoo y Postgres. Lo uso cuando el frente público ya está resuelto por un nginx compartido (por ejemplo, mi CT-100, que hace de proxy para varios clientes) y sólo quiero el Odoo detrás, ligero y sin duplicar SSL.

oci-install-types.png

Las dos dimensiones son ortogonales: puedo tener un Full Stack directo sobre un VPS, o un Odoo + DB Only detrás de Proxmox envuelto en pct exec. Eso cubre casi todo lo que veo en el día a día.

El baremetal no se hace aquí. Para baremetal (Odoo instalado directamente sobre el sistema, sin Docker) uso oca_management, que es el próximo post de la serie. Es más, el propio oci_management tira de una plantilla de instalación (oca.install.template) que genera precisamente oca_management: la lista de repositorios OCA, las ramas, las dependencias Python. Es difícil separarlos: uno aporta el catálogo, el otro lo empaqueta en Docker.

Y lo que viene después: estoy empezando a llevar oci_management a desplegar sobre un clúster Kubernetes, para los clientes que ya tienen esa infraestructura. Cuando esté maduro vuelvo y lo cuento.

S4. TheBurgerPalace: un deploy real

Para que no se quede en teoría, este módulo acaba de parir un cliente real: TheBurgerPalace (TBP), una hostelería con POS. Odoo 18 CE sobre CT-150 en ipve1, 239 módulos instalados, chart de cuentas es_pymes, EUR, l10n_es desde el primer init. install_type = Detrás de Proxmox (porque el host es un Proxmox con varios LXC), deploy_type = Odoo + DB Only (porque el nginx público vive en CT-100 y hace de reverse proxy para todos los clientes).

oci-actions.png

En el proyecto de TBP, los tres botones que aparecen arriba son los que llevan la orquestación. LOAD REPOS FROM TEMPLATE lee la plantilla de oca_management y carga los repositorios OCA que toquen para la versión y las verticales elegidas. GENERATE MANIFEST FROM VERTICALS construye el manifest del módulo bundle custom a partir de las verticales (hostelería + POS + alérgenos, en este caso). DOWNLOAD CUSTOM MODULE FILES empaqueta el repo custom y lo sube a GitLab. Los tres encadenados dejan el árbol de código listo para el build Docker.

oci-server-instances-zoom70.png

En la pestaña de Server Instances del proyecto se ven los repositorios OCA aprovisionados. Para TBP terminaron siendo del orden de 140 repos: no porque haya elegido 140 a mano, sino porque las verticales eligen un puñado y el resto baja por resolución recursiva de dependencias. Cada repo OCA depende de otros repos OCA, y el árbol se desenrolla solo hasta que cierra; si te paras en el primer nivel te dejas fuera las transitivas y el build cascada en módulos que no encuentra. Esa fue una de las memorias que costaron sangre.

tbp-odoo18-home.png

Y al final, el Odoo 18 corriendo en theburgerpalace.lemontreecloud.com. La captura es la landing todavía sin debranding (toca en la fase siguiente), pero es un Odoo vivo con usuarios, POS, cocina y menú digital con QR.

He aprendido a fuerza de romper cosas: LXC privilegiado para que overlay2 funcione, l10n_es desde el primer init porque después no se cambia el plan contable, inicializar con --workers=0 --no-http para evitar carreras con el entrypoint, y preparar addon_requirements.txt antes del build. Todo eso está codificado como memorias en Claude; no vuelvo a pisarlas.

Una tarde para un Odoo completo. Y lo repetiré igual para el siguiente cliente.

Cierre

Si llegas hasta aquí, tres caminos, sin orden y sin venta:

  • Te lo monto yo. La infra es tuya, tú la alquilas con el proveedor que quieras, y yo opero encima con oci_management. Tú pides "otro Odoo para este cliente" y al rato lo tienes corriendo.
  • Te formo vía Open Teach Partner. Si prefieres que tu propia empresa entienda y opere esto, tengo un programa de formación pensado para ello (Odoo + OCA, infra Proxmox, agentes Claude). También vale si quieres que alguien de tu equipo ejerza ese rol.
  • Te inspiro y lo pides a otro. Este post existe para que sepas que la categoría ya existe. Si encuentras a otro que te lo monte mejor, adelante.

oci_management es la mitad on-premise y cloud. Para baremetal uso oca_management, y ese lo veremos pronto.

VPS, dedicado, cloud: dónde deben vivir los datos de tu PYME
Guía para directivos: qué elegir, por qué, y qué dice el RGPD de verdad