Despliegue n8n Kubernetes: Manifiestos y Config

2026.05.10
Technology
911 Words
Despliegue n8n Kubernetes: Manifiestos y Config

Despliegue de n8n: Guía de Manifiestos Kubernetes

Parte 2 de 3. Parte 1: Configuración con Docker Compose | Parte 3: Configuración en Profundidad

Despliegue en Kubernetes

Cuando muevo n8n a un cluster de producción, uso Kubernetes con manifiestos tipo Helm gestionados mediante GitOps. Los siguientes manifiestos asumen que tienes un cluster en ejecución con un controlador de ingress y cert-manager para TLS.

Paso 1: Namespace y Secrets

namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: n8n
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: n8n-secrets
namespace: n8n
type: Opaque
stringData:
postgres-password: "<GENERA_32_CARACTERES_PASSWORD>"
encryption-key: "<GENERA_32_CARACTERES_KEY>"
basic-auth-user: "admin"
basic-auth-password: "<GENERA_24_CARACTERES_PASSWORD>"

Aplica con kubectl apply -f namespace.yaml -f secret.yaml.

Paso 2: PostgreSQL StatefulSet

postgres.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: n8n
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine
env:
- name: POSTGRES_USER
value: "n8n"
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: n8n-secrets
key: postgres-password
- name: POSTGRES_DB
value: "n8n"
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: n8n
spec:
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432

Paso 3: Despliegue de Redis

redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: n8n
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- --appendonly
- "yes"
- --maxmemory
- "256mb"
- --maxmemory-policy
- "allkeys-lru"
ports:
- containerPort: 6379
volumeMounts:
- name: redis-data
mountPath: /data
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: redis-data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: n8n
spec:
selector:
app: redis
ports:
- port: 6379
targetPort: 6379

Paso 4: Despliegue principal de n8n

n8n-main.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n-main
namespace: n8n
spec:
replicas: 1
selector:
matchLabels:
app: n8n-main
template:
metadata:
labels:
app: n8n-main
spec:
containers:
- name: n8n
image: n8nio/n8n:1.50
ports:
- containerPort: 5678
env:
- name: DB_TYPE
value: "postgresdb"
- name: DB_POSTGRESDB_HOST
value: "postgres"
- name: DB_POSTGRESDB_PORT
value: "5432"
- name: DB_POSTGRESDB_DATABASE
value: "n8n"
- name: DB_POSTGRESDB_USER
value: "n8n"
- name: DB_POSTGRESDB_PASSWORD
valueFrom:
secretKeyRef:
name: n8n-secrets
key: postgres-password
- name: EXECUTIONS_MODE
value: "queue"
- name: QUEUE_BULL_REDIS_HOST
value: "redis"
- name: QUEUE_BULL_REDIS_PORT
value: "6379"
- name: N8N_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: n8n-secrets
key: encryption-key
- name: WEBHOOK_URL
value: "https://n8n.tudominio.com/"
- name: GENERIC_TIMEZONE
value: "UTC"
- name: N8N_BASIC_AUTH_ACTIVE
value: "true"
- name: N8N_BASIC_AUTH_USER
valueFrom:
secretKeyRef:
name: n8n-secrets
key: basic-auth-user
- name: N8N_BASIC_AUTH_PASSWORD
valueFrom:
secretKeyRef:
name: n8n-secrets
key: basic-auth-password
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "2000m"
---
apiVersion: v1
kind: Service
metadata:
name: n8n-main
namespace: n8n
spec:
selector:
app: n8n-main
ports:
- port: 5678
targetPort: 5678

Paso 5: Workers de n8n

n8n-worker.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n-worker
namespace: n8n
spec:
replicas: 3
selector:
matchLabels:
app: n8n-worker
template:
metadata:
labels:
app: n8n-worker
spec:
containers:
- name: n8n
image: n8nio/n8n:1.50
command: ["n8n", "worker"]
env:
- name: DB_TYPE
value: "postgresdb"
- name: DB_POSTGRESDB_HOST
value: "postgres"
- name: DB_POSTGRESDB_PASSWORD
valueFrom:
secretKeyRef:
name: n8n-secrets
key: postgres-password
- name: QUEUE_BULL_REDIS_HOST
value: "redis"
- name: QUEUE_BULL_REDIS_PORT
value: "6379"
- name: N8N_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: n8n-secrets
key: encryption-key
- name: GENERIC_TIMEZONE
value: "UTC"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "1000m"

Paso 6: Ingress con TLS

ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: n8n
namespace: n8n
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- n8n.tudominio.com
secretName: n8n-tls
rules:
- host: n8n.tudominio.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: n8n-main
port:
number: 5678

Aplica todos los manifiestos:

Terminal window
kubectl apply -f namespace.yaml -f secret.yaml -f postgres.yaml -f redis.yaml -f n8n-main.yaml -f n8n-worker.yaml -f ingress.yaml

Verifica el despliegue:

Terminal window
kubectl get pods -n n8n
kubectl logs -n n8n deployment/n8n-main | grep "Editor is now accessible"

Seguridad de webhooks

Los webhooks son la superficie más expuesta de cualquier plataforma de automatización. Así es como yo los bloqueo.

Usa un subdominio dedicado para webhooks

Siempre separo el ingress de webhooks de la UI del editor. Si tu instancia principal está en n8n.tudominio.com, ejecuta webhooks en hooks.tudominio.com. Esto te permite aplicar límites de tasa diferentes, reglas de WAF y políticas de autenticación.

Habilita autenticación de webhook

n8n soporta autenticación básica y basada en encabezados en flujos de webhook. Para webhooks de producción, agrego una verificación de encabezado personalizado:

// n8n Nodo Webhook → Headers
{
"X-Webhook-Secret": "{{$env.WEBHOOK_SECRET}}"
}

Guarda WEBHOOK_SECRET en el vault de credenciales de n8n, no en el JSON del flujo de trabajo.

Lista blanca de IPs

Si tus webhooks solo reciben eventos de fuentes conocidas (GitHub, Stripe, etc.), restringe el ingress por IP de origen:

# anotación de nginx ingress
nginx.ingress.kubernetes.io/whitelist-source-range: "192.30.252.0/22, 185.199.108.0/22"

Gestión de credenciales

n8n encripta las credenciales en reposo usando N8N_ENCRYPTION_KEY. Sin embargo, hay capas adicionales que deberías agregar.

CapaImplementaciónRiesgo mitigado
Encriptación en reposoN8N_ENCRYPTION_KEYRobo de base de datos
Encriptación en tránsitoTLS en ingressAtaques man-in-the-middle
Inyección de secretosKubernetes Secrets / Docker SecretsFuga de credenciales en env
Control de acceson8n RBAC + autenticación básicaEdiciones no autorizadas de flujos
Registro de auditoríaRegistros de consulta de PostgreSQLRastreo de acceso a credenciales

Roto la clave de encriptación trimestralmente. Para hacer esto, exporta todos los flujos, destruye el volumen, inicia n8n con una clave nueva y vuelve a importar. Es tedioso pero necesario para entornos de alta seguridad.

Configuración del nodo AI Agent

El nodo AI Agent de n8n te permite construir flujos de trabajo agenticos que pueden llamar herramientas, razonar sobre contexto e interactuar con LLMs. Yo uso esto para construir alertas de infraestructura autocurables y triaje automatizado de tickets.

Conectar con un LLM autohospedado

Si seguiste mi guía de despliegue de Ollama, ya tienes un LLM local en ejecución. Conéctalo a n8n así:

  1. Agrega un nodo HTTP Request o usa el nodo Ollama Chat Model (nodo comunitario).
  2. Establece la URL base a tu instancia de Ollama: http://ollama.ai-serving.svc.cluster.local:11434.
  3. Selecciona el modelo: llama3.1:8b o mistral:7b.
  4. Para el nodo AI Agent, establece el System Message para definir el rol del agente:
Eres un asistente de SRE. Tienes acceso a logs de Kubernetes, estados de despliegue
e historial de alertas. Cuando te pregunten sobre un incidente, resume los síntomas,
sugiere causas raíz y recomienda el siguiente paso de diagnóstico. No ejecutes
comandos sin aprobación explícita.

Flujo básico: Alerta → LLM → Slack

Aquí hay un flujo simple que ejecuto para triaje de alertas de Prometheus:

  1. Webhook Trigger: Recibe el payload de alerta de Alertmanager.
  2. HTTP Request: Obtiene logs recientes de Loki para el servicio afectado.
  3. AI Agent: Resume los logs y sugiere una causa raíz.
  4. Slack: Publica el resumen en #incidents con botones de aprobar/rechazar.
  5. Si se aprueba: Una segunda rama ejecuta un diagnóstico seguro (ej., kubectl get events).

Esto mantiene a los humanos en el bucle mientras se automatiza la reducción de ruido que normalmente agota a los ingenieros de guardia.

Preguntas frecuentes

¿Qué es n8n y qué lo hace diferente de Zapier?

n8n es una plataforma de automatización de flujo de trabajo de código abierto. La diferencia clave con Zapier: todo corre en tu infraestructura. Tus datos nunca tocan servidores de terceros, las credenciales se quedan encriptadas en tu base de datos y no hay límites de uso por plan. Cambié a n8n cuando Zapier cambió su modelo de precios y mi factura de automatización se triplicó de la noche a la mañana.

¿Cómo escalo los workers de n8n en Kubernetes?

Ajusta el campo replicas en el manifiesto Deployment de n8n-worker. Empiezo con 3 réplicas y escalo según la profundidad de la cola de Redis. Monitorea LLEN bull:jobs en Redis; cuando se mantiene por encima de 100 por más de 5 minutos, agrego más workers. Cada worker necesita al menos 256Mi RAM y 250m CPU para flujos básicos.

¿Puedo usar n8n con vLLM en lugar de Ollama?

Sí. Ambos exponen APIs compatibles con OpenAI. Apunta el nodo HTTP Request o el nodo OpenAI Chat Model a la URL de tu servicio vLLM. Uso Ollama para desarrollo y vLLM para producción.

¿Cómo hago backup de n8n en Kubernetes?

Respaldar dos cosas: la base de datos PostgreSQL (pg_dump) y la clave de encriptación. Sin la N8N_ENCRYPTION_KEY, tus credenciales son irrecuperables. Ejecuto pg_dumps nocturnos a almacenamiento S3 y guardo la clave en un vault seguro.

¿Qué es el queue mode y cuándo lo necesito?

El queue mode separa la UI web de los workers de ejecución usando Redis como cola de trabajos. Activo queue mode en cuanto tengo más de 5 flujos activos. Sin él, un solo flujo lento puede bloquear todo el pipeline de ejecución.

¿El nodo AI Agent de n8n está listo para producción?

Para herramientas internas y triaje de alertas, sí. No lo usaría para remediación autónoma en producción sin compuertas de aprobación humana. Siempre mantén a un humano supervisando acciones destructivas como borrar recursos o modificar despliegues.


Partes en esta serie: Parte 1: Configuración con Docker Compose ← | Parte 3: Configuración en Profundidad →

# N8N # ai-automation # workflow # docker # Kubernetes # redis # postgresql # deployment # self-hosted