Files
odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/index.html
T
2026-08-28 10:11:11 -03:00

2398 lines
101 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<link rel="preconnect" href="https://d3js.org" crossorigin>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="alternate icon" href="/favicon.ico">
<title>Odoo Docker Hosting 2026 | Odoo Expertos · FR</title>
<meta name="description" content="Guia definitiva de Odoo con Docker en 2026. Aprende a desplegar Odoo en contenedores: Docker Compose, configuracion, optimizacion, ba - Odoo Docker Hosting 2026 | FR">
<meta name="keywords" content="odoo docker, docker compose odoo, contenedores odoo, odoo docker hosting, desplegar odoo docker, odoo containerizado, docker postgresql odoo, odoo docker produccion">
<meta name="author" content="Dr. Equipo Odoo Expertos">
<meta name="robots" content="index, follow">
<meta name="language" content="fr">
<link rel="canonical" href="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/">
<!-- Hreflang -->
<link rel="alternate" hreflang="fr" href="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/" />
<link rel="alternate" hreflang="en" href="https://www.odoo-expertos.com/en/odoo-hosting/odoo-docker-hosting-2026/" />
<link rel="alternate" hreflang="de" href="https://www.odoo-expertos.com/de/odoo-hosting/odoo-docker-hosting-2026/" />
<link rel="alternate" hreflang="fr" href="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/" />
<link rel="alternate" hreflang="x-default" href="https://www.odoo-expertos.com/odoo-hosting/odoo-docker-hosting-2026/" />
<!-- Open Graph -->
<meta property="og:title" content="Odoo Docker Hébergement 2026: Guide Complet de Contenedores">
<meta property="og:description" content="Guia definitiva de Odoo con Docker en 2026. Aprende a desplegar Odoo en contenedores con Docker Compose, optimizacion y mejores practicas.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/">
<meta property="og:image" content="https://www.odoo-expertos.com/images/odoo-docker-hosting-2026.jpg">
<meta property="og:site_name" content="Odoo Expertos">
<meta property="og:locale" content="fr_FR">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Odoo Docker Hébergement 2026: Guide Complet de Contenedores">
<meta name="twitter:description" content="Guia definitiva de Odoo con Docker. Docker Compose, optimizacion, backups y mejores proveedores.">
<!-- Schema.org Article -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "Odoo Docker Hébergement 2026: Guide Complet de Contenedores",
"description": "Guia definitiva de Odoo con Docker en 2026. Aprende a desplegar Odoo en contenedores: Docker Compose, configuracion, optimizacion, backups y mejores proveedores de hosting Docker.",
"author": {
"@type": "Person",
"name": "Dr. Equipo Odoo Expertos",
"url": "https://www.odoo-expertos.com/autor/maria-elena-rodriguez/",
"jobTitle": "Consultante Senior en Systèmes ERP"
},
"publisher": {
"@type": "Organization",
"name": "Odoo Expertos",
"logo": {
"@type": "ImageObject",
"url": "https://www.odoo-expertos.com/logo.png"
}
},
"datePublished": "2026-01-25",
"dateModified": "2026-01-25",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/"
},
"proficiencyLevel": "Intermediate",
"dependencies": "Docker, Docker Compose, PostgreSQL"
}
</script>
<!-- FAQ Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Es Docker recomendable pour Odoo en produccion?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Si, Docker es altamente recomendable pour Odoo en produccion en 2026. Ofrece aislamiento, reproducibilidad, escalabilidad horizontal y facilita los despliegues. Empresas como Amazon, Google y Microsoft utilizan contenedores en produccion. La clave esta en una correcta configuracion de volumenes persistentes, redes y orquestacion."
}
},
{
"@type": "Question",
"name": "Cuantos recursos necesita Odoo en Docker?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pour Odoo 18 en Docker se recomienda: 4GB RAM minimo (8GB recomendado), 2 CPU cores (4 recomendado), 40GB SSD pour volumenes. Docker anade aproximadamente un 2-5% de overhead compourdo con instalacion nativa, pero los beneficios de gestion superan ampliamente este coste."
}
},
{
"@type": "Question",
"name": "Como hago backup de Odoo en Docker?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pour backup de Odoo en Docker: 1) Backup de PostgreSQL con pg_dump desde el contenedor, 2) Backup del volumen filestore, 3) Backup de configuracion odoo.conf. Automatiza con cron jobs y docker exec. Recomendamos backups incrementales diarios y completos semanales con retencion de 30 dias."
}
},
{
"@type": "Question",
"name": "Puedo usar Docker Compose pour multiples instancias de Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Si, Docker Compose es ideal pour multi-tenant Odoo. Puedes definir multiples servicios Odoo en el mismo archivo compose, cada uno con su propia base de datos. Usa Traefik o Nginx como reverse proxy pour enrutar dominios a cada instancia. Esto es perfecto pour agencias que gestionan varios clientes."
}
},
{
"@type": "Question",
"name": "Docker Swarm o Kubernetes pour Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pour la mayoria de despliegues Odoo, Docker Swarm es suficiente y mas simple de gestionar. Kubernetes es recomendable solo pour despliegues muy grandes (100+ usuarios concurrentes) o si ya tienes infraestructura K8s. Docker Swarm ofrece alta disponibilidad, balanceo de carga y escalado con menor complejidad operativa."
}
},
{
"@type": "Question",
"name": "Como actualizo Odoo en Docker sin downtime?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pour actualizar Odoo en Docker con minimo downtime: 1) Pull de la nueva imagen, 2) Backup completo, 3) Levantar nuevo contenedor en pourlelo, 4) Ejecutar migracion de base de datos, 5) Cambiar el proxy al nuevo contenedor, 6) Eliminar contenedor antiguo. Con Docker Swarm puedes hacer rolling updates automaticos."
}
},
{
"@type": "Question",
"name": "Cual es la mejor imagen Docker pour Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "La imagen oficial de Odoo (odoo:18) es la recomendada pour produccion. Esta optimizada, actualizada regularmente y soportada. Pour personalizaciones, crea tu propia imagen basada en la oficial con un Dockerfile. Evita imagenes de terceros no verificadas por razones de seguridad."
}
},
{
"@type": "Question",
"name": "Como configuro SSL/HTTPS pour Odoo en Docker?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Pour SSL en Odoo Docker usa un reverse proxy: 1) Traefik con Let's Encrypt automatico (recomendado), 2) Nginx con Certbot, 3) Caddy con SSL automatico. El proxy maneja SSL y redirige al contenedor Odoo via HTTP interno. Nunca expongas Odoo directamente a internet sin SSL."
}
}
]
}
</script>
<!-- HowTo Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Como desplegar Odoo con Docker Compose",
"description": "Guia paso a paso pour desplegar Odoo 18 en produccion usando Docker y Docker Compose",
"totalTime": "PT30M",
"estimatedCost": {
"@type": "MonetaryAmount",
"currency": "EUR",
"value": "0"
},
"tool": [
{
"@type": "HowToTool",
"name": "Docker Engine"
},
{
"@type": "HowToTool",
"name": "Docker Compose"
}
],
"step": [
{
"@type": "HowToStep",
"name": "Instalar Docker",
"text": "Instala Docker Engine y Docker Compose en tu servidor Ubuntu 24.04"
},
{
"@type": "HowToStep",
"name": "Crear docker-compose.yml",
"text": "Crea el archivo docker-compose.yml con los servicios de Odoo y PostgreSQL"
},
{
"@type": "HowToStep",
"name": "Configurar volumenes",
"text": "Define volumenes persistentes pour datos de PostgreSQL y filestore de Odoo"
},
{
"@type": "HowToStep",
"name": "Iniciar contenedores",
"text": "Ejecuta docker compose up -d pour iniciar los servicios"
},
{
"@type": "HowToStep",
"name": "Configurar reverse proxy",
"text": "Configura Traefik o Nginx como reverse proxy con SSL"
}
]
}
</script>
<!-- BreadcrumbList Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Inicio",
"item": "https://www.odoo-expertos.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Hosting Odoo",
"item": "https://www.odoo-expertos.com/fr/odoo-hosting/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Odoo Docker Hosting 2026",
"item": "https://www.odoo-expertos.com/fr/odoo-hosting/odoo-docker-hosting-2026/"
}
]
}
</script>
<!-- Product Comparison Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ItemList",
"name": "Mejores Proveedores de Docker Hosting pour Odoo 2026",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"item": {
"@type": "Product",
"name": "DigitalOcean App Platform",
"description": "Plataforma de contenedores gestionada ideal pour Odoo Docker",
"offers": {
"@type": "Offer",
"price": "25",
"priceCurrency": "EUR"
}
}
},
{
"@type": "ListItem",
"position": 2,
"item": {
"@type": "Product",
"name": "Hetzner Cloud",
"description": "VPS de alto rendimiento con Docker preinstalado",
"offers": {
"@type": "Offer",
"price": "15",
"priceCurrency": "EUR"
}
}
},
{
"@type": "ListItem",
"position": 3,
"item": {
"@type": "Product",
"name": "AWS ECS/Fargate",
"description": "Orquestacion de contenedores empresarial",
"offers": {
"@type": "Offer",
"price": "50",
"priceCurrency": "EUR"
}
}
}
]
}
</script>
<link rel="stylesheet" href="/css/main.min.css">
<style>
.pillar-hero {
background: linear-gradient(135deg, #1a1a1a 0%, #0d47a1 50%, #1a1a1a 100%);
padding: 4rem 2rem;
text-align: center;
border-bottom: 3px solid #2196F3;
position: relative;
overflow: hidden;
}
.pillar-hero::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: radial-gradient(ellipse at center, rgba(33,150,243,0.15) 0%, transparent 70%);
pointer-events: none;
}
.pillar-hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
color: #2196F3;
margin-bottom: 1rem;
line-height: 1.2;
position: relative;
}
.pillar-subtitle {
font-size: 1.3rem;
color: #b0b0b0;
max-width: 800px;
margin: 0 auto 2rem;
}
.pillar-meta {
display: flex;
justify-content: center;
gap: 2rem;
flex-wrap: wrap;
font-size: 0.9rem;
color: #888;
}
.pillar-meta span {
display: flex;
align-items: center;
gap: 0.5rem;
}
.quick-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1.5rem;
padding: 2rem;
background: #2a2a2a;
border-radius: 12px;
margin: 2rem 0;
}
.stat-card {
text-align: center;
padding: 1.5rem;
background: rgba(33,150,243,0.1);
border-radius: 8px;
border: 1px solid rgba(33,150,243,0.2);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
border-color: #2196F3;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: #2196F3;
display: block;
}
.stat-label {
color: #b0b0b0;
font-size: 0.9rem;
margin-top: 0.5rem;
}
.toc {
background: #2a2a2a;
border: 2px solid #2196F3;
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
}
.toc h2 {
color: #2196F3;
margin-bottom: 1rem;
font-size: 1.5rem;
}
.toc-list {
list-style: none;
padding: 0;
columns: 2;
column-gap: 2rem;
}
.toc-list li {
margin-bottom: 0.75rem;
break-inside: avoid;
}
.toc-list a {
color: #e0e0e0;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
transition: color 0.3s ease;
}
.toc-list a:hover {
color: #2196F3;
}
.toc-list a::before {
content: '>';
color: #2196F3;
font-family: monospace;
}
.content-section {
margin: 3rem 0;
}
.content-section h2 {
color: #64B5F6;
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid rgba(33,150,243,0.3);
}
.content-section h3 {
color: #90CAF9;
margin: 2rem 0 1rem;
}
.chart-section {
margin: 3rem 0;
padding: 2rem;
background: #2a2a2a;
border-radius: 12px;
}
.chart-section h3 {
color: #64B5F6;
margin-bottom: 1rem;
}
.chart-container {
width: 100%;
min-height: 400px;
position: relative;
}
.code-block {
background: #1a1a2e;
border-radius: 8px;
padding: 1.5rem;
margin: 1.5rem 0;
overflow-x: auto;
border: 1px solid #333;
position: relative;
}
.code-block::before {
content: attr(data-lang);
position: absolute;
top: 0;
right: 0;
background: #2196F3;
color: #fff;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
border-radius: 0 8px 0 8px;
text-transform: uppercase;
}
.code-block pre {
margin: 0;
color: #e0e0e0;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.9rem;
line-height: 1.6;
white-space: pre;
}
.code-block .comment { color: #6a9955; }
.code-block .keyword { color: #569cd6; }
.code-block .string { color: #ce9178; }
.code-block .number { color: #b5cea8; }
.code-block .property { color: #9cdcfe; }
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
background: #2a2a2a;
border-radius: 12px;
overflow: hidden;
}
.comparison-table th,
.comparison-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid #3a3a3a;
}
.comparison-table th {
background: rgba(33,150,243,0.2);
color: #2196F3;
font-weight: 600;
}
.comparison-table tr:hover {
background: rgba(33,150,243,0.05);
}
.comparison-table .check {
color: #4CAF50;
font-weight: bold;
}
.comparison-table .cross {
color: #f44336;
}
.provider-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.provider-card {
background: #2a2a2a;
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(33,150,243,0.2);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.provider-card:hover {
transform: translateY(-5px);
border-color: #2196F3;
}
.provider-card.featured {
border-color: #2196F3;
background: linear-gradient(135deg, rgba(33,150,243,0.15) 0%, #2a2a2a 100%);
position: relative;
}
.provider-card .badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #2196F3;
color: #fff;
border-radius: 20px;
font-size: 0.8rem;
margin-bottom: 1rem;
}
.provider-card h4 {
color: #fff;
margin-bottom: 0.5rem;
font-size: 1.3rem;
}
.provider-card .price {
font-size: 2rem;
color: #2196F3;
font-weight: 700;
}
.provider-card .price-period {
color: #888;
font-size: 0.9rem;
}
.provider-card ul {
list-style: none;
padding: 0;
margin: 1rem 0;
}
.provider-card li {
padding: 0.5rem 0;
border-bottom: 1px solid #3a3a3a;
display: flex;
align-items: center;
gap: 0.5rem;
color: #b0b0b0;
}
.provider-card li::before {
content: '>';
color: #4CAF50;
font-weight: bold;
font-family: monospace;
}
.provider-card .cta-btn {
display: block;
text-align: center;
padding: 0.75rem 1.5rem;
background: #2196F3;
color: #fff;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: background 0.3s ease, transform 0.3s ease;
margin-top: 1rem;
}
.provider-card .cta-btn:hover {
background: #64B5F6;
transform: scale(1.02);
}
.faq-section {
margin: 3rem 0;
}
.faq-item {
background: #2a2a2a;
border-radius: 8px;
margin-bottom: 1rem;
overflow: hidden;
}
.faq-question {
padding: 1.25rem;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
color: #fff;
font-weight: 500;
transition: background 0.3s ease;
}
.faq-question:hover {
background: rgba(33,150,243,0.1);
}
.faq-question::after {
content: '+';
font-size: 1.5rem;
color: #2196F3;
transition: transform 0.3s ease;
}
.faq-item.open .faq-question::after {
transform: rotate(45deg);
}
.faq-answer {
padding: 0 1.25rem;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
color: #b0b0b0;
}
.faq-item.open .faq-answer {
padding: 0 1.25rem 1.25rem;
max-height: 500px;
}
.cta-banner {
background: linear-gradient(135deg, rgba(33,150,243,0.2) 0%, rgba(100,181,246,0.1) 100%);
border: 2px solid rgba(33,150,243,0.5);
border-radius: 12px;
padding: 2.5rem;
text-align: center;
margin: 3rem 0;
}
.cta-banner h3 {
color: #2196F3;
margin-bottom: 1rem;
font-size: 1.8rem;
}
.cta-banner p {
margin-bottom: 1.5rem;
color: #b0b0b0;
font-size: 1.1rem;
}
.cta-banner .cta-btn {
display: inline-block;
padding: 1rem 2.5rem;
background: #2196F3;
color: #fff;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
font-size: 1.1rem;
transition: background 0.3s ease, transform 0.3s ease;
}
.cta-banner .cta-btn:hover {
background: #64B5F6;
transform: scale(1.05);
}
.related-articles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.related-card {
background: #2a2a2a;
border-radius: 8px;
overflow: hidden;
transition: transform 0.3s ease;
text-decoration: none;
}
.related-card:hover {
transform: translateY(-5px);
}
.related-card-image {
height: 150px;
background: linear-gradient(135deg, rgba(33,150,243,0.3), rgba(100,181,246,0.3));
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
}
.related-card-content {
padding: 1.25rem;
}
.related-card h4 {
color: #fff;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.related-card p {
color: #888;
font-size: 0.9rem;
margin: 0;
}
.d3-tooltip {
position: absolute;
background: rgba(0,0,0,0.95);
color: #fff;
padding: 0.75rem 1rem;
border-radius: 8px;
font-size: 0.9rem;
pointer-events: none;
z-index: 100;
max-width: 280px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
border: 1px solid rgba(33,150,243,0.3);
}
.d3-tooltip strong {
color: #2196F3;
}
.highlight-box {
background: linear-gradient(135deg, rgba(33,150,243,0.1) 0%, rgba(100,181,246,0.05) 100%);
border-left: 4px solid #2196F3;
padding: 1.5rem;
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.highlight-box h4 {
color: #2196F3;
margin-bottom: 0.5rem;
}
.warning-box {
background: linear-gradient(135deg, rgba(255,152,0,0.1) 0%, rgba(255,193,7,0.05) 100%);
border-left: 4px solid #FF9800;
padding: 1.5rem;
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.warning-box h4 {
color: #FF9800;
margin-bottom: 0.5rem;
}
.pros-cons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
margin: 1.5rem 0;
}
.pros, .cons {
padding: 1.5rem;
border-radius: 8px;
}
.pros {
background: rgba(76, 175, 80, 0.1);
border: 1px solid rgba(76, 175, 80, 0.3);
}
.cons {
background: rgba(244, 67, 54, 0.1);
border: 1px solid rgba(244, 67, 54, 0.3);
}
.pros h4 {
color: #4CAF50;
margin-bottom: 1rem;
}
.cons h4 {
color: #f44336;
margin-bottom: 1rem;
}
.pros ul, .cons ul {
list-style: none;
padding: 0;
margin: 0;
}
.pros li::before {
content: '> ';
color: #4CAF50;
}
.cons li::before {
content: 'x ';
color: #f44336;
}
.architecture-diagram {
background: #1a1a2e;
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
border: 1px solid #333;
}
.step-list {
counter-reset: step-counter;
list-style: none;
padding: 0;
}
.step-list li {
counter-increment: step-counter;
padding: 1rem 0 1rem 3.5rem;
position: relative;
border-left: 2px solid #333;
margin-left: 1rem;
}
.step-list li::before {
content: counter(step-counter);
position: absolute;
left: -1.25rem;
top: 1rem;
width: 2.5rem;
height: 2.5rem;
background: #2196F3;
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.step-list li:last-child {
border-left: 2px solid transparent;
}
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 768px) {
.toc-list {
columns: 1;
}
.pillar-meta {
flex-direction: column;
gap: 0.5rem;
}
.chart-container {
min-height: 300px;
}
.pros-cons {
grid-template-columns: 1fr;
}
.provider-grid {
grid-template-columns: 1fr;
}
.code-block {
font-size: 0.8rem;
}
}
</style>
</head>
<body>
<div id="header"><header class="site-header"><nav class="navbar"><div class="container"><div class="nav-brand"><a href="/fr/" class="logo"><span class="logo-text">Odoo Expertos</span></a></div><button class="nav-toggle" aria-label="Toggle navigation"><span></span><span></span><span></span></button><div class="nav-menu"><ul class="nav-list"><li><a href="/fr/">Accueil</a></li><li><a href="/fr/odoo/">Odoo</a></li><li><a href="/fr/odoo-ia/">Odoo IA</a></li><li><a href="/fr/odoo-hosting/">Hebergement Odoo</a></li><li><a href="/fr/mapa-del-sitio/">Plan du Site</a></li></ul></div></div></nav></header></div><button class="nav-toggle" aria-label="Toggle navigation"><span></span><span></span><span></span></button><div class="nav-menu"><ul class="nav-list"><li><a href="/fr/">Accueil</a></li><li><a href="/fr/odoo/">Odoo</a></li><li><a href="/fr/odoo-ia/">Odoo IA</a></li><li><a href="/fr/odoo-hosting/">Hebergement Odoo</a></li><li><a href="/fr/mapa-del-sitio/">Plan du Site</a></li></ul></div></div></nav></header></div>
<!-- Breadcrumbs -->
<nav class="breadcrumbs">
<div class="container">
<ol class="breadcrumb-list" itemscope itemtype="https://schema.org/BreadcrumbList">
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/"><span itemprop="name">Accueil</span></a>
<span itemprop="position" style="display:none">1</span>
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/fr/odoo-hosting/"><span itemprop="name">Hébergement Odoo</span></a>
<span itemprop="position" style="display:none">2</span>
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<span itemprop="name">Odoo Docker Hosting 2026</span>
<span itemprop="position" style="display:none">3</span>
</li>
</ol>
</div>
</nav>
<!-- Hero Section -->
<section class="pillar-hero">
<div class="container">
<h1>Odoo Docker Hosting 2026: Guia Completa de Contenedores</h1>
<p class="pillar-subtitle">Domina el despliegue de Odoo con Docker. Aprende Docker Compose, optimizacion de rendimiento, estrategias de backup y los mejores proveedores de hosting pour contenedores.</p>
<div class="pillar-meta">
<span>Publié : 25 janvier 2026</span>
<span>Mis à jour : 25 janvier 2026</span>
<span>30 min lectura</span>
<span>Dr. Equipo Odoo Expertos</span>
</div>
</div>
</section>
<main class="container">
<!-- Quick Stats -->
<section class="quick-stats fade-in">
<div class="stat-card">
<span class="stat-number">85%</span>
<span class="stat-label">Empresas usan Docker</span>
</div>
<div class="stat-card">
<span class="stat-number">70%</span>
<span class="stat-label">Reduccion tiempo deploy</span>
</div>
<div class="stat-card">
<span class="stat-number">15EUR</span>
<span class="stat-label">Precio minimo/mes</span>
</div>
<div class="stat-card">
<span class="stat-number">99.9%</span>
<span class="stat-label">Uptime con orquestacion</span>
</div>
<div class="stat-card">
<span class="stat-number">5min</span>
<span class="stat-label">Tiempo de despliegue</span>
</div>
</section>
<!-- Table of Contents -->
<nav class="toc fade-in">
<h2>Contenido de esta Guia</h2>
<ol class="toc-list">
<li><a href="#introduccion">Por que Docker pour Odoo</a></li>
<li><a href="#arquitectura">Arquitectura Docker pour Odoo</a></li>
<li><a href="#docker-compose">Docker Compose Configuracion</a></li>
<li><a href="#optimizacion">Optimizacion de Rendimiento</a></li>
<li><a href="#proveedores">Mejores Proveedores Docker</a></li>
<li><a href="#backups">Backup y Recuperacion</a></li>
<li><a href="#seguridad">Seguridad en Contenedores</a></li>
<li><a href="#orquestacion">Swarm vs Kubernetes</a></li>
<li><a href="#faq">Preguntas Frecuentes (8+)</a></li>
<li><a href="#relacionados">Articles Connexes</a></li>
</ol>
</nav>
<!-- Introduction Section -->
<section id="introduccion" class="content-section fade-in">
<h2>Por que Docker es la Mejor Opcion pour Odoo en 2026</h2>
<p>La contenedorizacion ha revolucionado la forma en que desplegamos y gestionamos aplicaciones empresariales. En 2026, Docker se ha consolidado como el estandar de facto pour despliegues de Odoo, ofreciendo ventajas significativas sobre las instalaciones tradicionales en servidores bare metal.</p>
<p>Segun las ultimas estadisticas de la industria, mas del 85% de las empresas que implementan Odoo en produccion utilizan algun tipo de contenedorizacion. Docker, con su ecosistema maduro y amplia documentacion, lidera este mercado con una cuota superior al 70%.</p>
<div class="highlight-box">
<h4>Conclusion Clave</h4>
<p>Docker no solo simplifica el despliegue de Odoo, sino que reduce el tiempo de configuracion de dias a minutos, garantiza consistencia entre entornos de desarrollo y produccion, y facilita la escalabilidad horizontal cuando tu negocio crece.</p>
</div>
<h3>Beneficios de Odoo Containerizado</h3>
<div class="pros-cons">
<div class="pros">
<h4>Ventajas de Docker</h4>
<ul>
<li>Aislamiento completo de dependencias</li>
<li>Reproducibilidad garantizada</li>
<li>Escalabilidad horizontal sencilla</li>
<li>Rollback instantaneo ante fallos</li>
<li>Menor consumo de recursos vs VMs</li>
<li>CI/CD integrado nativamente</li>
<li>Portabilidad entre proveedores</li>
</ul>
</div>
<div class="cons">
<h4>Consideraciones</h4>
<ul>
<li>Curva de aprendizaje inicial</li>
<li>Overhead de 2-5% en rendimiento</li>
<li>Complejidad en networking</li>
<li>Gestion de volumenes persistentes</li>
<li>Requiere monitorizacion adicional</li>
</ul>
</div>
</div>
<h3>Docker vs Instalacion Tradicional</h3>
<p>La instalacion tradicional de Odoo implica configurar manualmente Python, PostgreSQL, dependencias del sistema, wkhtmltopdf y multiples bibliotecas. Este proceso puede tardar horas y es propenso a errores. Con Docker, todo esto se reduce a un simple comando que levanta un entorno identico cada vez.</p>
<p>Ademas, cuando necesitas actualizar Odoo o migrar a un nuevo servidor, Docker permite hacer pull de la nueva imagen, probarla en pourlelo y cambiar el trafico sin interrupcion. En una instalacion tradicional, este proceso requiere planificacion cuidadosa y frecuentemente implica downtime.</p>
</section>
<!-- Architecture Diagram Section -->
<section class="chart-section fade-in">
<h3 id="arquitectura">Arquitectura Docker pour Odoo: Diagrama Interactivo</h3>
<p>Explora la arquitectura recomendada pour desplegar Odoo con Docker. Pasa el cursor sobre cada componente pour ver detalles de configuracion.</p>
<div class="chart-container" id="architecture-diagram"></div>
</section>
<!-- Docker Compose Section -->
<section id="docker-compose" class="content-section fade-in">
<h2>Configuracion Docker Compose pour Odoo 18</h2>
<p>Docker Compose es la herramienta preferida pour definir y ejecutar aplicaciones multi-contenedor. Pour Odoo, necesitamos al menos dos servicios: el servidor Odoo y la base de datos PostgreSQL. A continuacion presentamos configuraciones desde basica hasta produccion.</p>
<h3>Configuracion Basica pour Desarrollo</h3>
<p>Esta configuracion es ideal pour desarrollo local y pruebas. Incluye los servicios esenciales con configuracion minima.</p>
<div class="code-block" data-lang="yaml">
<pre><span class="comment"># docker-compose.yml - Configuracion basica</span>
<span class="keyword">version</span>: <span class="string">'3.8'</span>
<span class="keyword">services</span>:
<span class="property">odoo</span>:
<span class="keyword">image</span>: <span class="string">odoo:18</span>
<span class="keyword">depends_on</span>:
- <span class="string">db</span>
<span class="keyword">ports</span>:
- <span class="string">"8069:8069"</span>
<span class="keyword">volumes</span>:
- <span class="string">odoo-data:/var/lib/odoo</span>
- <span class="string">./config:/etc/odoo</span>
- <span class="string">./addons:/mnt/extra-addons</span>
<span class="keyword">environment</span>:
- <span class="property">HOST</span>=<span class="string">db</span>
- <span class="property">USER</span>=<span class="string">odoo</span>
- <span class="property">PASSWORD</span>=<span class="string">odoo_password</span>
<span class="property">db</span>:
<span class="keyword">image</span>: <span class="string">postgres:16</span>
<span class="keyword">environment</span>:
- <span class="property">POSTGRES_DB</span>=<span class="string">postgres</span>
- <span class="property">POSTGRES_USER</span>=<span class="string">odoo</span>
- <span class="property">POSTGRES_PASSWORD</span>=<span class="string">odoo_password</span>
<span class="keyword">volumes</span>:
- <span class="string">db-data:/var/lib/postgresql/data</span>
<span class="keyword">volumes</span>:
<span class="property">odoo-data</span>:
<span class="property">db-data</span>:</pre>
</div>
<h3>Configuracion Avanzada pour Produccion</h3>
<p>Pour entornos de produccion, necesitamos anadir reverse proxy con SSL, limites de recursos, healthchecks, logging y configuracion de red aislada.</p>
<div class="code-block" data-lang="yaml">
<pre><span class="comment"># docker-compose.prod.yml - Configuracion produccion</span>
<span class="keyword">version</span>: <span class="string">'3.8'</span>
<span class="keyword">services</span>:
<span class="property">traefik</span>:
<span class="keyword">image</span>: <span class="string">traefik:v3.0</span>
<span class="keyword">command</span>:
- <span class="string">"--api.dashboard=true"</span>
- <span class="string">"--providers.docker=true"</span>
- <span class="string">"--entrypoints.web.address=:80"</span>
- <span class="string">"--entrypoints.websecure.address=:443"</span>
- <span class="string">"--certificatesresolvers.letsencrypt.acme.email=admin@tudominio.com"</span>
- <span class="string">"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"</span>
- <span class="string">"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"</span>
<span class="keyword">ports</span>:
- <span class="string">"80:80"</span>
- <span class="string">"443:443"</span>
<span class="keyword">volumes</span>:
- <span class="string">/var/run/docker.sock:/var/run/docker.sock:ro</span>
- <span class="string">letsencrypt:/letsencrypt</span>
<span class="keyword">networks</span>:
- <span class="string">odoo-network</span>
<span class="property">odoo</span>:
<span class="keyword">image</span>: <span class="string">odoo:18</span>
<span class="keyword">depends_on</span>:
<span class="property">db</span>:
<span class="keyword">condition</span>: <span class="string">service_healthy</span>
<span class="keyword">labels</span>:
- <span class="string">"traefik.enable=true"</span>
- <span class="string">"traefik.http.routers.odoo.rule=Host(`erp.tudominio.com`)"</span>
- <span class="string">"traefik.http.routers.odoo.tls.certresolver=letsencrypt"</span>
- <span class="string">"traefik.http.services.odoo.loadbalancer.server.port=8069"</span>
<span class="keyword">volumes</span>:
- <span class="string">odoo-data:/var/lib/odoo</span>
- <span class="string">./config/odoo.conf:/etc/odoo/odoo.conf:ro</span>
- <span class="string">./addons:/mnt/extra-addons:ro</span>
<span class="keyword">environment</span>:
- <span class="property">HOST</span>=<span class="string">db</span>
- <span class="property">USER</span>=<span class="string">odoo</span>
- <span class="property">PASSWORD_FILE</span>=<span class="string">/run/secrets/db_password</span>
<span class="keyword">secrets</span>:
- <span class="string">db_password</span>
<span class="keyword">deploy</span>:
<span class="keyword">resources</span>:
<span class="keyword">limits</span>:
<span class="property">cpus</span>: <span class="string">'2'</span>
<span class="property">memory</span>: <span class="string">4G</span>
<span class="keyword">reservations</span>:
<span class="property">cpus</span>: <span class="string">'1'</span>
<span class="property">memory</span>: <span class="string">2G</span>
<span class="keyword">healthcheck</span>:
<span class="keyword">test</span>: [<span class="string">"CMD"</span>, <span class="string">"curl"</span>, <span class="string">"-f"</span>, <span class="string">"http://localhost:8069/web/health"</span>]
<span class="keyword">interval</span>: <span class="string">30s</span>
<span class="keyword">timeout</span>: <span class="string">10s</span>
<span class="keyword">retries</span>: <span class="number">3</span>
<span class="keyword">networks</span>:
- <span class="string">odoo-network</span>
<span class="keyword">restart</span>: <span class="string">unless-stopped</span>
<span class="property">db</span>:
<span class="keyword">image</span>: <span class="string">postgres:16-alpine</span>
<span class="keyword">environment</span>:
- <span class="property">POSTGRES_DB</span>=<span class="string">postgres</span>
- <span class="property">POSTGRES_USER</span>=<span class="string">odoo</span>
- <span class="property">POSTGRES_PASSWORD_FILE</span>=<span class="string">/run/secrets/db_password</span>
<span class="keyword">secrets</span>:
- <span class="string">db_password</span>
<span class="keyword">volumes</span>:
- <span class="string">db-data:/var/lib/postgresql/data</span>
- <span class="string">./postgres/postgresql.conf:/etc/postgresql/postgresql.conf:ro</span>
<span class="keyword">command</span>: <span class="string">postgres -c config_file=/etc/postgresql/postgresql.conf</span>
<span class="keyword">deploy</span>:
<span class="keyword">resources</span>:
<span class="keyword">limits</span>:
<span class="property">cpus</span>: <span class="string">'2'</span>
<span class="property">memory</span>: <span class="string">2G</span>
<span class="keyword">healthcheck</span>:
<span class="keyword">test</span>: [<span class="string">"CMD-SHELL"</span>, <span class="string">"pg_isready -U odoo"</span>]
<span class="keyword">interval</span>: <span class="string">10s</span>
<span class="keyword">timeout</span>: <span class="string">5s</span>
<span class="keyword">retries</span>: <span class="number">5</span>
<span class="keyword">networks</span>:
- <span class="string">odoo-network</span>
<span class="keyword">restart</span>: <span class="string">unless-stopped</span>
<span class="keyword">secrets</span>:
<span class="property">db_password</span>:
<span class="keyword">file</span>: <span class="string">./secrets/db_password.txt</span>
<span class="keyword">volumes</span>:
<span class="property">odoo-data</span>:
<span class="property">db-data</span>:
<span class="property">letsencrypt</span>:
<span class="keyword">networks</span>:
<span class="property">odoo-network</span>:
<span class="keyword">driver</span>: <span class="string">bridge</span></pre>
</div>
<h3>Archivo de Configuracion odoo.conf</h3>
<div class="code-block" data-lang="ini">
<pre><span class="comment">; /config/odoo.conf - Configuracion optimizada</span>
[<span class="keyword">options</span>]
<span class="property">addons_path</span> = <span class="string">/mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons</span>
<span class="property">data_dir</span> = <span class="string">/var/lib/odoo</span>
<span class="property">admin_passwd</span> = <span class="string">$pbkdf2-sha512$your_hashed_password</span>
<span class="comment">; Configuracion de workers pour produccion</span>
<span class="property">workers</span> = <span class="number">4</span>
<span class="property">max_cron_threads</span> = <span class="number">2</span>
<span class="property">limit_memory_hard</span> = <span class="number">2684354560</span>
<span class="property">limit_memory_soft</span> = <span class="number">2147483648</span>
<span class="property">limit_request</span> = <span class="number">8192</span>
<span class="property">limit_time_cpu</span> = <span class="number">600</span>
<span class="property">limit_time_real</span> = <span class="number">1200</span>
<span class="property">limit_time_real_cron</span> = <span class="number">-1</span>
<span class="comment">; Proxy y seguridad</span>
<span class="property">proxy_mode</span> = <span class="string">True</span>
<span class="property">xmlrpc_interface</span> = <span class="string">0.0.0.0</span>
<span class="property">netrpc_interface</span> = <span class="string">0.0.0.0</span>
<span class="comment">; Logging</span>
<span class="property">logfile</span> = <span class="string">/var/log/odoo/odoo.log</span>
<span class="property">log_level</span> = <span class="string">warn</span>
<span class="property">log_handler</span> = <span class="string">:WARNING,werkzeug:WARNING,odoo.addons:WARNING</span>
<span class="comment">; Base de datos</span>
<span class="property">db_host</span> = <span class="string">db</span>
<span class="property">db_port</span> = <span class="number">5432</span>
<span class="property">db_maxconn</span> = <span class="number">64</span>
<span class="property">db_template</span> = <span class="string">template0</span></pre>
</div>
<div class="warning-box">
<h4>Importante: Seguridad de Passwords</h4>
<p>Nunca guardes passwords en texto plano en archivos de configuracion. Usa Docker secrets como se muestra en la configuracion de produccion, o variables de entorno inyectadas desde un sistema de gestion de secretos como HashiCorp Vault.</p>
</div>
</section>
<!-- Performance Comparison Chart -->
<section class="chart-section fade-in">
<h3 id="optimizacion">Compourtiva de Rendimiento: Docker vs Nativo vs VM</h3>
<p>Este grafico muestra el rendimiento relativo de Odoo en diferentes entornos de despliegue. Los valores representan transacciones por segundo normalizadas.</p>
<div class="chart-container" id="performance-chart"></div>
</section>
<!-- Optimization Section -->
<section class="content-section fade-in">
<h2>Optimizacion de Rendimiento pour Odoo Docker</h2>
<p>Aunque Docker introduce un overhead minimo (2-5%), una configuracion incorrecta puede degradar significativamente el rendimiento. Estas son las optimizaciones esenciales pour maximizar el rendimiento de tu Odoo containerizado.</p>
<h3>1. Configuracion de Workers</h3>
<p>El numero de workers determina cuantas peticiones puede manejar Odoo simultaneamente. La formula recomendada es:</p>
<div class="highlight-box">
<h4>Formula de Workers</h4>
<p><strong>workers = (CPU cores * 2) + 1</strong></p>
<p>Pour un servidor con 4 cores: workers = (4 * 2) + 1 = 9 workers</p>
<p>Cada worker consume aproximadamente 150-300MB de RAM.</p>
</div>
<h3>2. Optimizacion de PostgreSQL</h3>
<div class="code-block" data-lang="conf">
<pre><span class="comment"># postgresql.conf optimizado pour Odoo</span>
<span class="property">shared_buffers</span> = <span class="string">512MB</span>
<span class="property">effective_cache_size</span> = <span class="string">1536MB</span>
<span class="property">maintenance_work_mem</span> = <span class="string">128MB</span>
<span class="property">checkpoint_completion_target</span> = <span class="number">0.9</span>
<span class="property">wal_buffers</span> = <span class="string">16MB</span>
<span class="property">default_statistics_target</span> = <span class="number">100</span>
<span class="property">random_page_cost</span> = <span class="number">1.1</span>
<span class="property">effective_io_concurrency</span> = <span class="number">200</span>
<span class="property">work_mem</span> = <span class="string">10MB</span>
<span class="property">min_wal_size</span> = <span class="string">1GB</span>
<span class="property">max_wal_size</span> = <span class="string">4GB</span>
<span class="property">max_worker_processes</span> = <span class="number">4</span>
<span class="property">max_pourllel_workers_per_gather</span> = <span class="number">2</span>
<span class="property">max_pourllel_workers</span> = <span class="number">4</span>
<span class="property">max_pourllel_maintenance_workers</span> = <span class="number">2</span></pre>
</div>
<h3>3. Volumenes: Bind Mounts vs Named Volumes</h3>
<p>Pour datos de produccion, usa named volumes gestionados por Docker. Son mas eficientes y faciles de respaldar. Los bind mounts son utiles solo pour desarrollo cuando necesitas editar archivos directamente.</p>
<h3>4. Network Mode</h3>
<p>Pour comunicacion entre contenedores en el mismo host, usa networks bridge personalizadas. Evita el modo host excepto pour debug. Las redes overlay son necesarias pour Docker Swarm multi-nodo.</p>
<ul class="step-list">
<li><strong>Usa imagenes Alpine</strong> - postgres:16-alpine es 70% mas pequena que la imagen estandar</li>
<li><strong>Habilita BuildKit</strong> - DOCKER_BUILDKIT=1 acelera builds con cache de capas</li>
<li><strong>Limita logs</strong> - Configura max-size y max-file en logging driver</li>
<li><strong>Monitoriza con cAdvisor</strong> - Metricas de contenedores en tiempo real</li>
<li><strong>Usa SSD pour volumenes</strong> - Minimo NVMe pour base de datos</li>
</ul>
</section>
<!-- Providers Section -->
<section id="proveedores" class="content-section fade-in">
<h2>Mejores Proveedores de Docker Hosting pour Odoo</h2>
<p>Elegir el proveedor correcto pour tu hosting Docker es crucial. Evaluamos los principales proveedores considerando precio, rendimiento, facilidad de uso y soporte pour contenedores.</p>
<div class="provider-grid">
<!-- DigitalOcean -->
<div class="provider-card featured">
<span class="badge">Mejor Calidad-Precio</span>
<h4>DigitalOcean</h4>
<p class="price">25EUR<span class="price-period">/mes</span></p>
<ul>
<li>Droplets optimizados pour Docker</li>
<li>App Platform con contenedores</li>
<li>Managed Kubernetes disponible</li>
<li>Backups automaticos incluidos</li>
<li>Excelente documentacion</li>
<li>Datacenter en Frankfurt</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
<!-- Hetzner -->
<div class="provider-card featured">
<span class="badge">Mejor Rendimiento/Precio</span>
<h4>Hetzner Cloud</h4>
<p class="price">15EUR<span class="price-period">/mes</span></p>
<ul>
<li>CPUs AMD EPYC dedicadas</li>
<li>NVMe SSD incluido</li>
<li>Docker preinstalado opcional</li>
<li>Firewall cloud gratuito</li>
<li>Datacenters en Alemania/Finlandia</li>
<li>IPv6 nativo</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
<!-- AWS -->
<div class="provider-card">
<span class="badge">Enterprise</span>
<h4>AWS ECS/Fargate</h4>
<p class="price">50EUR<span class="price-period">/mes min</span></p>
<ul>
<li>Orquestacion empresarial</li>
<li>Auto-scaling automatico</li>
<li>Integracion con servicios AWS</li>
<li>Fargate serverless</li>
<li>Multi-region</li>
<li>Cumplimiento ISO/SOC</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
<!-- Google Cloud -->
<div class="provider-card">
<h4>Google Cloud Run</h4>
<p class="price">35EUR<span class="price-period">/mes</span></p>
<ul>
<li>Contenedores serverless</li>
<li>Escala a cero automatico</li>
<li>HTTPS automatico</li>
<li>Integracion Cloud SQL</li>
<li>CI/CD con Cloud Build</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
<!-- Vultr -->
<div class="provider-card">
<h4>Vultr Kubernetes</h4>
<p class="price">20EUR<span class="price-period">/mes</span></p>
<ul>
<li>Kubernetes gestionado</li>
<li>High-frequency compute</li>
<li>Storage NVMe</li>
<li>32 datacenters globales</li>
<li>API completa</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
<!-- Contabo -->
<div class="provider-card">
<h4>Contabo VPS</h4>
<p class="price">12EUR<span class="price-period">/mes</span></p>
<ul>
<li>Mejor precio del mercado</li>
<li>Recursos generosos</li>
<li>Docker no gestionado</li>
<li>Ideal pour desarrollo</li>
<li>Soporte basico</li>
</ul>
<a href="#" class="cta-btn">Ver Planes</a>
</div>
</div>
</section>
<!-- Provider Comparison Chart -->
<section class="chart-section fade-in">
<h3>Compourtiva de Proveedores Docker: Radar de Caracteristicas</h3>
<p>Visualiza como se compourn los principales proveedores de Docker hosting en 6 dimensiones clave pour despliegues de Odoo.</p>
<div class="chart-container" id="radar-chart"></div>
</section>
<!-- Backup Section -->
<section id="backups" class="content-section fade-in">
<h2>Estrategias de Backup y Recuperacion</h2>
<p>Un plan de backup robusto es critico pour cualquier despliegue de Odoo en produccion. Con Docker, necesitamos respaldar tres componentes: la base de datos PostgreSQL, el filestore de Odoo y la configuracion.</p>
<h3>Script de Backup Automatizado</h3>
<div class="code-block" data-lang="bash">
<pre><span class="comment">#!/bin/bash</span>
<span class="comment"># backup-odoo.sh - Script de backup completo</span>
<span class="property">BACKUP_DIR</span>=<span class="string">"/backups/odoo/$(date +%Y-%m-%d)"</span>
<span class="property">RETENTION_DAYS</span>=<span class="number">30</span>
<span class="property">CONTAINER_DB</span>=<span class="string">"odoo_db_1"</span>
<span class="property">CONTAINER_ODOO</span>=<span class="string">"odoo_odoo_1"</span>
<span class="comment"># Crear directorio de backup</span>
<span class="keyword">mkdir</span> -p <span class="string">"$BACKUP_DIR"</span>
<span class="comment"># Backup de PostgreSQL</span>
<span class="keyword">echo</span> <span class="string">"[$(date)] Iniciando backup de PostgreSQL..."</span>
<span class="keyword">docker</span> exec <span class="string">$CONTAINER_DB</span> pg_dumpall -U odoo | \
gzip > <span class="string">"$BACKUP_DIR/postgres_full_$(date +%H%M).sql.gz"</span>
<span class="comment"># Backup del filestore</span>
<span class="keyword">echo</span> <span class="string">"[$(date)] Iniciando backup del filestore..."</span>
<span class="keyword">docker</span> run --rm \
-v odoo_odoo-data:/source:ro \
-v <span class="string">$BACKUP_DIR</span>:/backup \
alpine tar -czf /backup/filestore_$(date +%H%M).tar.gz -C /source .
<span class="comment"># Backup de configuracion</span>
<span class="keyword">echo</span> <span class="string">"[$(date)] Backup de configuracion..."</span>
<span class="keyword">cp</span> -r ./config <span class="string">"$BACKUP_DIR/config"</span>
<span class="keyword">cp</span> docker-compose.yml <span class="string">"$BACKUP_DIR/"</span>
<span class="comment"># Limpiar backups antiguos</span>
<span class="keyword">echo</span> <span class="string">"[$(date)] Limpiando backups mayores a $RETENTION_DAYS dias..."</span>
<span class="keyword">find</span> /backups/odoo -type d -mtime +<span class="string">$RETENTION_DAYS</span> -exec rm -rf {} +
<span class="comment"># Sincronizar a almacenamiento remoto (opcional)</span>
<span class="comment"># rclone sync $BACKUP_DIR remote:odoo-backups/$(date +%Y-%m-%d)</span>
<span class="keyword">echo</span> <span class="string">"[$(date)] Backup completado en $BACKUP_DIR"</span></pre>
</div>
<h3>Programar Backups con Cron</h3>
<div class="code-block" data-lang="cron">
<pre><span class="comment"># Editar crontab: crontab -e</span>
<span class="comment"># Backup diario a las 3:00 AM</span>
<span class="number">0</span> <span class="number">3</span> * * * /opt/scripts/backup-odoo.sh >> /var/log/odoo-backup.log <span class="number">2</span>>&<span class="number">1</span>
<span class="comment"># Backup incremental cada 6 horas</span>
<span class="number">0</span> */6 * * * /opt/scripts/backup-incremental.sh >> /var/log/odoo-backup.log <span class="number">2</span>>&<span class="number">1</span></pre>
</div>
<h3>Restauracion de Backup</h3>
<div class="code-block" data-lang="bash">
<pre><span class="comment">#!/bin/bash</span>
<span class="comment"># restore-odoo.sh - Script de restauracion</span>
<span class="property">BACKUP_DATE</span>=<span class="string">"$1"</span> <span class="comment"># Formato: 2026-01-25</span>
<span class="property">BACKUP_DIR</span>=<span class="string">"/backups/odoo/$BACKUP_DATE"</span>
<span class="comment"># Detener Odoo</span>
<span class="keyword">docker</span> compose stop odoo
<span class="comment"># Restaurar PostgreSQL</span>
<span class="keyword">gunzip</span> -c <span class="string">"$BACKUP_DIR/postgres_full_*.sql.gz"</span> | \
<span class="keyword">docker</span> exec -i odoo_db_1 psql -U odoo
<span class="comment"># Restaurar filestore</span>
<span class="keyword">docker</span> run --rm \
-v odoo_odoo-data:/target \
-v <span class="string">$BACKUP_DIR</span>:/backup:ro \
alpine sh -c <span class="string">"rm -rf /target/* && tar -xzf /backup/filestore_*.tar.gz -C /target"</span>
<span class="comment"># Reiniciar servicios</span>
<span class="keyword">docker</span> compose up -d
<span class="keyword">echo</span> <span class="string">"Restauracion completada desde $BACKUP_DATE"</span></pre>
</div>
<div class="highlight-box">
<h4>Regla 3-2-1 de Backups</h4>
<p><strong>3 copias</strong> de tus datos, en <strong>2 tipos</strong> de almacenamiento diferentes, con <strong>1 copia offsite</strong>. Ejemplo: disco local + NAS + cloud (S3/Backblaze).</p>
</div>
</section>
<!-- Security Section -->
<section id="seguridad" class="content-section fade-in">
<h2>Seguridad en Contenedores Odoo</h2>
<p>La seguridad en entornos Docker requiere atencion en multiples capas: imagen base, configuracion del contenedor, red y host. Estas son las mejores practicas pour asegurar tu Odoo containerizado.</p>
<h3>Checklist de Seguridad Docker</h3>
<ul class="step-list">
<li><strong>Usa imagenes oficiales</strong> - Solo odoo:18 o builds propios basados en oficial</li>
<li><strong>Escanea vulnerabilidades</strong> - Trivy o Snyk en CI/CD pipeline</li>
<li><strong>Usuario no-root</strong> - Configura USER en Dockerfile</li>
<li><strong>Read-only filesystem</strong> - Monta volumenes como :ro cuando sea posible</li>
<li><strong>Secrets management</strong> - Docker secrets o Vault, nunca env vars en compose</li>
<li><strong>Network isolation</strong> - Redes bridge personalizadas, nunca host mode</li>
<li><strong>Resource limits</strong> - Limita CPU y memoria pour prevenir DoS</li>
<li><strong>Actualizaciones regulares</strong> - Pull semanal de imagenes base</li>
</ul>
<h3>Configuracion de Firewall (UFW)</h3>
<div class="code-block" data-lang="bash">
<pre><span class="comment"># Configuracion basica de firewall pour Docker host</span>
<span class="keyword">ufw</span> default deny incoming
<span class="keyword">ufw</span> default allow outgoing
<span class="keyword">ufw</span> allow ssh
<span class="keyword">ufw</span> allow <span class="number">80</span>/tcp
<span class="keyword">ufw</span> allow <span class="number">443</span>/tcp
<span class="keyword">ufw</span> enable
<span class="comment"># Importante: Docker modifica iptables directamente</span>
<span class="comment"># Configura DOCKER_OPTS pour respetar UFW</span>
<span class="keyword">echo</span> <span class="string">'{"iptables": false}'</span> | sudo tee /etc/docker/daemon.json</pre>
</div>
</section>
<!-- Orchestration Comparison -->
<section class="chart-section fade-in">
<h3 id="orquestacion">Docker Swarm vs Kubernetes: Arbol de Decision</h3>
<p>Navega por este arbol interactivo pour determinar que orquestador es mejor pour tu caso de uso con Odoo.</p>
<div class="chart-container" id="decision-tree"></div>
</section>
<section class="content-section fade-in">
<h2>Orquestacion: Swarm vs Kubernetes</h2>
<p>Cuando tu despliegue de Odoo crece, necesitas orquestacion pour alta disponibilidad, balanceo de carga y actualizaciones sin downtime. Las dos opciones principales son Docker Swarm y Kubernetes.</p>
<h3>Docker Swarm</h3>
<p>Docker Swarm es la solucion de orquestacion nativa de Docker. Es mas simple de configurar y gestionar, ideal pour equipos pequenos o despliegues de tamano medio.</p>
<div class="code-block" data-lang="bash">
<pre><span class="comment"># Inicializar Swarm</span>
<span class="keyword">docker</span> swarm init --advertise-addr <span class="number">192.168.1.10</span>
<span class="comment"># Desplegar stack de Odoo</span>
<span class="keyword">docker</span> stack deploy -c docker-compose.prod.yml odoo
<span class="comment"># Escalar servicio</span>
<span class="keyword">docker</span> service scale odoo_odoo=<span class="number">3</span>
<span class="comment"># Rolling update</span>
<span class="keyword">docker</span> service update --image odoo:<span class="number">18.1</span> odoo_odoo</pre>
</div>
<h3>Kubernetes (K8s)</h3>
<p>Kubernetes es el estandar de la industria pour orquestacion de contenedores a gran escala. Ofrece mas funcionalidades pero con mayor complejidad operativa.</p>
<div class="comparison-table">
<table>
<thead>
<tr>
<th>Caracteristica</th>
<th>Docker Swarm</th>
<th>Kubernetes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Complejidad</td>
<td class="check">Baja</td>
<td class="cross">Alta</td>
</tr>
<tr>
<td>Curva aprendizaje</td>
<td class="check">Dias</td>
<td class="cross">Semanas/Meses</td>
</tr>
<tr>
<td>Escalabilidad</td>
<td>Hasta 1000 nodos</td>
<td class="check">5000+ nodos</td>
</tr>
<tr>
<td>Auto-healing</td>
<td class="check">Si</td>
<td class="check">Si (avanzado)</td>
</tr>
<tr>
<td>Rolling updates</td>
<td class="check">Si</td>
<td class="check">Si (con mas control)</td>
</tr>
<tr>
<td>Service mesh</td>
<td class="cross">Limitado</td>
<td class="check">Istio/Linkerd</td>
</tr>
<tr>
<td>Ecosistema</td>
<td>Docker nativo</td>
<td class="check">Muy amplio</td>
</tr>
<tr>
<td>Recommandé pour Odoo</td>
<td class="check">< 100 usuarios</td>
<td class="check">> 100 usuarios</td>
</tr>
</tbody>
</table>
</div>
<div class="highlight-box">
<h4>Nuestra Recomendacion</h4>
<p>Pour el 90% de despliegues de Odoo, <strong>Docker Swarm</strong> es suficiente y mucho mas facil de mantener. Solo considera Kubernetes si tienes mas de 100 usuarios concurrentes, necesitas multi-region activo-activo, o ya tienes infraestructura K8s existente.</p>
</div>
</section>
<!-- CTA Banner -->
<section class="cta-banner fade-in">
<h3>Despliega Odoo con Docker Facilmente</h3>
<p>Descarga nuestra plantilla Docker Compose optimizada pour produccion. Incluye Traefik, SSL automatico, backups y monitorizacion.</p>
<a href="#" class="cta-btn">Descargar Plantilla Gratis</a>
</section>
<!-- FAQ Section -->
<section id="faq" class="faq-section fade-in">
<h2>Preguntas Frecuentes sobre Odoo Docker</h2>
<div class="faq-item">
<div class="faq-question">Es Docker recomendable pour Odoo en produccion?</div>
<div class="faq-answer">Si, Docker es altamente recomendable pour Odoo en produccion en 2026. Ofrece aislamiento, reproducibilidad, escalabilidad horizontal y facilita los despliegues. Empresas como Amazon, Google y Microsoft utilizan contenedores en produccion. La clave esta en una correcta configuracion de volumenes persistentes, redes y orquestacion.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cuantos recursos necesita Odoo en Docker?</div>
<div class="faq-answer">Pour Odoo 18 en Docker se recomienda: 4GB RAM minimo (8GB recomendado), 2 CPU cores (4 recomendado), 40GB SSD pour volumenes. Docker anade aproximadamente un 2-5% de overhead compourdo con instalacion nativa, pero los beneficios de gestion superan ampliamente este coste.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como hago backup de Odoo en Docker?</div>
<div class="faq-answer">Pour backup de Odoo en Docker: 1) Backup de PostgreSQL con pg_dump desde el contenedor, 2) Backup del volumen filestore, 3) Backup de configuracion odoo.conf. Automatiza con cron jobs y docker exec. Recomendamos backups incrementales diarios y completos semanales con retencion de 30 dias.</div>
</div>
<div class="faq-item">
<div class="faq-question">Puedo usar Docker Compose pour multiples instancias de Odoo?</div>
<div class="faq-answer">Si, Docker Compose es ideal pour multi-tenant Odoo. Puedes definir multiples servicios Odoo en el mismo archivo compose, cada uno con su propia base de datos. Usa Traefik o Nginx como reverse proxy pour enrutar dominios a cada instancia. Esto es perfecto pour agencias que gestionan varios clientes.</div>
</div>
<div class="faq-item">
<div class="faq-question">Docker Swarm o Kubernetes pour Odoo?</div>
<div class="faq-answer">Pour la mayoria de despliegues Odoo, Docker Swarm es suficiente y mas simple de gestionar. Kubernetes es recomendable solo pour despliegues muy grandes (100+ usuarios concurrentes) o si ya tienes infraestructura K8s. Docker Swarm ofrece alta disponibilidad, balanceo de carga y escalado con menor complejidad operativa.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como actualizo Odoo en Docker sin downtime?</div>
<div class="faq-answer">Pour actualizar Odoo en Docker con minimo downtime: 1) Pull de la nueva imagen, 2) Backup completo, 3) Levantar nuevo contenedor en pourlelo, 4) Ejecutar migracion de base de datos, 5) Cambiar el proxy al nuevo contenedor, 6) Eliminar contenedor antiguo. Con Docker Swarm puedes hacer rolling updates automaticos.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cual es la mejor imagen Docker pour Odoo?</div>
<div class="faq-answer">La imagen oficial de Odoo (odoo:18) es la recomendada pour produccion. Esta optimizada, actualizada regularmente y soportada. Pour personalizaciones, crea tu propia imagen basada en la oficial con un Dockerfile. Evita imagenes de terceros no verificadas por razones de seguridad.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como configuro SSL/HTTPS pour Odoo en Docker?</div>
<div class="faq-answer">Pour SSL en Odoo Docker usa un reverse proxy: 1) Traefik con Let's Encrypt automatico (recomendado), 2) Nginx con Certbot, 3) Caddy con SSL automatico. El proxy maneja SSL y redirige al contenedor Odoo via HTTP interno. Nunca expongas Odoo directamente a internet sin SSL.</div>
</div>
</section>
<!-- Related Articles -->
<section id="relacionados" class="content-section fade-in">
<h2>Articles Connexes</h2>
<div class="related-articles">
<a href="/fr/odoo-hosting/mejor-hosting-odoo-2026/" class="related-card">
<div class="related-card-image">*</div>
<div class="related-card-content">
<h4>Mejor Hosting Odoo 2026</h4>
<p>Compourtiva completa de proveedores</p>
</div>
</a>
<a href="/fr/odoo-hosting/vps-hosting-odoo-servidor-virtual-2025/" class="related-card">
<div class="related-card-image">[VPS]</div>
<div class="related-card-content">
<h4>VPS pour Odoo: Guia Completa</h4>
<p>Configuracion de servidor virtual paso a paso</p>
</div>
</a>
<a href="/fr/odoo-hosting/requisitos-hosting-odoo-servidor-2025/" class="related-card">
<div class="related-card-image">[REQ]</div>
<div class="related-card-content">
<h4>Requisitos Tecnicos Odoo</h4>
<p>Especificaciones de hardware y software</p>
</div>
</a>
<a href="/fr/odoo-hosting/odoo-sh-hosting-oficial-plataforma-2025/" class="related-card">
<div class="related-card-image">[SH]</div>
<div class="related-card-content">
<h4>Odoo.sh: Plataforma Oficial</h4>
<p>Analisis completo de Odoo.sh</p>
</div>
</a>
<a href="/fr/odoo-hosting/hosting-odoo-gratis-gratuito-2025/" class="related-card">
<div class="related-card-image">[FREE]</div>
<div class="related-card-content">
<h4>Hosting Odoo Gratis</h4>
<p>Opciones gratuitas pour comenzar</p>
</div>
</a>
<a href="/fr/odoo-hosting/precios-hosting-odoo-costos-2025/" class="related-card">
<div class="related-card-image">[EUR]</div>
<div class="related-card-content">
<h4>Precios Hosting Odoo</h4>
<p>Compourtiva detallada de costos</p>
</div>
</a>
</div>
</section>
</main>
<!-- EEAT Author Section -->
<div id="eeat-section"></div>
<div id="footer"><footer class="site-footer"><div class="container"><div class="footer-cols"><div><strong>Odoo Expertos</strong></div><nav class="footer-nav"><a href="/fr/">Accueil</a><a href="/fr/odoo/">Odoo</a><a href="/fr/odoo-ia/">Odoo IA</a><a href="/fr/odoo-hosting/">Hebergement Odoo</a><a href="/fr/mapa-del-sitio/">Plan du Site</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div><nav class="footer-nav"><a href="/fr/">Accueil</a><a href="/fr/odoo/">Odoo</a><a href="/fr/odoo-ia/">Odoo IA</a><a href="/fr/odoo-hosting/">Hebergement Odoo</a><a href="/fr/mapa-del-sitio/">Plan du Site</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div>
<!-- Scripts -->
<script src="/js/language-router.js"></script>
<script src="/components/header.min.js"></script>
<script src="/components/footer.min.js"></script>
<script src="/components/eeat.min.js"></script>
<script src="/js/cookie-banner.min.js"></script>
<!-- D3.js -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script>
// Initialize components
// Scroll animation observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.fade-in').forEach(el => observer.observe(el));
// FAQ Toggle
document.querySelectorAll('.faq-question').forEach(question => {
question.addEventListener('click', () => {
const item = question.parentElement;
item.classList.toggle('open');
});
});
// Tooltip
const tooltip = d3.select('body').append('div')
.attr('class', 'd3-tooltip')
.style('opacity', 0);
// Color scales
const blueScale = d3.scaleOrdinal()
.range(['#2196F3', '#64B5F6', '#90CAF9', '#42A5F5', '#1E88E5', '#1565C0']);
const colorScale = d3.scaleOrdinal()
.range(['#2196F3', '#4CAF50', '#FF9800', '#9C27B0', '#00BCD4', '#E91E63']);
// Architecture Diagram
function renderArchitectureDiagram() {
const container = d3.select('#architecture-diagram');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 450;
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
// Architecture components
const components = [
{ id: 'internet', label: 'Internet', x: width/2, y: 40, type: 'external', desc: 'Trafico de usuarios y APIs externas' },
{ id: 'traefik', label: 'Traefik/Nginx', x: width/2, y: 120, type: 'proxy', desc: 'Reverse proxy con SSL/TLS, balanceo de carga' },
{ id: 'odoo1', label: 'Odoo Container 1', x: width/3, y: 220, type: 'app', desc: 'Instancia Odoo con workers configurados' },
{ id: 'odoo2', label: 'Odoo Container 2', x: 2*width/3, y: 220, type: 'app', desc: 'Replica pour alta disponibilidad' },
{ id: 'postgres', label: 'PostgreSQL', x: width/3, y: 330, type: 'db', desc: 'Base de datos con volumenes persistentes' },
{ id: 'redis', label: 'Redis Cache', x: 2*width/3, y: 330, type: 'cache', desc: 'Cache de sesiones y cola de trabajos' },
{ id: 'volumes', label: 'Docker Volumes', x: width/2, y: 410, type: 'storage', desc: 'Filestore y datos persistentes' }
];
const connections = [
{ from: 'internet', to: 'traefik' },
{ from: 'traefik', to: 'odoo1' },
{ from: 'traefik', to: 'odoo2' },
{ from: 'odoo1', to: 'postgres' },
{ from: 'odoo2', to: 'postgres' },
{ from: 'odoo1', to: 'redis' },
{ from: 'odoo2', to: 'redis' },
{ from: 'postgres', to: 'volumes' },
{ from: 'odoo1', to: 'volumes' },
{ from: 'odoo2', to: 'volumes' }
];
// Draw connections
connections.forEach((conn, i) => {
const from = components.find(c => c.id === conn.from);
const to = components.find(c => c.id === conn.to);
svg.append('line')
.attr('x1', from.x)
.attr('y1', from.y + 20)
.attr('x2', to.x)
.attr('y2', to.y - 20)
.attr('stroke', '#444')
.attr('stroke-width', 2)
.attr('stroke-dasharray', '5,5')
.attr('opacity', 0)
.transition()
.duration(500)
.delay(i * 50)
.attr('opacity', 0.7);
});
// Color by type
const typeColors = {
external: '#9E9E9E',
proxy: '#2196F3',
app: '#4CAF50',
db: '#FF9800',
cache: '#E91E63',
storage: '#9C27B0'
};
// Draw components
components.forEach((comp, i) => {
const g = svg.append('g')
.attr('transform', `translate(${comp.x}, ${comp.y})`)
.style('cursor', 'pointer')
.style('opacity', 0);
// Rectangle
g.append('rect')
.attr('x', -70)
.attr('y', -20)
.attr('width', 140)
.attr('height', 40)
.attr('rx', 8)
.attr('fill', typeColors[comp.type])
.attr('fill-opacity', 0.2)
.attr('stroke', typeColors[comp.type])
.attr('stroke-width', 2);
// Label
g.append('text')
.attr('text-anchor', 'middle')
.attr('dy', 5)
.attr('fill', '#e0e0e0')
.attr('font-size', '12px')
.attr('font-weight', '500')
.text(comp.label);
// Icon based on type
const icons = {
external: 'WWW',
proxy: 'LB',
app: 'APP',
db: 'DB',
cache: '$',
storage: 'VOL'
};
g.append('text')
.attr('x', -55)
.attr('dy', 5)
.attr('fill', typeColors[comp.type])
.attr('font-size', '10px')
.attr('font-family', 'monospace')
.text(icons[comp.type]);
// Hover effects
g.on('mouseover', function(event) {
d3.select(this).select('rect')
.attr('fill-opacity', 0.4)
.attr('stroke-width', 3);
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${comp.label}</strong><br>${comp.desc}`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).select('rect')
.attr('fill-opacity', 0.2)
.attr('stroke-width', 2);
tooltip.transition().duration(200).style('opacity', 0);
});
g.transition()
.duration(500)
.delay(i * 100)
.style('opacity', 1);
});
// Legend
const legend = svg.append('g')
.attr('transform', `translate(20, 20)`);
Object.entries(typeColors).forEach(([type, color], i) => {
const labels = {
external: 'Externo',
proxy: 'Proxy',
app: 'Aplicacion',
db: 'Base Datos',
cache: 'Cache',
storage: 'Almacenamiento'
};
const g = legend.append('g')
.attr('transform', `translate(0, ${i * 22})`);
g.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('fill', color)
.attr('rx', 3);
g.append('text')
.attr('x', 22)
.attr('y', 12)
.attr('fill', '#888')
.attr('font-size', '11px')
.text(labels[type]);
});
}
// Performance Comparison Chart
function renderPerformanceChart() {
const container = d3.select('#performance-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = { top: 40, right: 30, bottom: 80, left: 60 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
const data = [
{ category: 'Bare Metal', docker: 0, native: 100, vm: 0 },
{ category: 'Docker', docker: 97, native: 0, vm: 0 },
{ category: 'Docker Swarm', docker: 95, native: 0, vm: 0 },
{ category: 'Kubernetes', docker: 93, native: 0, vm: 0 },
{ category: 'VM (KVM)', docker: 0, native: 0, vm: 85 },
{ category: 'VM (VMware)', docker: 0, native: 0, vm: 82 }
];
const categories = data.map(d => d.category);
const metrics = ['native', 'docker', 'vm'];
const metricLabels = { native: 'Nativo', docker: 'Docker', vm: 'Maquina Virtual' };
const metricColors = { native: '#4CAF50', docker: '#2196F3', vm: '#FF9800' };
const xScale = d3.scaleBand()
.domain(categories)
.range([margin.left, width - margin.right])
.padding(0.3);
const yScale = d3.scaleLinear()
.domain([0, 105])
.range([height - margin.bottom, margin.top]);
// Grid
svg.append('g')
.attr('class', 'grid')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale).tickSize(-(width - margin.left - margin.right)).tickFormat(''))
.selectAll('line').attr('stroke', '#333');
// X axis
svg.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale))
.selectAll('text')
.attr('fill', '#888')
.attr('transform', 'rotate(-25)')
.attr('text-anchor', 'end');
// Y axis
svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale).tickFormat(d => d + '%'))
.attr('color', '#888');
// Y label
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -height / 2)
.attr('y', 15)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '12px')
.text('Rendimiento Relativo (%)');
// Bars
data.forEach((d, i) => {
metrics.forEach((metric) => {
if (d[metric] > 0) {
const bar = svg.append('rect')
.attr('x', xScale(d.category))
.attr('y', yScale(0))
.attr('width', xScale.bandwidth())
.attr('height', 0)
.attr('fill', metricColors[metric])
.attr('rx', 4)
.style('cursor', 'pointer');
bar.on('mouseover', function(event) {
d3.select(this).attr('fill-opacity', 0.8);
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${d.category}</strong><br>Rendimiento: ${d[metric]}%`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).attr('fill-opacity', 1);
tooltip.transition().duration(200).style('opacity', 0);
});
bar.transition()
.duration(800)
.delay(i * 100)
.attr('y', yScale(d[metric]))
.attr('height', yScale(0) - yScale(d[metric]));
// Value label
svg.append('text')
.attr('x', xScale(d.category) + xScale.bandwidth() / 2)
.attr('y', yScale(d[metric]) - 8)
.attr('text-anchor', 'middle')
.attr('fill', '#e0e0e0')
.attr('font-size', '12px')
.attr('font-weight', '600')
.attr('opacity', 0)
.text(d[metric] + '%')
.transition()
.duration(500)
.delay(i * 100 + 400)
.attr('opacity', 1);
}
});
});
// Legend
const legend = svg.append('g')
.attr('transform', `translate(${width - 150}, 30)`);
Object.entries(metricLabels).forEach(([key, label], i) => {
const g = legend.append('g')
.attr('transform', `translate(0, ${i * 22})`);
g.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('fill', metricColors[key])
.attr('rx', 3);
g.append('text')
.attr('x', 22)
.attr('y', 12)
.attr('fill', '#b0b0b0')
.attr('font-size', '12px')
.text(label);
});
}
// Radar Chart for Provider Comparison
function renderRadarChart() {
const container = d3.select('#radar-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = 100;
const radius = Math.min(width, height) / 2 - margin;
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width/2},${height/2})`);
const categories = ['Docker Support', 'Precio', 'Rendimiento', 'Escalabilidad', 'Soporte', 'Facilidad'];
const angleSlice = Math.PI * 2 / categories.length;
const providers = [
{ name: 'DigitalOcean', values: [95, 80, 85, 90, 85, 95], color: '#2196F3' },
{ name: 'Hetzner', values: [85, 95, 92, 80, 65, 75], color: '#4CAF50' },
{ name: 'AWS ECS', values: [100, 50, 90, 100, 90, 60], color: '#FF9800' },
{ name: 'Google Cloud', values: [95, 60, 88, 95, 85, 70], color: '#9C27B0' }
];
const rScale = d3.scaleLinear()
.domain([0, 100])
.range([0, radius]);
// Grid circles
const levels = 5;
for (let i = 1; i <= levels; i++) {
svg.append('circle')
.attr('r', radius * i / levels)
.attr('fill', 'none')
.attr('stroke', '#3a3a3a')
.attr('stroke-dasharray', '4,4');
svg.append('text')
.attr('x', 5)
.attr('y', -radius * i / levels)
.attr('fill', '#666')
.attr('font-size', '10px')
.text(i * 20);
}
// Axis lines and labels
categories.forEach((cat, i) => {
const angle = angleSlice * i - Math.PI / 2;
svg.append('line')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', radius * Math.cos(angle))
.attr('y2', radius * Math.sin(angle))
.attr('stroke', '#444');
const labelRadius = radius + 25;
svg.append('text')
.attr('x', labelRadius * Math.cos(angle))
.attr('y', labelRadius * Math.sin(angle))
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.attr('fill', '#b0b0b0')
.attr('font-size', '11px')
.text(cat);
});
// Radar areas
const radarLine = d3.lineRadial()
.radius(d => rScale(d))
.angle((d, i) => angleSlice * i)
.curve(d3.curveLinearClosed);
providers.forEach((provider, idx) => {
const path = svg.append('path')
.datum(provider.values)
.attr('d', radarLine)
.attr('fill', provider.color)
.attr('fill-opacity', 0)
.attr('stroke', provider.color)
.attr('stroke-width', 2)
.attr('stroke-opacity', 0);
path.transition()
.duration(800)
.delay(idx * 200)
.attr('fill-opacity', 0.15)
.attr('stroke-opacity', 1);
// Data points
provider.values.forEach((val, i) => {
const angle = angleSlice * i - Math.PI / 2;
svg.append('circle')
.attr('cx', rScale(val) * Math.cos(angle))
.attr('cy', rScale(val) * Math.sin(angle))
.attr('r', 0)
.attr('fill', provider.color)
.transition()
.duration(500)
.delay(idx * 200 + i * 50)
.attr('r', 4);
});
});
// Legend
const legendX = width > 600 ? radius + 50 : -radius;
const legendY = width > 600 ? -radius + 20 : radius + 30;
providers.forEach((provider, idx) => {
const g = svg.append('g')
.attr('transform', `translate(${legendX}, ${legendY + idx * 25})`);
g.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('fill', provider.color)
.attr('rx', 3);
g.append('text')
.attr('x', 22)
.attr('y', 12)
.attr('fill', '#b0b0b0')
.attr('font-size', '12px')
.text(provider.name);
});
}
// Decision Tree
function renderDecisionTree() {
const container = d3.select('#decision-tree');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 500;
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
const g = svg.append('g')
.attr('transform', `translate(50,30)`);
const treeData = {
name: 'Usuarios concurrentes?',
description: 'Cuantos usuarios acceden simultaneamente',
children: [
{
name: '< 50 usuarios',
description: 'Pequena/mediana empresa',
children: [
{
name: 'Equipo DevOps?',
children: [
{ name: 'Si', children: [
{ name: 'Docker Compose', description: 'Simple, efectivo, facil de mantener' }
]},
{ name: 'No', children: [
{ name: 'Hosting Gestionado', description: 'Odoo4projects o similar' }
]}
]
}
]
},
{
name: '50-200 usuarios',
description: 'Empresa mediana',
children: [
{
name: 'Alta disponibilidad?',
children: [
{ name: 'Si', children: [
{ name: 'Docker Swarm', description: 'HA simple, rolling updates' }
]},
{ name: 'No', children: [
{ name: 'Docker + Replicas', description: 'Compose con multiples instancias' }
]}
]
}
]
},
{
name: '> 200 usuarios',
description: 'Gran empresa',
children: [
{ name: 'Kubernetes', description: 'Escalabilidad maxima, service mesh' }
]
}
]
};
const treeLayout = d3.tree()
.size([width - 100, height - 80]);
const root = d3.hierarchy(treeData);
treeLayout(root);
// Links
g.selectAll('.link')
.data(root.links())
.join('path')
.attr('class', 'link')
.attr('d', d3.linkVertical()
.x(d => d.x)
.y(d => d.y))
.attr('fill', 'none')
.attr('stroke', '#555')
.attr('stroke-width', 2)
.attr('stroke-dasharray', function() {
return this.getTotalLength();
})
.attr('stroke-dashoffset', function() {
return this.getTotalLength();
})
.transition()
.duration(1200)
.attr('stroke-dashoffset', 0);
// Nodes
const nodes = g.selectAll('.node')
.data(root.descendants())
.join('g')
.attr('class', 'node')
.attr('transform', d => `translate(${d.x},${d.y})`)
.style('opacity', 0)
.style('cursor', 'pointer');
nodes.append('circle')
.attr('r', d => d.children ? 10 : 8)
.attr('fill', d => d.children ? '#2196F3' : '#4CAF50')
.attr('stroke', '#fff')
.attr('stroke-width', 2);
nodes.append('text')
.attr('dy', d => d.children ? -18 : 25)
.attr('text-anchor', 'middle')
.attr('fill', '#e0e0e0')
.attr('font-size', d => d.depth === 0 ? '13px' : '11px')
.attr('font-weight', d => d.depth === 0 ? '600' : '400')
.text(d => d.data.name);
nodes.on('mouseover', function(event, d) {
d3.select(this).select('circle').attr('r', d.children ? 14 : 12);
if (d.data.description) {
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${d.data.name}</strong><br>${d.data.description}`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
}
})
.on('mouseout', function(event, d) {
d3.select(this).select('circle').attr('r', d.children ? 10 : 8);
tooltip.transition().duration(200).style('opacity', 0);
});
nodes.transition()
.duration(500)
.delay((d, i) => i * 80)
.style('opacity', 1);
}
// Initialize charts when visible
const chartObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.id;
setTimeout(() => {
if (id === 'architecture-diagram') renderArchitectureDiagram();
if (id === 'performance-chart') renderPerformanceChart();
if (id === 'radar-chart') renderRadarChart();
if (id === 'decision-tree') renderDecisionTree();
}, 100);
chartObserver.unobserve(entry.target);
}
});
}, { threshold: 0.15 });
document.querySelectorAll('.chart-container').forEach(el => chartObserver.observe(el));
// Resize handler
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
renderArchitectureDiagram();
renderPerformanceChart();
renderRadarChart();
renderDecisionTree();
}, 300);
});
</script>
</body>
</html>