1. 架构设计概述
本部署方案采用 n8n 官方推荐的 分布式队列架构 (Queue Mode),并引入了最新的 独立沙盒执行器 (Runners),实现了调度、执行与第三方代码运行的物理隔离,最大程度保障了系统的稳定性、并发能力与安全性。
核心组件说明
- n8n (Main Node): 核心控制平面,负责提供 Web UI、处理 Webhook 入口流量以及任务编排调度。
- n8n-worker (Worker Node): 专属工作节点,从 Redis 队列中认领并执行后台标准工作流,支持水平扩展。
- Runners (Python/JS Sandboxes): 独立沙盒执行器,专门用于执行大模型生成的 Python/JS 代码,防止恶意代码越权访问主机资源。
- PostgreSQL (v16): 核心元数据库,存储工作流定义、凭证加密数据与执行日志。
- Redis (v6): 消息中间件,作为 BullMQ 队列驱动,负责 Main 节点与 Worker 节点之间的任务分发与状态同步。
2. 核心架构亮点与最佳实践
2.1 极度严谨的网络代理策略 (Proxy Anchoring)
利用 Docker Compose 的 YAML 锚点 (&proxy) 功能,实现了代理配置的全局复用。
- 强制指定
HTTP_PROXY与HTTPS_PROXY,确保拉取大模型 API 或外部插件时流量稳定穿透。 - 配置了极其精细的
NO_PROXY白名单,确保集群内部组件 (PostgreSQL, Redis, Runner, 10.0.0.0/8 内网段) 之间的通信绝对直连,避免内网流量被错误路由到代理服务器导致握手失败。
2.2 生产级数据修剪与“防爆盘”策略
通过精细化配置执行日志的保留策略,极大降低了 PostgreSQL 的 I/O 负担,避免因为高频流水分发导致数据库物理存储空间耗尽。
- 成功则静默,失败则记录:
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none/EXECUTIONS_DATA_SAVE_ON_ERROR=all。 - 滚动清理机制: 强制开启数据修剪 (
EXECUTIONS_DATA_PRUNE=true),生命周期严格限制为 7 天 (EXECUTIONS_DATA_MAX_AGE=168)。
2.3 权限最小化与安全隔离
- 数据库降权: 拒绝使用 Root 直连,通过
init-data.sh自动初始化n8n专属业务库及n8n弱权限账号。 - 沙盒认证: 主节点与 Runner 之间使用 24 位强随机哈希串 (
RUNNERS_AUTH_TOKEN) 进行内部鉴权,防止队列被恶意投毒。 - 凭证加密: 核心资产(如 API Keys)在落库前通过专属 16 位哈希串 (
ENCRYPTION_KEY) 进行高强度加密。
3. 环境变量速查表 (.env)
| 变量类别 | 变量名 | 配置建议 / 作用 |
|---|---|---|
| 版本控制 | DB_VERSION | 16.13 (锁定 PG 大版本,保障数据一致性) |
N8N_VERSION | 2.12.1 (拒绝 latest 盲盒,确保集群组件版本对齐) | |
| 基础配置 | WEBHOOK_URL | 必须精确配置为对外网关地址,且末尾必须包含斜杠 /。 |
TZ / GENERIC_TIMEZONE | 统一配置为 Asia/Shanghai,保障 Cron 触发器精确执行。 | |
| 安全凭证 | ENCRYPTION_KEY | 灾备核心:丢失将导致历史凭证全部作废,必须严格备份。 |
RUNNERS_AUTH_TOKEN | 主/从节点间调用的握手暗号。 | |
| 合规与遥测 | N8N_DIAGNOSTICS_ENABLED | false (关闭物理遥测,防止内部拓扑信息外泄) |
N8N_PERSONALIZATION_ENABLED | false (关闭广告与个性化追踪) |
4. 服务依赖与启动顺序
本架构采用严格的 depends_on 与 healthcheck 机制确保启动时序:
- 基础层:
redis与postgres率先启动。 - 校验层: 主控节点 (
n8n) 必须等待 DB 与 Redis 的健康检查 (ping/pg_isready) 通过后才启动初始化。 - 计算层:
n8n-worker与n8n-runner等待主控节点就绪后,接入队列开始消费。
5. 部署文件
5.1 基础环境准备与源码获取
我们采用 n8n 官方提供的 n8n-hosting 仓库作为基座,并在其 withPostgresAndWorker 分布式架构的基础上进行深度定制改造。
第一步:克隆官方部署脚手架 在你的宿主机(如 CentOS/Ubuntu)上执行以下命令,获取官方推荐的目录结构和初始化脚本:
# 克隆官方 hosting 仓库
git clone https://github.com/n8n-io/n8n-hosting.git
# 进入带有 PostgreSQL 和 Worker 的高级分布式架构目录
cd n8n-hosting/docker-compose/withPostgresAndWorker/
# 赋予数据库初始化脚本执行权限(极其重要)
chmod +x init-data.sh
5.2 注入企业级定制配置
官方的默认配置无法满足我们对“极度安全、代理穿透、性能修剪”的要求。我们需要用我们精心调优过的配置来覆盖默认文件。
第二步:配置环境变量 (.env) 在此目录下(withPostgresAndWorker/),备份默认的 .env 文件,并创建我们的定制版:
mv .env .env.bak
vi .env
(在此处粘贴我们之前整理好的、包含 N8N_VERSION=2.12.1、ENCRYPTION_KEY、以及防爆盘策略的完整 .env 文件内容并保存。)
# ==========================================
# 🐳 镜像版本控制 (极其重要,拒绝 latest 盲盒)
# ==========================================
DB_VERSION=16.13
N8N_VERSION=2.12.1
# ==========================================
# 🐘 PostgreSQL 底层安全与权限配置
# ==========================================
# 数据库超级管理员账号 (仅供 init-data.sh 脚本首次建库使用)
POSTGRES_USER=postgres
POSTGRES_PASSWORD=Your_PWD
# n8n 专属业务库名与业务弱权账号 (防止越权操作,必须设置)
POSTGRES_DB=n8n
POSTGRES_NON_ROOT_USER=n8n
POSTGRES_NON_ROOT_PASSWORD=Your_PWD
# ==========================================
# 🔐 n8n 分布式核心安全凭证
# ==========================================
# 灾备生命线:主密钥。用于加密数据库中的第三方系统凭据 (如 GitLab Token、钉钉 AppSecret)。
# ⚠️ 极其重要:务必妥善备份此密钥,丢失将导致所有历史凭据无法解密!
# (可由 openssl rand -hex 16 生成)
ENCRYPTION_KEY=Your_Key
# 沙盒接头暗号:在队列模式下,主节点/工作节点与其对应的执行沙盒 (Runner) 间互相验证身份的唯一凭证。
# (可由 openssl rand -hex 24 生成)
RUNNERS_AUTH_TOKEN=Your_Token
# ==========================================
# 🚀 企业级业务增强与数据修剪策略
# ==========================================
# 允许在非 HTTPS (内网 IP) 环境下登录 n8n 后台
N8N_SECURE_COOKIE=false
# 统一时区:确保 Cron 定时任务精准触发
TZ=Asia/Shanghai
GENERIC_TIMEZONE=Asia/Shanghai
# 全局透出网关地址:向外部系统 (如钉钉/企业微信) 暴露的 Webhook 域名。
# ⚠️ 注意:末尾必须带斜杠 (/)
WEBHOOK_URL=http://192.168.100.103:5678/
# 垃圾数据修剪策略 (防爆盘生命线):
# 仅当任务发生错误时才保存详细日志与 Payload,成功则丢弃,从而极大减轻数据库 I/O 负担。
EXECUTIONS_DATA_SAVE_ON_ERROR=all
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
# 开启滚动清理,保留最近 7 天 (168小时) 的历史流水
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
# 隐私与合规:物理关闭无用的官方遥测数据、控制台广告及个性化推销
N8N_DIAGNOSTICS_ENABLED=false
N8N_PERSONALIZATION_ENABLED=false
N8N_HIRING_BANNER_ENABLED=false
第三步:配置编排文件 (docker-compose.yml) 同样地,备份默认的编排文件,并使用包含网络代理锚点 (&proxy) 和 Runner 沙盒的定制版进行覆盖:
mv docker-compose.yml docker-compose.yml.bak
vi docker-compose.yml
(在此处粘贴我们之前整理好的,包含 x-proxy、x-shared 结构以及全套网络代理透传的完整 docker-compose.yml 文件内容并保存。)
volumes:
db_storage:
n8n_storage:
redis_storage:
# =============================
# 代理统一配置
# =============================
x-proxy: &proxy
NODE_USE_ENV_PROXY: "1"
HTTP_PROXY: http://proxy-host-ip:7890
HTTPS_PROXY: http://proxy-host-ip:7890
http_proxy: http://proxy-host-ip:7890
https_proxy: http://proxy-host-ip:7890
NO_PROXY: localhost,127.0.0.1,postgres,redis,n8n,n8n-worker,n8n-runner,192.168.0.0/16,10.0.0.0/8,.local,.internal
no_proxy: localhost,127.0.0.1,postgres,redis,n8n,n8n-worker,n8n-runner,192.168.0.0/16,10.0.0.0/8,.local,.internal
# =============================
# n8n 主节点 / worker 公共配置
# =============================
x-shared: &shared
restart: always
image: docker.n8n.io/n8nio/n8n:${N8N_VERSION:-latest}
environment:
<<: *proxy
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: ${POSTGRES_DB}
DB_POSTGRESDB_USER: ${POSTGRES_NON_ROOT_USER}
DB_POSTGRESDB_PASSWORD: ${POSTGRES_NON_ROOT_PASSWORD}
EXECUTIONS_MODE: queue
QUEUE_BULL_REDIS_HOST: redis
QUEUE_HEALTH_CHECK_ACTIVE: true
N8N_ENCRYPTION_KEY: ${ENCRYPTION_KEY}
N8N_RUNNERS_MODE: external
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_AUTH_TOKEN}
N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: true
GENERIC_TIMEZONE: ${GENERIC_TIMEZONE}
TZ: ${TZ}
WEBHOOK_URL: ${WEBHOOK_URL}
EXECUTIONS_DATA_SAVE_ON_ERROR: ${EXECUTIONS_DATA_SAVE_ON_ERROR}
EXECUTIONS_DATA_SAVE_ON_SUCCESS: ${EXECUTIONS_DATA_SAVE_ON_SUCCESS}
EXECUTIONS_DATA_PRUNE: ${EXECUTIONS_DATA_PRUNE}
EXECUTIONS_DATA_MAX_AGE: ${EXECUTIONS_DATA_MAX_AGE}
N8N_DIAGNOSTICS_ENABLED: ${N8N_DIAGNOSTICS_ENABLED}
N8N_PERSONALIZATION_ENABLED: ${N8N_PERSONALIZATION_ENABLED}
N8N_HIRING_BANNER_ENABLED: ${N8N_HIRING_BANNER_ENABLED}
N8N_SECURE_COOKIE: ${N8N_SECURE_COOKIE}
# 推荐安装社区的插件
N8N_CUSTOM_EXTENSIONS: n8n-nodes-mcp
volumes:
- n8n_storage:/home/node/.n8n
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
# =============================
# Runner 公共配置
# =============================
x-runner: &runner
restart: always
image: n8nio/runners:${N8N_VERSION:-latest}
environment:
<<: *proxy
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_AUTH_TOKEN}
# =============================
# Services
# =============================
services:
postgres:
image: postgres:${DB_VERSION:-16}
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_NON_ROOT_USER: ${POSTGRES_NON_ROOT_USER}
POSTGRES_NON_ROOT_PASSWORD: ${POSTGRES_NON_ROOT_PASSWORD}
volumes:
- db_storage:/var/lib/postgresql/data
- ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
healthcheck:
test: ['CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
interval: 5s
timeout: 5s
retries: 10
redis:
image: redis:6-alpine
restart: always
volumes:
- redis_storage:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 5s
retries: 10
n8n:
<<: *shared
ports:
- 5678:5678
n8n-worker:
<<: *shared
command: worker
depends_on:
- n8n
n8n-runner:
<<: *runner
environment:
<<: *proxy
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_AUTH_TOKEN}
N8N_RUNNERS_TASK_BROKER_URI: http://n8n:5679
depends_on:
- n8n
n8n-worker-runner:
<<: *runner
environment:
<<: *proxy
N8N_RUNNERS_AUTH_TOKEN: ${RUNNERS_AUTH_TOKEN}
N8N_RUNNERS_TASK_BROKER_URI: http://n8n-worker:5679
depends_on:
- n8n-worker
6. 运维操作手册
集群拉起
docker compose up -d
平滑重启 Worker 节点 (适用于更新自定义配置后)
docker compose restart n8n-worker n8n-worker-runner
查看沙盒执行器日志 (排查 AI 代码执行错误)
docker compose logs -f n8n-runner
一键无感扩容 Worker 节点 (提升并发处理能力)
得益于 Redis 消息队列架构,当面临海量任务或高耗时工作流时,可直接通过 scale 参数水平横向扩容工作节点,无需重启现有集群:
💡 架构师提示:
- 主节点别动:主节点 (
n8n) 负责提供 Web UI 和接收 Webhook,除非配置了前置负载均衡 (如 Nginx/HAProxy),否则保持默认的 1 个实例即可。- 按需扩容:重活、累活全都在
n8n-worker上跑。如果发现排队严重,直接scale扩容 worker;等高峰期过了,再改回--scale n8n-worker=1优雅缩容,绝不浪费服务器资源。- 沙盒扩容:如果你的 AI 代码执行量非常大,同样可以按需扩容执行器:
docker compose up -d --scale n8n-runner=3。
docker compose up -d --scale n8n-runner=3
👑 实战案例 —— 基于 MCP 协议构建 Jenkins AI 助手 (含 SSO 鉴权避坑指南)
本案例记录了如何在 n8n / Dify 等 AI 中控面板中,通过 MCP (Model Context Protocol) 协议接入 Jenkins,并利用 AI Agent 实现自然语言 CI/CD 运维。
1. 安装核心依赖节点
由于 MCP Client 目前并非 n8n 官方内置节点,需要通过社区插件体系引入。
- 操作路径:
Settings->Community nodes - 安装包名:
n8n-nodes-mcp(当前版本 v0.1.37)
2. 构建 Agent 拓扑架构
采用标准的“大脑 + 手脚”分离架构搭建工作流:
- 触发器:添加
When chat message received作为对话入口。 - 核心调度:连接
AI Agent节点。 - 挂载大脑:在
Model锚点接入Google Gemini Chat Model。 - 挂载工具:在
Tool锚点接入刚才安装的MCP Client。
3. 🚨 核心排坑:SSO 环境下的 Jenkins 凭证构造
在开启了统一身份认证 (SSO) 的 Jenkins 环境中,MCP 协议往往会因为鉴权失败而报出 "anonymous is missing the Overall/Read permission" 的错误。 请务必遵循以下**“三步排坑法”**生成标准鉴权头:
坑位一:弄错真实的 User ID
在 SSO 体系下,用户登录的账号名(如 admin 或中文名)往往不是底层的真实 ID。
- 正解:登录 Jenkins 后,点击右上角个人 Profile。观察浏览器地址栏的 URL(例如:
http://192.168.100.103:8080/user/ziming.xing@email.com/)。 - 提取:URL 里的
ziming.xing@email.com才是你真正用于 API 调用的唯一账号。去设置里为该账号生成全新的 API Token。
坑位二:Linux Base64 的隐藏“换行符”陷阱
当你使用 echo 拼接长账号和 Token 时,如果字符串超过 76 个字符,Linux 的 base64 命令会自动折行(插入 \n 换行符),导致 HTTP Header 解析彻底断裂。
-
错误写法:
echo "user:token" | base64 -
完美写法 (必须带 -n 取消末尾换行,以及 -w 0 取消折行):
echo -n "userName@email.com:111c74218db20e7302***********" | base64 -w 0
坑位三:配置到 MCP 节点
拿到上面生成的纯净、单行 Base64 字符串后,在 MCP Client 节点中做如下配置:
- Endpoint:
http://192.168.100.103:8080/mcp-server/mcp - Server Transport:
HTTP Streamable/SSE - Authentication / Headers:
- 添加自定义请求头。
- Key:
Authorization - Value:
Basic emltaW5...你的纯净Base64...(务必注意 Basic 后面保留一个英文空格)
4. 真实对话调用与能力验证
完成鉴权后,点击 Execute step,节点会亮起绿灯,并成功从 Jenkins 侧拉取到 getJobs, triggerBuild, getBuildLog 等多达十几个底层运维工具。
进入 Chat 界面,发起真实指令测试:
- 用户输入:
帮我查一下现在 Jenkins 里有哪些 Job 列表? - Agent 行为分析:
- Gemini 大脑准确理解意图,决定调用 Jenkins MCP 工具链。
- 精准选择并触发了
getJobs方法发起 POST 请求,携带了正确的 Basic Auth 头。 - 服务端响应:HTTP 200 OK,返回真实的 Job 列表 JSON 数据。
- 结果输出:Agent 捕获到数据,并将其转化为清晰的自然语言(中文),在对话框中列出当前环境的所有 CI/CD 流水线。
- 架构结论: 大模型的 Tool Calling 能力、MCP 路由转发,以及企业级 SSO 鉴权通道均已完美打通,成功实现 DevOps 运维闭环!





1895

被折叠的 条评论
为什么被折叠?



