Files
2026-08-28 10:11:11 -03:00

2153 lines
93 KiB
HTML

<!DOCTYPE html>
<html lang="pt-BR">
<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 Kubernetes Hosting 2026 | Odoo Expertos · PT</title>
<meta name="description" content="Guia definitiva para desplegar Odoo en Kubernetes en 2026. Helm charts, estrategias de deployment, proveedores cloud con K8s gest - Odoo Kubernetes Hosting 2026 | PT">
<meta name="keywords" content="odoo kubernetes, odoo k8s, odoo helm chart, kubernetes odoo deployment, odoo docker kubernetes, odoo gke, odoo eks, odoo aks, odoo cloud native">
<meta name="author" content="Dra. Equipo Odoo Expertos">
<meta name="robots" content="index, follow">
<meta name="language" content="pt-BR">
<link rel="canonical" href="https://www.odoo-expertos.com/pt/odoo-hosting/odoo-kubernetes-hosting-2026/">
<!-- Hreflang -->
<link rel="alternate" hreflang="pt-BR" href="https://www.odoo-expertos.com/pt/odoo-hosting/odoo-kubernetes-hosting-2026/" />
<link rel="alternate" hreflang="en" href="https://www.odoo-expertos.com/en/odoo-hosting/odoo-kubernetes-hosting-2026/" />
<link rel="alternate" hreflang="de" href="https://www.odoo-expertos.com/de/odoo-hosting/odoo-kubernetes-hosting-2026/" />
<link rel="alternate" hreflang="fr" href="https://www.odoo-expertos.com/fr/odoo-hosting/odoo-kubernetes-hosting-2026/" />
<link rel="alternate" hreflang="x-default" href="https://www.odoo-expertos.com/odoo-hosting/odoo-kubernetes-hosting-2026/" />
<!-- Open Graph -->
<meta property="og:title" content="Odoo en Kubernetes 2026: Guia Completa de Despliegue y Hosting K8s">
<meta property="og:description" content="Guia definitiva para desplegar Odoo en Kubernetes. Helm charts, estrategias de deployment, proveedores cloud con K8s gestionado.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.odoo-expertos.com/pt/odoo-hosting/odoo-kubernetes-hosting-2026/">
<meta property="og:image" content="https://www.odoo-expertos.com/images/odoo-kubernetes-hosting-2026.jpg">
<meta property="og:site_name" content="Odoo Expertos">
<meta property="og:locale" content="pt_BR">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Odoo en Kubernetes 2026: Guia Completa de Despliegue">
<meta name="twitter:description" content="Guia definitiva para desplegar Odoo en Kubernetes. Helm charts y proveedores cloud.">
<!-- Schema.org Article -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Odoo en Kubernetes 2026: Guia Completa de Despliegue y Hosting K8s",
"description": "Guia definitiva para desplegar Odoo en Kubernetes en 2026. Helm charts, estrategias de deployment, proveedores cloud con K8s gestionado.",
"author": {
"@type": "Person",
"name": "Dra. Equipo Odoo Expertos",
"url": "https://www.odoo-expertos.com/autor/maria-elena-rodriguez/",
"jobTitle": "Consultora Senior en Sistemas ERP y Cloud Architecture"
},
"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/odoo-hosting/odoo-kubernetes-hosting-2026/"
}
}
</script>
<!-- FAQ Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Cuando tiene sentido usar Kubernetes para Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Kubernetes es recomendable para Odoo cuando necesitas alta disponibilidad (99.99%+), escalabilidad automatica para picos de demanda, multiples entornos (dev/staging/prod), integracion con CI/CD avanzado, o cuando manejas mas de 100 usuarios concurrentes. Para PYMEs con menos de 50 usuarios, un VPS gestionado suele ser mas cost-effective."
}
},
{
"@type": "Question",
"name": "Cual es el mejor proveedor cloud para Odoo en Kubernetes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Para empresas en Europa, Google GKE ofrece la mejor relacion precio/rendimiento con Autopilot. AWS EKS es ideal si ya usas servicios AWS. Azure AKS es la opcion preferida para empresas con infraestructura Microsoft. DigitalOcean DOKS es excelente para presupuestos ajustados con simplicidad."
}
},
{
"@type": "Question",
"name": "Existe un Helm chart oficial para Odoo?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Não existe un Helm chart oficial de Odoo S.A. Simn embargo, Bitnami mantiene el chart mas popular y estable (bitnami/odoo), actualizado regularmente con cada version de Odoo. Tambien existen charts comunitarios en ArtifactHub con configuraciones especializadas."
}
},
{
"@type": "Question",
"name": "Cuanto cuesta ejecutar Odoo en Kubernetes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "El costo minimo viable es aproximadamente 150-200 EUR/mes para un cluster basico (3 nodos, 2vCPU, 4GB cada uno) mas almacenamiento y networking. Para produccion con alta disponibilidad, el costo tipico es 400-800 EUR/mes. Los costos pueden reducirse significativamente con nodos spot/preemptibles."
}
},
{
"@type": "Question",
"name": "Como manejo los volumenes persistentes de Odoo en K8s?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Odoo requiere almacenamiento persistente para el filestore y la base de datos PostgreSQL. Usa PersistentVolumeClaims con StorageClass que soporte ReadWriteMany (como NFS, EFS, o Filestore) para el filestore si necesitas multiples replicas. Para PostgreSQL, usa operadores como CloudNativePG o servicios gestionados (Cloud SQL, RDS)."
}
},
{
"@type": "Question",
"name": "Puedo escalar Odoo horizontalmente en Kubernetes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Sim, pero con consideraciones. Odoo puede escalar horizontalmente los workers de Odoo si configuras correctamente: sesiones en Redis/Memcached, filestore compartido (NFS/S3), y PostgreSQL con suficiente capacidad. El escalado horizontal tipico es 2-10 pods de Odoo apuntando a una base de datos PostgreSQL con alta disponibilidad."
}
},
{
"@type": "Question",
"name": "Que estrategia de deployment es mejor para Odoo en K8s?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Para actualizaciones de Odoo, recomendamos Blue-Green deployment por su capacidad de rollback instantaneo. Rolling updates funcionan para cambios menores de codigo. Canary deployments son utiles para probar nuevos modulos con un porcentaje de trafico. Simempre haz backup de la base de datos antes de cualquier actualizacion."
}
},
{
"@type": "Question",
"name": "Como configuro HTTPS/SSL para Odoo en Kubernetes?",
"acceptedAnswer": {
"@type": "Answer",
"text": "La forma mas comun es usar un Ingress Controller (nginx-ingress o traefik) combinado con cert-manager para certificados automaticos de Let's Encrypt. Configura annotations en el Ingress para SSL redirect y HSTS. Para produccion enterprise, considera certificados wildcard o de organizacion."
}
}
]
}
</script>
<!-- HowTo Schema -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Como desplegar Odoo en Kubernetes con Helm",
"description": "Guia paso a paso para instalar Odoo en un cluster de Kubernetes usando Helm charts",
"step": [
{
"@type": "HowToStep",
"name": "Preparar el cluster",
"text": "Asegurate de tener un cluster Kubernetes funcionando con kubectl configurado y Helm 3 instalado"
},
{
"@type": "HowToStep",
"name": "Agregar repositorio Bitnami",
"text": "Ejecuta: helm repo add bitnami https://charts.bitnami.com/bitnami && helm repo update"
},
{
"@type": "HowToStep",
"name": "Crear archivo de valores",
"text": "Crea un archivo values.yaml con la configuracion personalizada de recursos, persistencia y PostgreSQL"
},
{
"@type": "HowToStep",
"name": "Instalar Odoo",
"text": "Ejecuta: helm install odoo bitnami/odoo -f values.yaml -n odoo --create-namespace"
},
{
"@type": "HowToStep",
"name": "Configurar Ingress",
"text": "Aplica un recurso Ingress para exponer Odoo con SSL/TLS usando cert-manager"
}
]
}
</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/pt/odoo-hosting/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Odoo Kubernetes Hosting 2026",
"item": "https://www.odoo-expertos.com/pt/odoo-hosting/odoo-kubernetes-hosting-2026/"
}
]
}
</script>
<link rel="stylesheet" href="/css/main.min.css">
<style>
.pillar-hero {
background: linear-gradient(135deg, #0d1b2a 0%, #1b263b 50%, #0d1b2a 100%);
padding: 4rem 2rem;
text-align: center;
border-bottom: 3px solid #326ce5;
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(50,108,229,0.15) 0%, transparent 70%);
pointer-events: none;
}
.pillar-hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
color: #326ce5;
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: #1b263b;
border-radius: 12px;
margin: 2rem 0;
}
.stat-card {
text-align: center;
padding: 1.5rem;
background: rgba(50,108,229,0.1);
border-radius: 8px;
border: 1px solid rgba(50,108,229,0.2);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
border-color: #326ce5;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: #326ce5;
display: block;
}
.stat-label {
color: #b0b0b0;
font-size: 0.9rem;
margin-top: 0.5rem;
}
.toc {
background: #1b263b;
border: 2px solid #326ce5;
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
}
.toc h2 {
color: #326ce5;
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: #326ce5;
}
.toc-list a::before {
content: '>';
color: #326ce5;
font-family: monospace;
}
.content-section {
margin: 3rem 0;
}
.content-section h2 {
color: #5b9cf4;
margin-bottom: 1.5rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid rgba(50,108,229,0.3);
}
.content-section h3 {
color: #7cb3f7;
margin: 2rem 0 1rem;
}
.chart-section {
margin: 3rem 0;
padding: 2rem;
background: #1b263b;
border-radius: 12px;
}
.chart-section h3 {
color: #5b9cf4;
margin-bottom: 1rem;
}
.chart-container {
width: 100%;
min-height: 450px;
position: relative;
}
.comparison-table {
width: 100%;
border-collapse: collapse;
margin: 2rem 0;
background: #1b263b;
border-radius: 12px;
overflow: hidden;
}
.comparison-table th,
.comparison-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid #2a3f5f;
}
.comparison-table th {
background: rgba(50,108,229,0.2);
color: #326ce5;
font-weight: 600;
}
.comparison-table tr:hover {
background: rgba(50,108,229,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: #1b263b;
border-radius: 12px;
padding: 1.5rem;
border: 1px solid rgba(50,108,229,0.2);
transition: transform 0.3s ease, border-color 0.3s ease;
}
.provider-card:hover {
transform: translateY(-5px);
border-color: #326ce5;
}
.provider-card.featured {
border-color: #326ce5;
background: linear-gradient(135deg, rgba(50,108,229,0.15) 0%, #1b263b 100%);
position: relative;
}
.provider-card .badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #326ce5;
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: #326ce5;
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 #2a3f5f;
display: flex;
align-items: center;
gap: 0.5rem;
color: #b0b0b0;
}
.provider-card li::before {
content: '>';
color: #4CAF50;
font-family: monospace;
font-weight: bold;
}
.provider-card .cta-btn {
display: block;
text-align: center;
padding: 0.75rem 1.5rem;
background: #326ce5;
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: #5b9cf4;
transform: scale(1.02);
}
.code-block {
background: #0d1b2a;
border: 1px solid #2a3f5f;
border-radius: 8px;
padding: 1.5rem;
overflow-x: auto;
margin: 1.5rem 0;
font-family: 'Monaco', 'Consolas', monospace;
font-size: 0.9rem;
line-height: 1.6;
}
.code-block code {
color: #e0e0e0;
}
.code-block .comment {
color: #6a9955;
}
.code-block .keyword {
color: #569cd6;
}
.code-block .string {
color: #ce9178;
}
.code-block .number {
color: #b5cea8;
}
.faq-section {
margin: 3rem 0;
}
.faq-item {
background: #1b263b;
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(50,108,229,0.1);
}
.faq-question::after {
content: '+';
font-size: 1.5rem;
color: #326ce5;
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(50,108,229,0.2) 0%, rgba(91,156,244,0.1) 100%);
border: 2px solid rgba(50,108,229,0.5);
border-radius: 12px;
padding: 2.5rem;
text-align: center;
margin: 3rem 0;
}
.cta-banner h3 {
color: #326ce5;
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: #326ce5;
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: #5b9cf4;
transform: scale(1.05);
}
.highlight-box {
background: linear-gradient(135deg, rgba(50,108,229,0.1) 0%, rgba(91,156,244,0.05) 100%);
border-left: 4px solid #326ce5;
padding: 1.5rem;
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.highlight-box h4 {
color: #326ce5;
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;
font-family: monospace;
}
.cons li::before {
content: 'x ';
color: #f44336;
font-family: monospace;
}
.related-articles {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.related-card {
background: #1b263b;
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(50,108,229,0.3), rgba(91,156,244,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(13,27,42,0.98);
color: #fff;
padding: 0.75rem 1rem;
border-radius: 8px;
font-size: 0.9rem;
pointer-events: none;
z-index: 100;
max-width: 300px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
border: 1px solid rgba(50,108,229,0.3);
}
.d3-tooltip strong {
color: #326ce5;
}
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
.k8s-icon {
display: inline-block;
width: 24px;
height: 24px;
background: #326ce5;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
.architecture-legend {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 1rem;
justify-content: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.85rem;
color: #b0b0b0;
}
.legend-color {
width: 16px;
height: 16px;
border-radius: 4px;
}
@media (max-width: 768px) {
.toc-list {
columns: 1;
}
.pillar-meta {
flex-direction: column;
gap: 0.5rem;
}
.chart-container {
min-height: 350px;
}
.pros-cons {
grid-template-columns: 1fr;
}
.provider-grid {
grid-template-columns: 1fr;
}
.code-block {
font-size: 0.8rem;
padding: 1rem;
}
}
</style>
</head>
<body>
<div id="header"><header class="site-header"><nav class="navbar"><div class="container"><div class="nav-brand"><a href="/pt/" 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="/pt/">Inicio</a></li><li><a href="/pt/odoo/">Odoo</a></li><li><a href="/pt/odoo-ia/">Odoo IA</a></li><li><a href="/pt/odoo-hosting/">Hospedagem Odoo</a></li><li><a href="/pt/mapa-del-sitio/">Mapa do 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="/pt/">Inicio</a></li><li><a href="/pt/odoo/">Odoo</a></li><li><a href="/pt/odoo-ia/">Odoo IA</a></li><li><a href="/pt/odoo-hosting/">Hospedagem Odoo</a></li><li><a href="/pt/mapa-del-sitio/">Mapa do 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">Inicio</span></a>
<span itemprop="position" style="display:none">1</span>
</li>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a itemprop="item" href="/pt/odoo-hosting/"><span itemprop="name">Hosting 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 Kubernetes 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 en Kubernetes 2026: Guia Completa de Despliegue y Hosting K8s</h1>
<p class="pillar-subtitle">Domina el despliegue de Odoo en Kubernetes. Desde conceptos basicos hasta arquitecturas de alta disponibilidad con escalado automatico, Helm charts y mejores practicas para produccion.</p>
<div class="pillar-meta">
<span>Publicado: 25 enero 2026</span>
<span>Actualizado: 25 enero 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">99.99%</span>
<span class="stat-label">Uptime Alcanzable</span>
</div>
<div class="stat-card">
<span class="stat-number">4</span>
<span class="stat-label">Proveedores K8s Analizados</span>
</div>
<div class="stat-card">
<span class="stat-number">150EUR</span>
<span class="stat-label">Costo Minimo/Mes</span>
</div>
<div class="stat-card">
<span class="stat-number">10x</span>
<span class="stat-label">Escalabilidad Potencial</span>
</div>
<div class="stat-card">
<span class="stat-number">3</span>
<span class="stat-label">Estrategias de Deploy</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">Introduccion: Por que Kubernetes para Odoo</a></li>
<li><a href="#cuando-k8s">Cuando Tiene Sentido Usar K8s</a></li>
<li><a href="#arquitectura">Arquitectura de Odoo en Kubernetes</a></li>
<li><a href="#helm-charts">Helm Charts para Odoo</a></li>
<li><a href="#estrategias-deployment">Estrategias de Deployment</a></li>
<li><a href="#proveedores-cloud">Proveedores Cloud con K8s Gestionado</a></li>
<li><a href="#configuracion-produccion">Configuracion para Produccion</a></li>
<li><a href="#escalabilidad">Escalabilidad y Alta Disponibilidad</a></li>
<li><a href="#costos">Analisis de Costos</a></li>
<li><a href="#faq">Preguntas Frecuentes (8+)</a></li>
</ol>
</nav>
<!-- Introduction -->
<section id="introduccion" class="content-section fade-in">
<h2>Introduccion: Por que Kubernetes para Odoo en 2026</h2>
<p>Kubernetes se ha consolidado como el estandar de facto para la orquestacion de contenedores en entornos empresariales. Para Odoo, esto representa una oportunidad unica de lograr niveles de disponibilidad, escalabilidad y automatizacion que eran impensables hace pocos anos. Sin embargo, no todas las implementaciones de Odoo se benefician de la complejidad adicional que Kubernetes introduce.</p>
<p>En esta guia exhaustiva, analizaremos cuando tiene sentido migrar tu instalacion de Odoo a Kubernetes, como disenar una arquitectura robusta, que herramientas utilizar (Helm charts, operadores), y como elegir entre los principales proveedores de Kubernetes gestionado. Tambien cubriremos estrategias de deployment, configuracion de persistencia, y optimizacion de costos.</p>
<div class="highlight-box">
<h4>Resumen Ejecutivo</h4>
<p>Kubernetes es ideal para Odoo cuando necesitas <strong>alta disponibilidad (99.99%+)</strong>, <strong>escalado automatico</strong> para picos de demanda, o <strong>multiples entornos</strong> (desarrollo, staging, produccion) con despliegue continuo. Para PYMEs con menos de 50 usuarios y requisitos simples, un VPS gestionado sigue siendo mas cost-effective y facil de mantener.</p>
</div>
<h3>Que Aprenderas en Esta Guia</h3>
<ul>
<li>Criterios claros para decidir si Kubernetes es adecuado para tu caso de uso</li>
<li>Arquitectura de referencia para Odoo en K8s con diagramas interactivos</li>
<li>Configuracion completa de Helm charts con ejemplos de codigo</li>
<li>Comparativa de GKE, EKS, AKS y DOKS para hosting Odoo</li>
<li>Estrategias de deployment: Rolling, Blue-Green, y Canary</li>
<li>Optimizacion de costos con nodos spot y escalado automatico</li>
</ul>
</section>
<!-- When K8s Makes Sense -->
<section id="cuando-k8s" class="content-section fade-in">
<h2>Cuando Tiene Sentido Usar Kubernetes para Odoo</h2>
<p>La decision de usar Kubernetes no debe tomarse a la ligera. Aunque ofrece beneficios significativos, tambien introduce complejidad operativa que requiere conocimientos especializados. Aqui te presentamos los criterios clave para tomar esta decision.</p>
<h3>Kubernetes ES Recomendable Cuando:</h3>
<ul>
<li><strong>Mas de 100 usuarios concurrentes:</strong> El escalado horizontal de Odoo workers se vuelve critico</li>
<li><strong>Requisitos de uptime 99.99%+:</strong> Necesitas auto-healing y redundancia automatica</li>
<li><strong>Multiples entornos:</strong> Dev, staging, QA, produccion con despliegue frecuente</li>
<li><strong>CI/CD avanzado:</strong> Integracion con GitOps (ArgoCD, Flux) para deployments automaticos</li>
<li><strong>Microservicios:</strong> Odoo coexiste con otros servicios (APIs, workers de background)</li>
<li><strong>Picos de demanda predecibles:</strong> Black Friday, campanas de marketing, fin de mes contable</li>
<li><strong>Equipo DevOps dedicado:</strong> Tienes personal con experiencia en contenedores y K8s</li>
</ul>
<h3>Kubernetes NO Es Necesario Cuando:</h3>
<ul>
<li><strong>Menos de 50 usuarios:</strong> Un VPS bien dimensionado es suficiente y mas simple</li>
<li><strong>Presupuesto limitado:</strong> K8s tiene un costo base significativo (150-200 EUR/mes minimo)</li>
<li><strong>Sin equipo tecnico:</strong> La curva de aprendizaje es pronunciada</li>
<li><strong>Instalacion estatica:</strong> Raramente necesitas escalar o actualizar</li>
<li><strong>Requisitos de compliance simples:</strong> Un servidor dedicado puede ser mas facil de auditar</li>
</ul>
<div class="pros-cons">
<div class="pros">
<h4>Ventajas de K8s para Odoo</h4>
<ul>
<li>Auto-healing: pods se reinician automaticamente</li>
<li>Escalado horizontal y vertical automatico</li>
<li>Deployments sin downtime (rolling updates)</li>
<li>Rollback instantaneo a versiones anteriores</li>
<li>Infraestructura como codigo (IaC)</li>
<li>Portabilidad entre nubes</li>
</ul>
</div>
<div class="cons">
<h4>Desventajas de K8s para Odoo</h4>
<ul>
<li>Complejidad operativa significativa</li>
<li>Costo base mas alto que VPS</li>
<li>Curva de aprendizaje pronunciada</li>
<li>Debugging mas complejo</li>
<li>Requiere gestion de volumenes persistentes</li>
<li>Networking mas complejo</li>
</ul>
</div>
</div>
</section>
<!-- Architecture Diagram -->
<section class="chart-section fade-in">
<h3 id="arquitectura">Arquitectura de Odoo en Kubernetes</h3>
<p>Este diagrama interactivo muestra una arquitectura de referencia para Odoo en Kubernetes con alta disponibilidad. Pasa el cursor sobre cada componente para ver detalles.</p>
<div class="chart-container" id="architecture-diagram"></div>
<div class="architecture-legend">
<div class="legend-item"><div class="legend-color" style="background: #326ce5;"></div> Kubernetes Components</div>
<div class="legend-item"><div class="legend-color" style="background: #4CAF50;"></div> Odoo Application</div>
<div class="legend-item"><div class="legend-color" style="background: #ff9800;"></div> Database Layer</div>
<div class="legend-item"><div class="legend-color" style="background: #9c27b0;"></div> Storage/Cache</div>
<div class="legend-item"><div class="legend-color" style="background: #00bcd4;"></div> External Services</div>
</div>
</section>
<!-- Helm Charts -->
<section id="helm-charts" class="content-section fade-in">
<h2>Helm Charts para Odoo: Guia Completa</h2>
<p>Helm es el gestor de paquetes estandar para Kubernetes, y simplifica enormemente el despliegue de aplicaciones complejas como Odoo. Aunque Odoo S.A. no proporciona un chart oficial, la comunidad ha desarrollado varias opciones robustas.</p>
<h3>Chart Recomendado: Bitnami Odoo</h3>
<p>El chart de Bitnami es el mas mantenido y utilizado, con actualizaciones regulares para cada version de Odoo. Incluye PostgreSQL como dependencia y soporta configuracion avanzada.</p>
<div class="code-block">
<code><span class="comment"># Agregar repositorio de Bitnami</span>
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
<span class="comment"># Buscar versiones disponibles</span>
helm search repo bitnami/odoo --versions
<span class="comment"># Instalar Odoo con configuracion basica</span>
helm install odoo bitnami/odoo \
--namespace odoo \
--create-namespace \
--set odooEmail=admin@ejemplo.com \
--set odooPassword=<span class="string">"SecurePassword123!"</span></code>
</div>
<h3>Archivo values.yaml Personalizado para Produccion</h3>
<p>Para entornos de produccion, es esencial personalizar la configuracion. Aqui un ejemplo completo:</p>
<div class="code-block">
<code><span class="comment"># values-produccion.yaml</span>
<span class="keyword">replicaCount</span>: <span class="number">3</span>
<span class="keyword">image</span>:
<span class="keyword">tag</span>: <span class="string">"18.0"</span>
<span class="keyword">pullPolicy</span>: IfNotPresent
<span class="keyword">resources</span>:
<span class="keyword">requests</span>:
<span class="keyword">memory</span>: <span class="string">"2Gi"</span>
<span class="keyword">cpu</span>: <span class="string">"1000m"</span>
<span class="keyword">limits</span>:
<span class="keyword">memory</span>: <span class="string">"4Gi"</span>
<span class="keyword">cpu</span>: <span class="string">"2000m"</span>
<span class="keyword">persistence</span>:
<span class="keyword">enabled</span>: <span class="keyword">true</span>
<span class="keyword">storageClass</span>: <span class="string">"premium-rwo"</span>
<span class="keyword">size</span>: <span class="string">"100Gi"</span>
<span class="keyword">postgresql</span>:
<span class="keyword">enabled</span>: <span class="keyword">true</span>
<span class="keyword">auth</span>:
<span class="keyword">postgresPassword</span>: <span class="string">"PostgresSecure123!"</span>
<span class="keyword">database</span>: <span class="string">"odoo"</span>
<span class="keyword">primary</span>:
<span class="keyword">persistence</span>:
<span class="keyword">size</span>: <span class="string">"50Gi"</span>
<span class="keyword">resources</span>:
<span class="keyword">requests</span>:
<span class="keyword">memory</span>: <span class="string">"1Gi"</span>
<span class="keyword">cpu</span>: <span class="string">"500m"</span>
<span class="keyword">ingress</span>:
<span class="keyword">enabled</span>: <span class="keyword">true</span>
<span class="keyword">hostname</span>: <span class="string">"odoo.tudominio.com"</span>
<span class="keyword">tls</span>: <span class="keyword">true</span>
<span class="keyword">annotations</span>:
<span class="keyword">kubernetes.io/ingress.class</span>: <span class="string">"nginx"</span>
<span class="keyword">cert-manager.io/cluster-issuer</span>: <span class="string">"letsencrypt-prod"</span>
<span class="keyword">autoscaling</span>:
<span class="keyword">enabled</span>: <span class="keyword">true</span>
<span class="keyword">minReplicas</span>: <span class="number">2</span>
<span class="keyword">maxReplicas</span>: <span class="number">10</span>
<span class="keyword">targetCPU</span>: <span class="number">70</span>
<span class="keyword">targetMemory</span>: <span class="number">80</span></code>
</div>
<h3>Instalacion con Valores Personalizados</h3>
<div class="code-block">
<code><span class="comment"># Instalar con archivo de valores personalizado</span>
helm install odoo bitnami/odoo \
-f values-produccion.yaml \
-n odoo \
--create-namespace
<span class="comment"># Verificar el estado del despliegue</span>
kubectl get pods -n odoo -w
<span class="comment"># Obtener la URL de acceso</span>
kubectl get ingress -n odoo</code>
</div>
<div class="warning-box">
<h4>Importante: Gestion de Secretos</h4>
<p>Nunca almacenes contrasenas en texto plano en archivos YAML versionados. Usa <strong>Kubernetes Secrets</strong>, <strong>Sealed Secrets</strong>, o integraciones con gestores de secretos como <strong>HashiCorp Vault</strong>, <strong>AWS Secrets Manager</strong>, o <strong>Google Secret Manager</strong>.</p>
</div>
</section>
<!-- Deployment Strategies -->
<section id="estrategias-deployment" class="content-section fade-in">
<h2>Estrategias de Deployment para Odoo en Kubernetes</h2>
<p>La eleccion de la estrategia de deployment correcta es crucial para minimizar el downtime y los riesgos durante actualizaciones. Kubernetes ofrece varias opciones, cada una con sus ventajas y casos de uso.</p>
<h3>1. Rolling Update (Por Defecto)</h3>
<p>Actualiza los pods gradualmente, reemplazando instancias antiguas por nuevas de forma progresiva. Es la estrategia por defecto en Kubernetes y funciona bien para cambios menores.</p>
<div class="pros-cons">
<div class="pros">
<h4>Ventajas</h4>
<ul>
<li>Zero downtime durante actualizaciones</li>
<li>Uso eficiente de recursos</li>
<li>Configuracion simple por defecto</li>
</ul>
</div>
<div class="cons">
<h4>Limitaciones</h4>
<ul>
<li>Rollback no es instantaneo</li>
<li>Versiones mixtas durante el proceso</li>
<li>Problemas si hay migraciones de BD</li>
</ul>
</div>
</div>
<h3>2. Blue-Green Deployment (Recomendado para Odoo)</h3>
<p>Mantiene dos entornos identicos (blue y green). El trafico se dirige a uno mientras se actualiza el otro. Una vez validado, se cambia el trafico al nuevo entorno.</p>
<div class="code-block">
<code><span class="comment"># Ejemplo de Service que apunta a la version activa</span>
<span class="keyword">apiVersion</span>: v1
<span class="keyword">kind</span>: Service
<span class="keyword">metadata</span>:
<span class="keyword">name</span>: odoo
<span class="keyword">spec</span>:
<span class="keyword">selector</span>:
<span class="keyword">app</span>: odoo
<span class="keyword">version</span>: blue <span class="comment"># Cambiar a 'green' para switch</span>
<span class="keyword">ports</span>:
- <span class="keyword">port</span>: <span class="number">80</span>
<span class="keyword">targetPort</span>: <span class="number">8069</span></code>
</div>
<h3>3. Canary Deployment</h3>
<p>Despliega la nueva version a un pequeno porcentaje de usuarios primero. Util para probar nuevos modulos o cambios significativos con riesgo controlado.</p>
<div class="code-block">
<code><span class="comment"># Con Istio o ingress-nginx puedes controlar el porcentaje</span>
<span class="keyword">apiVersion</span>: networking.k8s.io/v1
<span class="keyword">kind</span>: Ingress
<span class="keyword">metadata</span>:
<span class="keyword">annotations</span>:
<span class="keyword">nginx.ingress.kubernetes.io/canary</span>: <span class="string">"true"</span>
<span class="keyword">nginx.ingress.kubernetes.io/canary-weight</span>: <span class="string">"10"</span> <span class="comment"># 10% del trafico</span></code>
</div>
<div class="highlight-box">
<h4>Recomendacion para Actualizaciones de Odoo</h4>
<p>Para actualizaciones mayores de Odoo (ej: 17.0 a 18.0), recomendamos <strong>Blue-Green deployment</strong> con backup completo de base de datos. Ejecuta las migraciones en el entorno "green" inactivo, valida, y luego cambia el trafico. Esto permite rollback instantaneo si algo falla.</p>
</div>
</section>
<!-- Cloud Providers Comparison -->
<section class="chart-section fade-in">
<h3 id="comparacion-proveedores">Comparativa de Proveedores K8s Gestionado</h3>
<p>Este grafico radar compara los principales proveedores de Kubernetes gestionado en dimensiones clave para hosting Odoo.</p>
<div class="chart-container" id="radar-chart"></div>
</section>
<!-- Cloud Providers -->
<section id="proveedores-cloud" class="content-section fade-in">
<h2>Proveedores Cloud con Kubernetes Gestionado</h2>
<p>Elegir el proveedor adecuado de Kubernetes gestionado impacta directamente en costos, rendimiento y facilidad de operacion. Analizamos los cuatro principales para hosting Odoo.</p>
<div class="provider-grid">
<!-- GKE -->
<div class="provider-card featured">
<span class="badge">Recomendado</span>
<h4>Google GKE</h4>
<p class="price">~180EUR<span class="price-period">/mes (Autopilot)</span></p>
<ul>
<li>Autopilot: K8s sin gestion de nodos</li>
<li>Integracion nativa con Cloud SQL</li>
<li>Networking avanzado (VPC-native)</li>
<li>Auto-upgrade y auto-repair</li>
<li>Excelente documentacion</li>
<li>Precios competitivos en Europa</li>
</ul>
<a href="https://cloud.google.com/kubernetes-engine" class="cta-btn" target="_blank" rel="noopener">Ver GKE</a>
</div>
<!-- EKS -->
<div class="provider-card">
<span class="badge">Enterprise</span>
<h4>Amazon EKS</h4>
<p class="price">~220EUR<span class="price-period">/mes</span></p>
<ul>
<li>Integracion con ecosistema AWS</li>
<li>EKS Fargate para serverless</li>
<li>RDS PostgreSQL gestionado</li>
<li>IAM para autenticacion</li>
<li>Mayor adopcion enterprise</li>
<li>Soporte 24/7 disponible</li>
</ul>
<a href="https://aws.amazon.com/eks/" class="cta-btn" target="_blank" rel="noopener">Ver EKS</a>
</div>
<!-- AKS -->
<div class="provider-card">
<span class="badge">Microsoft</span>
<h4>Azure AKS</h4>
<p class="price">~200EUR<span class="price-period">/mes</span></p>
<ul>
<li>Control plane gratuito</li>
<li>Integracion con Azure AD</li>
<li>Azure Database for PostgreSQL</li>
<li>Dev Spaces para desarrollo</li>
<li>Ideal si usas Office 365</li>
<li>Creditos para startups</li>
</ul>
<a href="https://azure.microsoft.com/services/kubernetes-service/" class="cta-btn" target="_blank" rel="noopener">Ver AKS</a>
</div>
<!-- DOKS -->
<div class="provider-card">
<span class="badge">Economico</span>
<h4>DigitalOcean DOKS</h4>
<p class="price">~150EUR<span class="price-period">/mes</span></p>
<ul>
<li>Simplicidad de uso</li>
<li>Control plane gratuito</li>
<li>Precios predecibles</li>
<li>Managed PostgreSQL</li>
<li>UI intuitiva</li>
<li>Ideal para startups</li>
</ul>
<a href="https://www.digitalocean.com/products/kubernetes" class="cta-btn" target="_blank" rel="noopener">Ver DOKS</a>
</div>
</div>
<h3>Tabla Comparativa Detallada</h3>
<div style="overflow-x: auto;">
<table class="comparison-table">
<thead>
<tr>
<th>Caracteristica</th>
<th>GKE</th>
<th>EKS</th>
<th>AKS</th>
<th>DOKS</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Control Plane</strong></td>
<td>$0.10/hr (Autopilot gratis)</td>
<td>$0.10/hr</td>
<td>Gratis</td>
<td>Gratis</td>
</tr>
<tr>
<td><strong>Nodo Minimo</strong></td>
<td>~$25/mes (e2-small)</td>
<td>~$30/mes (t3.small)</td>
<td>~$28/mes (B2s)</td>
<td>~$24/mes (s-2vcpu-4gb)</td>
</tr>
<tr>
<td><strong>PostgreSQL Gestionado</strong></td>
<td class="check">Cloud SQL</td>
<td class="check">RDS</td>
<td class="check">Azure Database</td>
<td class="check">Managed DB</td>
</tr>
<tr>
<td><strong>Serverless Pods</strong></td>
<td class="check">Autopilot/Cloud Run</td>
<td class="check">Fargate</td>
<td class="check">ACI Integration</td>
<td class="cross">No disponible</td>
</tr>
<tr>
<td><strong>Regiones en Europa</strong></td>
<td>6+ regiones</td>
<td>5+ regiones</td>
<td>8+ regiones</td>
<td>3 regiones</td>
</tr>
<tr>
<td><strong>Soporte SLA</strong></td>
<td>99.95%</td>
<td>99.95%</td>
<td>99.95%</td>
<td>99.99%</td>
</tr>
<tr>
<td><strong>Facilidad de Uso</strong></td>
<td>Alta</td>
<td>Media</td>
<td>Alta</td>
<td>Muy Alta</td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- Production Configuration -->
<section id="configuracion-produccion" class="content-section fade-in">
<h2>Configuracion para Produccion</h2>
<p>Llevar Odoo a produccion en Kubernetes requiere atencion a varios aspectos criticos: persistencia de datos, networking, seguridad, y observabilidad. Aqui cubrimos las configuraciones esenciales.</p>
<h3>1. Persistencia de Datos</h3>
<p>Odoo almacena archivos adjuntos en el filestore y requiere acceso a PostgreSQL. En K8s, esto se gestiona con PersistentVolumeClaims.</p>
<div class="code-block">
<code><span class="comment"># PVC para filestore de Odoo</span>
<span class="keyword">apiVersion</span>: v1
<span class="keyword">kind</span>: PersistentVolumeClaim
<span class="keyword">metadata</span>:
<span class="keyword">name</span>: odoo-filestore
<span class="keyword">namespace</span>: odoo
<span class="keyword">spec</span>:
<span class="keyword">accessModes</span>:
- ReadWriteMany <span class="comment"># Requerido para multiples replicas</span>
<span class="keyword">storageClassName</span>: <span class="string">"filestore-nfs"</span> <span class="comment"># O EFS, Filestore, etc.</span>
<span class="keyword">resources</span>:
<span class="keyword">requests</span>:
<span class="keyword">storage</span>: <span class="string">"100Gi"</span></code>
</div>
<h3>2. Base de Datos PostgreSQL</h3>
<p>Para produccion, recomendamos usar un servicio de PostgreSQL gestionado (Cloud SQL, RDS, Azure Database) en lugar de ejecutar PostgreSQL dentro del cluster.</p>
<div class="highlight-box">
<h4>Recomendacion: PostgreSQL Gestionado</h4>
<p>Los servicios gestionados ofrecen backups automaticos, alta disponibilidad, actualizaciones de seguridad, y escalado simplificado. El costo adicional (~50-100 EUR/mes) se compensa con la reduccion de carga operativa.</p>
</div>
<h3>3. Ingress y SSL/TLS</h3>
<p>Configura un Ingress Controller (nginx-ingress o traefik) con cert-manager para certificados automaticos.</p>
<div class="code-block">
<code><span class="comment"># Ingress con SSL automatico via cert-manager</span>
<span class="keyword">apiVersion</span>: networking.k8s.io/v1
<span class="keyword">kind</span>: Ingress
<span class="keyword">metadata</span>:
<span class="keyword">name</span>: odoo-ingress
<span class="keyword">namespace</span>: odoo
<span class="keyword">annotations</span>:
<span class="keyword">kubernetes.io/ingress.class</span>: <span class="string">"nginx"</span>
<span class="keyword">cert-manager.io/cluster-issuer</span>: <span class="string">"letsencrypt-prod"</span>
<span class="keyword">nginx.ingress.kubernetes.io/proxy-body-size</span>: <span class="string">"100m"</span>
<span class="keyword">nginx.ingress.kubernetes.io/proxy-read-timeout</span>: <span class="string">"600"</span>
<span class="keyword">spec</span>:
<span class="keyword">tls</span>:
- <span class="keyword">hosts</span>:
- <span class="string">"odoo.tudominio.com"</span>
<span class="keyword">secretName</span>: odoo-tls
<span class="keyword">rules</span>:
- <span class="keyword">host</span>: <span class="string">"odoo.tudominio.com"</span>
<span class="keyword">http</span>:
<span class="keyword">paths</span>:
- <span class="keyword">path</span>: /
<span class="keyword">pathType</span>: Prefix
<span class="keyword">backend</span>:
<span class="keyword">service</span>:
<span class="keyword">name</span>: odoo
<span class="keyword">port</span>:
<span class="keyword">number</span>: <span class="number">80</span></code>
</div>
<h3>4. Configuracion de Workers de Odoo</h3>
<p>Para multiples replicas, configura Odoo en modo multi-worker con sesiones compartidas:</p>
<div class="code-block">
<code><span class="comment"># Configuracion de odoo.conf para K8s</span>
[options]
workers = <span class="number">4</span>
max_cron_threads = <span class="number">1</span>
limit_memory_hard = <span class="number">2684354560</span>
limit_memory_soft = <span class="number">2147483648</span>
limit_time_cpu = <span class="number">600</span>
limit_time_real = <span class="number">1200</span>
proxy_mode = True
db_host = postgresql-service
db_port = <span class="number">5432</span>
db_user = odoo
db_password = <span class="string">${DB_PASSWORD}</span> <span class="comment"># Desde Secret</span></code>
</div>
<h3>5. Sesiones con Redis</h3>
<p>Para escalado horizontal, las sesiones deben almacenarse en Redis en lugar del filesystem local:</p>
<div class="code-block">
<code><span class="comment"># Instalar Redis con Helm</span>
helm install redis bitnami/redis \
--namespace odoo \
--set auth.password=<span class="string">"RedisSecure123!"</span> \
--set replica.replicaCount=<span class="number">2</span>
<span class="comment"># Configurar Odoo para usar Redis (requiere modulo)</span>
<span class="comment"># O usar nginx sticky sessions como alternativa</span></code>
</div>
</section>
<!-- Scalability -->
<section id="escalabilidad" class="content-section fade-in">
<h2>Escalabilidad y Alta Disponibilidad</h2>
<p>Una de las principales ventajas de Kubernetes es la capacidad de escalar automaticamente segun la demanda. Para Odoo, esto requiere configuracion especifica debido a la naturaleza stateful de la aplicacion.</p>
<h3>Horizontal Pod Autoscaler (HPA)</h3>
<p>Configura el HPA para escalar automaticamente los pods de Odoo basandose en CPU o memoria:</p>
<div class="code-block">
<code><span class="keyword">apiVersion</span>: autoscaling/v2
<span class="keyword">kind</span>: HorizontalPodAutoscaler
<span class="keyword">metadata</span>:
<span class="keyword">name</span>: odoo-hpa
<span class="keyword">namespace</span>: odoo
<span class="keyword">spec</span>:
<span class="keyword">scaleTargetRef</span>:
<span class="keyword">apiVersion</span>: apps/v1
<span class="keyword">kind</span>: Deployment
<span class="keyword">name</span>: odoo
<span class="keyword">minReplicas</span>: <span class="number">2</span>
<span class="keyword">maxReplicas</span>: <span class="number">10</span>
<span class="keyword">metrics</span>:
- <span class="keyword">type</span>: Resource
<span class="keyword">resource</span>:
<span class="keyword">name</span>: cpu
<span class="keyword">target</span>:
<span class="keyword">type</span>: Utilization
<span class="keyword">averageUtilization</span>: <span class="number">70</span>
- <span class="keyword">type</span>: Resource
<span class="keyword">resource</span>:
<span class="keyword">name</span>: memory
<span class="keyword">target</span>:
<span class="keyword">type</span>: Utilization
<span class="keyword">averageUtilization</span>: <span class="number">80</span>
<span class="keyword">behavior</span>:
<span class="keyword">scaleDown</span>:
<span class="keyword">stabilizationWindowSeconds</span>: <span class="number">300</span> <span class="comment"># Evita scale-down agresivo</span>
<span class="keyword">scaleUp</span>:
<span class="keyword">stabilizationWindowSeconds</span>: <span class="number">60</span></code>
</div>
<h3>Alta Disponibilidad de PostgreSQL</h3>
<p>Para alta disponibilidad de la base de datos, considera:</p>
<ul>
<li><strong>Servicios gestionados:</strong> Cloud SQL HA, RDS Multi-AZ, Azure Database HA</li>
<li><strong>Operadores K8s:</strong> CloudNativePG, Zalando Postgres Operator, CrunchyData PGO</li>
<li><strong>Patroni:</strong> Solucion open source para PostgreSQL HA</li>
</ul>
<h3>Arquitectura Multi-Region (Disaster Recovery)</h3>
<p>Para requisitos criticos de disponibilidad, considera una arquitectura multi-region con replicacion de base de datos y failover automatico:</p>
<div class="warning-box">
<h4>Complejidad vs Beneficio</h4>
<p>Una arquitectura multi-region anade complejidad significativa y costos (2-3x). Solo es necesaria si tu SLA requiere recuperacion en minutos ante desastres regionales. Para la mayoria de casos, alta disponibilidad dentro de una region (multi-zona) es suficiente.</p>
</div>
</section>
<!-- Cost Analysis Chart -->
<section class="chart-section fade-in">
<h3 id="costos">Analisis de Costos: K8s vs VPS vs Managed Hosting</h3>
<p>Este grafico compara los costos mensuales de diferentes opciones de hosting para Odoo segun el numero de usuarios.</p>
<div class="chart-container" id="cost-chart"></div>
</section>
<!-- Cost Section -->
<section id="costos-detalle" class="content-section fade-in">
<h2>Analisis Detallado de Costos</h2>
<p>Kubernetes tiene un costo base significativo que debe justificarse con los beneficios obtenidos. Aqui desglosamos los costos tipicos para diferentes escalas de uso.</p>
<h3>Costo Minimo Viable (Desarrollo/Test)</h3>
<table class="comparison-table">
<tr><th>Componente</th><th>GKE</th><th>EKS</th><th>AKS</th><th>DOKS</th></tr>
<tr><td>Control Plane</td><td>$0 (Autopilot)</td><td>$73/mes</td><td>$0</td><td>$0</td></tr>
<tr><td>Nodos (2x small)</td><td>~$50/mes</td><td>~$60/mes</td><td>~$56/mes</td><td>~$48/mes</td></tr>
<tr><td>Load Balancer</td><td>~$20/mes</td><td>~$20/mes</td><td>~$20/mes</td><td>~$12/mes</td></tr>
<tr><td>Almacenamiento 50GB</td><td>~$10/mes</td><td>~$12/mes</td><td>~$10/mes</td><td>~$10/mes</td></tr>
<tr><th>Total Minimo</th><th>~$80/mes</th><th>~$165/mes</th><th>~$86/mes</th><th>~$70/mes</th></tr>
</table>
<h3>Costo Produccion (10-50 usuarios)</h3>
<table class="comparison-table">
<tr><th>Componente</th><th>Cantidad</th><th>Costo Mensual</th></tr>
<tr><td>Nodos K8s (3x 4vCPU, 8GB)</td><td>3</td><td>~$180-250</td></tr>
<tr><td>PostgreSQL Gestionado</td><td>1 (db-f1-micro a db-n1-standard-1)</td><td>~$50-100</td></tr>
<tr><td>Load Balancer</td><td>1</td><td>~$20</td></tr>
<tr><td>Almacenamiento (100GB SSD)</td><td>100GB</td><td>~$20</td></tr>
<tr><td>Networking (egress)</td><td>Variable</td><td>~$20-50</td></tr>
<tr><th>Total Produccion</th><th colspan="2">~$290-440/mes (250-380 EUR)</th></tr>
</table>
<h3>Optimizacion de Costos</h3>
<ul>
<li><strong>Nodos Spot/Preemptibles:</strong> Ahorra 60-90% en nodos no criticos (workers de Odoo son buenos candidatos)</li>
<li><strong>Committed Use Discounts:</strong> 1-3 anos de compromiso = 30-60% descuento</li>
<li><strong>Right-sizing:</strong> Monitorea y ajusta recursos basandote en uso real</li>
<li><strong>Cluster Autoscaler:</strong> Reduce nodos en horarios de baja demanda</li>
<li><strong>GKE Autopilot:</strong> Paga solo por pods, no por nodos subutilizados</li>
</ul>
<div class="highlight-box">
<h4>Comparacion: K8s vs VPS Gestionado</h4>
<p>Para 20 usuarios, un <strong>VPS gestionado</strong> cuesta ~$50-80/mes (ej: Odoo4projects a 29EUR). Kubernetes para el mismo caso cuesta ~$200-300/mes. K8s se justifica cuando necesitas escalabilidad, alta disponibilidad, o tienes >50 usuarios con picos de demanda.</p>
</div>
</section>
<!-- CTA Banner -->
<section class="cta-banner fade-in">
<h3>Necesitas Ayuda con tu Despliegue de Odoo en Kubernetes?</h3>
<p>Nuestro equipo de expertos puede disenar e implementar tu arquitectura K8s para Odoo. Desde consultorias hasta implementaciones llave en mano.</p>
<a href="/contacto/" class="cta-btn">Solicitar Consultoria</a>
</section>
<!-- FAQ Section -->
<section id="faq" class="faq-section fade-in">
<h2>Preguntas Frecuentes sobre Odoo en Kubernetes</h2>
<div class="faq-item">
<div class="faq-question">Cuando tiene sentido usar Kubernetes para Odoo?</div>
<div class="faq-answer">Kubernetes es recomendable para Odoo cuando necesitas alta disponibilidad (99.99%+), escalabilidad automatica para picos de demanda, multiples entornos (dev/staging/prod), integracion con CI/CD avanzado, o cuando manejas mas de 100 usuarios concurrentes. Para PYMEs con menos de 50 usuarios, un VPS gestionado suele ser mas cost-effective.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cual es el mejor proveedor cloud para Odoo en Kubernetes?</div>
<div class="faq-answer">Para empresas en Europa, Google GKE ofrece la mejor relacion precio/rendimiento con Autopilot. AWS EKS es ideal si ya usas servicios AWS. Azure AKS es la opcion preferida para empresas con infraestructura Microsoft. DigitalOcean DOKS es excelente para presupuestos ajustados con simplicidad.</div>
</div>
<div class="faq-item">
<div class="faq-question">Existe un Helm chart oficial para Odoo?</div>
<div class="faq-answer">No existe un Helm chart oficial de Odoo S.A. Sin embargo, Bitnami mantiene el chart mas popular y estable (bitnami/odoo), actualizado regularmente con cada version de Odoo. Tambien existen charts comunitarios en ArtifactHub con configuraciones especializadas.</div>
</div>
<div class="faq-item">
<div class="faq-question">Cuanto cuesta ejecutar Odoo en Kubernetes?</div>
<div class="faq-answer">El costo minimo viable es aproximadamente 150-200 EUR/mes para un cluster basico (3 nodos, 2vCPU, 4GB cada uno) mas almacenamiento y networking. Para produccion con alta disponibilidad, el costo tipico es 400-800 EUR/mes. Los costos pueden reducirse significativamente con nodos spot/preemptibles.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como manejo los volumenes persistentes de Odoo en K8s?</div>
<div class="faq-answer">Odoo requiere almacenamiento persistente para el filestore y la base de datos PostgreSQL. Usa PersistentVolumeClaims con StorageClass que soporte ReadWriteMany (como NFS, EFS, o Filestore) para el filestore si necesitas multiples replicas. Para PostgreSQL, usa operadores como CloudNativePG o servicios gestionados (Cloud SQL, RDS).</div>
</div>
<div class="faq-item">
<div class="faq-question">Puedo escalar Odoo horizontalmente en Kubernetes?</div>
<div class="faq-answer">Si, pero con consideraciones. Odoo puede escalar horizontalmente los workers de Odoo si configuras correctamente: sesiones en Redis/Memcached, filestore compartido (NFS/S3), y PostgreSQL con suficiente capacidad. El escalado horizontal tipico es 2-10 pods de Odoo apuntando a una base de datos PostgreSQL con alta disponibilidad.</div>
</div>
<div class="faq-item">
<div class="faq-question">Que estrategia de deployment es mejor para Odoo en K8s?</div>
<div class="faq-answer">Para actualizaciones de Odoo, recomendamos Blue-Green deployment por su capacidad de rollback instantaneo. Rolling updates funcionan para cambios menores de codigo. Canary deployments son utiles para probar nuevos modulos con un porcentaje de trafico. Siempre haz backup de la base de datos antes de cualquier actualizacion.</div>
</div>
<div class="faq-item">
<div class="faq-question">Como configuro HTTPS/SSL para Odoo en Kubernetes?</div>
<div class="faq-answer">La forma mas comun es usar un Ingress Controller (nginx-ingress o traefik) combinado con cert-manager para certificados automaticos de Lets Encrypt. Configura annotations en el Ingress para SSL redirect y HSTS. Para produccion enterprise, considera certificados wildcard o de organizacion.</div>
</div>
</section>
<!-- Related Articles -->
<section class="content-section fade-in">
<h2>Articulos Relacionados</h2>
<div class="related-articles">
<a href="/pt/odoo-hosting/mejor-hosting-odoo-2026/" class="related-card">
<div class="related-card-image">Hosting</div>
<div class="related-card-content">
<h4>Mejor Hosting Odoo 2026: Comparativa</h4>
<p>Analisis de 15+ proveedores de hosting para Odoo</p>
</div>
</a>
<a href="/pt/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 para Odoo: Guia Completa</h4>
<p>Configura tu propio servidor virtual paso a paso</p>
</div>
</a>
<a href="/pt/odoo-hosting/odoo-docker-contenedores-2025/" class="related-card">
<div class="related-card-image">Docker</div>
<div class="related-card-content">
<h4>Odoo con Docker: Guia Definitiva</h4>
<p>Contenedores Docker para desarrollo y produccion</p>
</div>
</a>
<a href="/pt/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 para Odoo</h4>
<p>Especificaciones de servidor recomendadas</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="/pt/">Inicio</a><a href="/pt/odoo/">Odoo</a><a href="/pt/odoo-ia/">Odoo IA</a><a href="/pt/odoo-hosting/">Hospedagem Odoo</a><a href="/pt/mapa-del-sitio/">Mapa do Site</a></nav></div><div class="footer-bottom"><small>&copy; 2026 Odoo Expertos</small></div></div></footer></div><nav class="footer-nav"><a href="/pt/">Inicio</a><a href="/pt/odoo/">Odoo</a><a href="/pt/odoo-ia/">Odoo IA</a><a href="/pt/odoo-hosting/">Hospedagem Odoo</a><a href="/pt/mapa-del-sitio/">Mapa do 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 k8sColors = {
kubernetes: '#326ce5',
odoo: '#4CAF50',
database: '#ff9800',
storage: '#9c27b0',
external: '#00bcd4'
};
// 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);
// Define architecture components
const components = [
// External Layer
{ id: 'users', label: 'Usuarios', x: width/2, y: 30, color: k8sColors.external, type: 'external', description: 'Clientes web y movil accediendo a Odoo' },
{ id: 'dns', label: 'DNS/CDN', x: width/2, y: 80, color: k8sColors.external, type: 'external', description: 'Cloudflare, Route53 o similar para DNS y cache' },
// Kubernetes Cluster
{ id: 'ingress', label: 'Ingress Controller', x: width/2, y: 140, color: k8sColors.kubernetes, type: 'k8s', description: 'nginx-ingress o traefik con cert-manager para SSL' },
{ id: 'service', label: 'Odoo Service (ClusterIP)', x: width/2, y: 200, color: k8sColors.kubernetes, type: 'k8s', description: 'Load balancing interno entre pods de Odoo' },
// Odoo Pods
{ id: 'odoo1', label: 'Odoo Pod 1', x: width/4, y: 270, color: k8sColors.odoo, type: 'odoo', description: 'Replica 1 de Odoo con 4 workers' },
{ id: 'odoo2', label: 'Odoo Pod 2', x: width/2, y: 270, color: k8sColors.odoo, type: 'odoo', description: 'Replica 2 de Odoo con 4 workers' },
{ id: 'odoo3', label: 'Odoo Pod 3', x: 3*width/4, y: 270, color: k8sColors.odoo, type: 'odoo', description: 'Replica 3 de Odoo con 4 workers (escalable a N)' },
// Data Layer
{ id: 'redis', label: 'Redis (Sessions)', x: width/4, y: 350, color: k8sColors.storage, type: 'storage', description: 'Cache de sesiones compartido entre pods' },
{ id: 'postgres', label: 'PostgreSQL HA', x: width/2, y: 350, color: k8sColors.database, type: 'db', description: 'Base de datos con alta disponibilidad (Cloud SQL, RDS, o operador)' },
{ id: 'filestore', label: 'Filestore (NFS/S3)', x: 3*width/4, y: 350, color: k8sColors.storage, type: 'storage', description: 'Almacenamiento compartido para archivos adjuntos' },
// HPA
{ id: 'hpa', label: 'HPA (Autoscaler)', x: width - 80, y: 200, color: k8sColors.kubernetes, type: 'k8s', description: 'Horizontal Pod Autoscaler para escalar segun CPU/memoria' }
];
// Define connections
const connections = [
{ source: 'users', target: 'dns' },
{ source: 'dns', target: 'ingress' },
{ source: 'ingress', target: 'service' },
{ source: 'service', target: 'odoo1' },
{ source: 'service', target: 'odoo2' },
{ source: 'service', target: 'odoo3' },
{ source: 'odoo1', target: 'redis' },
{ source: 'odoo2', target: 'redis' },
{ source: 'odoo3', target: 'redis' },
{ source: 'odoo1', target: 'postgres' },
{ source: 'odoo2', target: 'postgres' },
{ source: 'odoo3', target: 'postgres' },
{ source: 'odoo1', target: 'filestore' },
{ source: 'odoo2', target: 'filestore' },
{ source: 'odoo3', target: 'filestore' },
{ source: 'hpa', target: 'odoo2', dashed: true }
];
// Draw cluster boundary
svg.append('rect')
.attr('x', 40)
.attr('y', 115)
.attr('width', width - 80)
.attr('height', 280)
.attr('fill', 'none')
.attr('stroke', k8sColors.kubernetes)
.attr('stroke-width', 2)
.attr('stroke-dasharray', '8,4')
.attr('rx', 12);
svg.append('text')
.attr('x', 55)
.attr('y', 135)
.attr('fill', k8sColors.kubernetes)
.attr('font-size', '12px')
.attr('font-weight', '600')
.text('Kubernetes Cluster');
// Create component map for connections
const componentMap = {};
components.forEach(c => componentMap[c.id] = c);
// Draw connections
connections.forEach((conn, i) => {
const source = componentMap[conn.source];
const target = componentMap[conn.target];
const line = svg.append('line')
.attr('x1', source.x)
.attr('y1', source.y + 15)
.attr('x2', target.x)
.attr('y2', target.y - 15)
.attr('stroke', '#555')
.attr('stroke-width', conn.dashed ? 1.5 : 1)
.attr('stroke-dasharray', conn.dashed ? '5,3' : 'none')
.attr('opacity', 0);
line.transition()
.duration(500)
.delay(i * 30)
.attr('opacity', 0.6);
});
// Draw components
components.forEach((comp, i) => {
const g = svg.append('g')
.attr('transform', `translate(${comp.x}, ${comp.y})`)
.style('cursor', 'pointer')
.style('opacity', 0);
// Background rect
const rectWidth = comp.type === 'k8s' || comp.type === 'db' ? 140 : 100;
g.append('rect')
.attr('x', -rectWidth/2)
.attr('y', -15)
.attr('width', rectWidth)
.attr('height', 30)
.attr('fill', comp.color)
.attr('fill-opacity', 0.2)
.attr('stroke', comp.color)
.attr('stroke-width', 2)
.attr('rx', 6);
// Label
g.append('text')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.attr('fill', '#e0e0e0')
.attr('font-size', '11px')
.attr('font-weight', '500')
.text(comp.label);
// Hover events
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.description}`)
.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);
});
// Animate in
g.transition()
.duration(600)
.delay(i * 80)
.style('opacity', 1);
});
}
// Radar Chart for Cloud Providers
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 = ['Precio', 'Rendimiento', 'Facilidad', 'Soporte', 'Escalabilidad', 'Integraciones'];
const angleSlice = Math.PI * 2 / categories.length;
const providers = [
{ name: 'GKE', values: [85, 95, 90, 85, 95, 90], color: '#4285f4' },
{ name: 'EKS', values: [70, 90, 70, 90, 95, 95], color: '#ff9900' },
{ name: 'AKS', values: [80, 85, 85, 80, 90, 85], color: '#0078d4' },
{ name: 'DOKS', values: [95, 75, 95, 70, 70, 60], color: '#0080ff' }
];
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', '#2a3f5f')
.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', '#3a5070');
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', '12px')
.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 + 40 : -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);
});
}
// Cost Comparison Chart
function renderCostChart() {
const container = d3.select('#cost-chart');
if (container.empty()) return;
const width = container.node().getBoundingClientRect().width;
const height = 400;
const margin = { top: 40, right: 120, bottom: 60, left: 70 };
container.html('');
const svg = container.append('svg')
.attr('width', width)
.attr('height', height);
// Data: costs at different user counts
const users = [10, 25, 50, 100, 200, 500];
const solutions = [
{ name: 'VPS Gestionado', color: '#4CAF50', values: [50, 60, 80, 150, 300, 600] },
{ name: 'Kubernetes (DOKS)', color: '#0080ff', values: [150, 160, 200, 280, 400, 700] },
{ name: 'Kubernetes (GKE)', color: '#4285f4', values: [180, 200, 250, 350, 500, 900] },
{ name: 'Kubernetes (EKS)', color: '#ff9900', values: [220, 250, 320, 450, 650, 1100] }
];
const xScale = d3.scaleLinear()
.domain([0, 500])
.range([margin.left, width - margin.right]);
const yScale = d3.scaleLinear()
.domain([0, 1200])
.range([height - margin.bottom, margin.top]);
// Grid lines
svg.append('g')
.attr('class', 'grid')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickSize(-(height - margin.top - margin.bottom)).tickFormat(''))
.selectAll('line').attr('stroke', '#2a3f5f');
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', '#2a3f5f');
// Axes
svg.append('g')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale).tickFormat(d => d))
.attr('color', '#888');
svg.append('g')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale).tickFormat(d => `${d} EUR`))
.attr('color', '#888');
// Axis labels
svg.append('text')
.attr('x', width / 2)
.attr('y', height - 10)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('Numero de Usuarios');
svg.append('text')
.attr('transform', 'rotate(-90)')
.attr('x', -height / 2)
.attr('y', 20)
.attr('text-anchor', 'middle')
.attr('fill', '#888')
.attr('font-size', '14px')
.text('Costo Mensual (EUR)');
// Line generator
const line = d3.line()
.x((d, i) => xScale(users[i]))
.y(d => yScale(d))
.curve(d3.curveMonotoneX);
// Draw lines
solutions.forEach((sol, idx) => {
const path = svg.append('path')
.datum(sol.values)
.attr('fill', 'none')
.attr('stroke', sol.color)
.attr('stroke-width', 3)
.attr('d', line);
const totalLength = path.node().getTotalLength();
path.attr('stroke-dasharray', totalLength + ' ' + totalLength)
.attr('stroke-dashoffset', totalLength)
.transition()
.duration(1500)
.delay(idx * 200)
.ease(d3.easeLinear)
.attr('stroke-dashoffset', 0);
// Data points
sol.values.forEach((val, i) => {
svg.append('circle')
.attr('cx', xScale(users[i]))
.attr('cy', yScale(val))
.attr('r', 0)
.attr('fill', sol.color)
.attr('stroke', '#fff')
.attr('stroke-width', 2)
.style('cursor', 'pointer')
.on('mouseover', function(event) {
d3.select(this).attr('r', 8);
tooltip.transition().duration(200).style('opacity', 1);
tooltip.html(`<strong>${sol.name}</strong><br>${users[i]} usuarios: ${val} EUR/mes`)
.style('left', (event.pageX + 15) + 'px')
.style('top', (event.pageY - 28) + 'px');
})
.on('mouseout', function() {
d3.select(this).attr('r', 5);
tooltip.transition().duration(200).style('opacity', 0);
})
.transition()
.duration(400)
.delay(idx * 200 + i * 100 + 500)
.attr('r', 5);
});
});
// Legend
const legend = svg.append('g')
.attr('transform', `translate(${width - margin.right + 20}, ${margin.top})`);
solutions.forEach((sol, idx) => {
const g = legend.append('g')
.attr('transform', `translate(0, ${idx * 25})`);
g.append('line')
.attr('x1', 0)
.attr('x2', 20)
.attr('y1', 8)
.attr('y2', 8)
.attr('stroke', sol.color)
.attr('stroke-width', 3);
g.append('text')
.attr('x', 28)
.attr('y', 12)
.attr('fill', '#b0b0b0')
.attr('font-size', '11px')
.text(sol.name);
});
// Breakeven annotation
svg.append('line')
.attr('x1', xScale(75))
.attr('x2', xScale(75))
.attr('y1', margin.top)
.attr('y2', height - margin.bottom)
.attr('stroke', '#ff5722')
.attr('stroke-width', 1.5)
.attr('stroke-dasharray', '6,4')
.attr('opacity', 0.7);
svg.append('text')
.attr('x', xScale(75) + 5)
.attr('y', margin.top + 20)
.attr('fill', '#ff5722')
.attr('font-size', '11px')
.text('Punto de equilibrio K8s')
.attr('transform', `rotate(90, ${xScale(75) + 5}, ${margin.top + 20})`);
}
// 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 === 'radar-chart') renderRadarChart();
if (id === 'cost-chart') renderCostChart();
}, 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();
renderRadarChart();
renderCostChart();
}, 300);
});
</script>
</body>
</html>