Despliegue n8n Kubernetes: Manifiestos y Config
Tabla de contenidos
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
apiVersion: v1kind: Namespacemetadata: name: n8napiVersion: v1kind: Secretmetadata: name: n8n-secrets namespace: n8ntype: OpaquestringData: 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
apiVersion: apps/v1kind: StatefulSetmetadata: name: postgres namespace: n8nspec: 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: v1kind: Servicemetadata: name: postgres namespace: n8nspec: selector: app: postgres ports: - port: 5432 targetPort: 5432Paso 3: Despliegue de Redis
apiVersion: apps/v1kind: Deploymentmetadata: name: redis namespace: n8nspec: 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: v1kind: Servicemetadata: name: redis namespace: n8nspec: selector: app: redis ports: - port: 6379 targetPort: 6379Paso 4: Despliegue principal de n8n
apiVersion: apps/v1kind: Deploymentmetadata: name: n8n-main namespace: n8nspec: 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: v1kind: Servicemetadata: name: n8n-main namespace: n8nspec: selector: app: n8n-main ports: - port: 5678 targetPort: 5678Paso 5: Workers de n8n
apiVersion: apps/v1kind: Deploymentmetadata: name: n8n-worker namespace: n8nspec: 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
apiVersion: networking.k8s.io/v1kind: Ingressmetadata: 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: 5678Aplica todos los manifiestos:
kubectl apply -f namespace.yaml -f secret.yaml -f postgres.yaml -f redis.yaml -f n8n-main.yaml -f n8n-worker.yaml -f ingress.yamlVerifica el despliegue:
kubectl get pods -n n8nkubectl 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 ingressnginx.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.
| Capa | Implementación | Riesgo mitigado |
|---|---|---|
| Encriptación en reposo | N8N_ENCRYPTION_KEY | Robo de base de datos |
| Encriptación en tránsito | TLS en ingress | Ataques man-in-the-middle |
| Inyección de secretos | Kubernetes Secrets / Docker Secrets | Fuga de credenciales en env |
| Control de acceso | n8n RBAC + autenticación básica | Ediciones no autorizadas de flujos |
| Registro de auditoría | Registros de consulta de PostgreSQL | Rastreo 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í:
- Agrega un nodo HTTP Request o usa el nodo Ollama Chat Model (nodo comunitario).
- Establece la URL base a tu instancia de Ollama:
http://ollama.ai-serving.svc.cluster.local:11434. - Selecciona el modelo:
llama3.1:8bomistral:7b. - 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 desplieguee 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 ejecutescomandos sin aprobación explícita.Flujo básico: Alerta → LLM → Slack
Aquí hay un flujo simple que ejecuto para triaje de alertas de Prometheus:
- Webhook Trigger: Recibe el payload de alerta de Alertmanager.
- HTTP Request: Obtiene logs recientes de Loki para el servicio afectado.
- AI Agent: Resume los logs y sugiere una causa raíz.
- Slack: Publica el resumen en
#incidentscon botones de aprobar/rechazar. - 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 →