Instalación de n8n en Kubernetes con PostgreSQL y Redis
Clase 12 de 13 • Curso de n8n Self-Hosted para Empresas
Resumen
Instala y ejecuta n8n en Kubernetes con KubeMode, conectándolo a PostgreSQL y Redis para un entorno listo para escalar. Aquí verás cómo crear el clúster con K3D, definir recursos clave como ConfigMap, PVC, Service, Deployment e Ingress, y validar con kubectl que todo queda operativo.
¿Cómo preparar Kubernetes y servicios base?
Primero se valida el entorno local con K3D y kubectl y se crea un clúster mapeando un puerto público al load balancer. Después se despliegan Postgres y Redis con Helm (chart de “Bitnami” en el ejemplo) y se comprueba que los pods están en estado “Running”.
¿Qué comandos iniciales necesitas?
- Verificar versiones con comandos:
k3d version
ykubectl version
. - Crear clúster y exponer puerto:
k3d cluster create demo --port 8080@loadbalancer
. - Ver información del clúster:
kubectl cluster-info
.
# Instalar PostgreSQL con Helm
helm install postgres vitnami/postgres \
--set postgresqlUsername=n8n \
--set postgresqlPassword="mi clave" \
--set postgresqlDatabase=n8n
# Verificar estado de pods
a) kubectl get pods
b) kubectl logs -f
¿Qué datos y puertos son críticos?
- PostgreSQL: puerto 5432, base de datos y usuario: n8n, contraseña: “mi clave”.
- Redis: puerto 6379, listo cuando muestra “ready to accept connections”.
- Mapear 8080 al load balancer del clúster para acceder desde el host.
¿Qué recursos de Kubernetes definen n8n en KubeMode?
La configuración se centraliza en un ConfigMap que expone variables para DB (host, puerto, base y credenciales), Redis y KubeMode. Se añade un PersistentVolumeClaim (PVC) para persistir /home/node/.n8n
. El Service expone solo el pod main en el puerto 5678 usando ClusterIP.
¿Cómo configurar variables con ConfigMap?
- Tipo y conexión de base: host del servicio de Postgres (formato servicio.namespace.svc.cluster.local), puerto 5432, base n8n, usuario n8n, contraseña “mi clave”.
- Conexión a Redis: host del servicio y puerto 6379.
- Modo de ejecución: KubeMode activo para usar worker y main.
- Red en local: N8N_TRUST_PROXY y N8N_PROXY_HOPS habilitados.
- Seguridad: autenticación básica del editor con usuario
admin
y contraseñaadmin
. - Rutas de webhooks: URL base para “test” y “producción”.
# configmap-n8n.yaml (fragmento)
apiVersion: v1
kind: ConfigMap
metadata:
name: n8nconfig
data:
# DB: host/puerto/base/usuario/clave
# Redis: host/puerto
# KubeMode y ajustes de proxy local
# Auth básica y webhooks
¿Cómo persistir datos con PVC y exponer el servicio?
- PVC: solicita almacenamiento y modo de acceso para el directorio de trabajo de n8n.
- Service (main): selecciona
app: n8n
y expone el puerto 5678 como ClusterIP.
# pvc-n8n-data.yaml (fragmento)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: n8n-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
# service-n8n-main.yaml (fragmento)
apiVersion: v1
kind: Service
metadata:
name: n8n-main
spec:
selector:
app: n8n
ports:
- port: 5678
type: ClusterIP
¿Cómo desplegar y verificar con deployments e ingress?
Se crean dos Deployments: uno para worker y otro para main. El worker corre con concurrency=1, lee entorno desde el ConfigMap, define requests/limits (memoria 512Mi/1Gi, CPU 250m/500m) y monta el PVC. Usa liveness y readiness probes por exec
. El main arranca con start
, expone 5678 y define probes HTTP GET a /healthz con delays mayores porque depende de Redis y Postgres.
¿Qué especificaciones clave usa cada deployment?
- Imagen:
n8n:latest
para worker y main. - Worker: argumento
worker
y--concurrency=1
. - Main: endpoint de salud /healthz en 5678 con
httpGet
. - Recursos: requests y limits para memoria y CPU.
- Almacenamiento: montar PVC en
/home/node/.n8n
.
# deployment-n8n-worker.yaml (fragmento)
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n-worker
spec:
replicas: 1
selector:
matchLabels:
app: n8n
role: worker
template:
metadata:
labels:
app: n8n
role: worker
spec:
containers:
- name: n8n-worker
image: n8n:latest
args: ["worker", "--concurrency=1"]
envFrom:
- configMapRef:
name: n8nconfig
resources:
requests: { memory: "512Mi", cpu: "250m" }
limits: { memory: "1Gi", cpu: "500m" }
volumeMounts:
- name: n8n-data
mountPath: /home/node/.n8n
volumes:
- name: n8n-data
persistentVolumeClaim:
claimName: n8n-data
# deployment-n8n-main.yaml (fragmento)
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n-main
spec:
replicas: 1
selector:
matchLabels:
app: n8n
role: main
template:
metadata:
labels:
app: n8n
role: main
spec:
containers:
- name: n8n-main
image: n8n:latest
args: ["start"]
ports:
- containerPort: 5678
readinessProbe:
httpGet: { path: "/healthz", port: 5678 }
initialDelaySeconds: 30
livenessProbe:
httpGet: { path: "/healthz", port: 5678 }
initialDelaySeconds: 30
volumeMounts:
- name: n8n-data
mountPath: /home/node/.n8n
volumes:
- name: n8n-data
persistentVolumeClaim:
claimName: n8n-data
¿Cómo publicar con ingress y aplicar en orden?
- Ingress con Traefik (por defecto en K3D), host
localhost
,path: /
, backendn8n-main:5678
.
# ingress-n8n-localhost.yaml (fragmento)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: n8n
spec:
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: n8n-main
port:
number: 5678
- Aplicar recursos en orden: ConfigMap, PVC, Service, Deployments (primero main, luego worker) e Ingress.
kubectl apply -f configmap-n8n.yaml
kubectl apply -f pvc-n8n-data.yaml
kubectl apply -f service-n8n-main.yaml
kubectl apply -f deployment-n8n-main.yaml
kubectl apply -f deployment-n8n-worker.yaml
kubectl apply -f ingress-n8n-localhost.yaml
- Validar con
kubectl get pods
hasta ver disponibles. Revisar conkubectl logs
el main. Abrir el navegador y completar el registro con correo y contraseña fuerte.
¿Quieres que profundicemos en el autoescalado horizontal en Kubernetes para n8n y sus workers? Cuéntame tu escenario y lo vemos paso a paso.