Odoo · Docker · DevOps
El mismo docker-compose.yml no debería servir para desarrollo y para producción: lo que en local es cómodo (montar el código como volumen, recargar en caliente) en producción es una vulnerabilidad, y lo que en producción da estabilidad (imagen inmutable, workers fijos) en local solo ralentiza el ciclo de prueba-error.
Desarrollo
En local: código como volumen, un solo worker, autoreload
En desarrollo el objetivo es iterar rápido: el código de tus módulos custom se monta como volumen para que cada cambio se refleje sin reconstruir la imagen, se usa un único proceso (--workers=0) para que los breakpoint() funcionen, y el modo --dev=all activa autoreload y assets sin minificar.
# docker-compose.dev.yml
services:
odoo:
image: odoo:19
volumes:
- ./addons:/mnt/extra-addons
- odoo-data-dev:/var/lib/odoo
command: >
odoo --workers=0 --dev=all
--db_host=db --db_user=odoo --db_password=odoo
ports:
- "8069:8069"
depends_on:
- db
--workers=0 es solo para desarrollo: con un único proceso no hay paralelismo real de requests; usarlo en producción convierte cualquier operación lenta en un cuello de botella para todos los usuarios.
Producción
En producción: imagen inmutable, multi-worker, sin volúmenes de código
En producción el código custom se copia (COPY) dentro de la imagen en el build, no se monta como volumen: así cada deploy es una imagen versionada y reproducible, sin sorpresas de "funcionaba en mi máquina". El número de --workers se dimensiona según CPU disponible, y --limit-memory-hard/--limit-time-cpu evitan que un request descontrolado tumbe el servicio entero.
# Dockerfile de producción
FROM odoo:19
COPY ./addons /mnt/extra-addons
# La imagen ya contiene el código: no depende de un volumen externo
# docker-compose.prod.yml
services:
odoo:
image: registro-interno/odoo-app:1.4.2
command: >
odoo --workers=4 --max-cron-threads=2
--limit-memory-hard=2684354560 --limit-time-cpu=60
volumes:
- odoo-filestore:/var/lib/odoo
restart: unless-stopped
Lo que nunca cambia
El filestore y la base de datos, siempre en volúmenes persistentes
Da igual el entorno: el filestore de adjuntos y los datos de PostgreSQL nunca deben vivir dentro del ciclo de vida efímero de un contenedor. Un docker compose down sin -v no debería poder borrar ni un adjunto ni una fila de producción; eso solo se garantiza con volúmenes nombrados explícitos, nunca con el filesystem interno del contenedor.
| Aspecto | Desarrollo | Producción |
|---|---|---|
| Código custom | Volumen montado | Copiado en la imagen (COPY) |
| Workers | --workers=0 | --workers=N según CPU |
| Modo dev/autoreload | --dev=all | Desactivado |
| Filestore y BD | Volumen (puede resetearse) | Volumen persistente + backup |
| Límites de recursos | Sin límite, prioriza velocidad | --limit-memory-hard, --limit-time-cpu |
Resumen
Desarrollo y producción comparten el mismo Dockerfile base pero no la misma composición: en local se optimiza para iterar rápido, en producción para estabilidad y reproducibilidad. Lo único que no cambia entre entornos es la persistencia del filestore y la base de datos fuera del ciclo de vida del contenedor.