任务运行器#
任务运行器(task runners)是一种通用机制,用于以安全且高性能的方式执行任务。它们被用来在 代码节点(Code node) 中执行用户提供的 JavaScript 和 Python 代码。
测试中
对原生 Python 的任务运行器支持以及
n8nio/runners镜像目前处于测试阶段(beta)。在该功能稳定之前,你必须使用环境变量N8N_NATIVE_PYTHON_RUNNER=true来启用 Python 运行器。
本文档介绍任务运行器的工作原理以及如何配置它们。
工作原理#
任务运行器功能由以下组件构成:一个或多个任务运行器(task runners)、一个任务代理(task broker)和一个任务请求者(task requester)。
任务运行器通过 WebSocket 连接与任务代理建立连接。任务请求者将任务请求提交给代理,随后可用的任务运行器会从中获取任务并执行。
运行器执行完任务后,将结果返回给任务请求者。任务代理负责协调运行器与请求者之间的通信。
n8n 实例(主进程和工作进程)充当代理角色,而此处的“代码节点”则作为任务请求者。
任务运行器模式#
你可以以两种不同模式使用任务运行器:内部模式 和 外部模式。
内部模式#
在内部模式下,n8n 实例会将任务运行器作为一个子进程启动。n8n 主进程负责监控并管理任务运行器的生命周期。任务运行器进程与 n8n 共享相同的 uid 和 gid。这种模式不推荐用于生产环境。
外部模式#
在外部模式下,一个启动程序应用(launcher application) 按需启动任务运行器,并管理其生命周期。通常这意味着你需要在 n8n 旁边添加一个独立的边车容器(sidecar container),运行包含 launcher、JS 任务运行器和 Python 任务运行器的 n8nio/runners 镜像。这个边车容器与 n8n 实例相互独立。
当使用 队列模式(Queue mode) 时,每个工作进程都需要拥有自己的边车容器来运行任务运行器。
此外,如果你未启用将手动执行卸载到工作进程的功能(即没有在配置中设置 OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true),那么你的主实例将负责运行手动执行流程,因此也需要配备自己的边车容器。请注意,在生产环境中不建议关闭此卸载功能。
配置外部模式#
在外部模式下,你需要将 n8nio/runners 镜像作为边车容器与 n8n 一同运行。以下提供了一个 Docker Compose 示例供参考。请注意:n8nio/runners 镜像的版本必须与 n8nio/n8n 镜像版本保持一致,且 n8n 版本必须 ≥1.111.0。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28| ``` services: n8n: image: n8nio/n8n:1.111.0 container_name: n8n-main environment:
- N8N_RUNNERS_ENABLED=true
- N8N_RUNNERS_MODE=external
- N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
- N8N_RUNNERS_AUTH_TOKEN=your-secret-here
- N8N_NATIVE_PYTHON_RUNNER=true ports:
- "5678:5678" volumes:
- n8n_data:/home/node/.n8n
等等。
task-runners:
image: n8nio/runners:1.111.0
container_name: n8n-runners
environment:
- N8N_RUNNERS_TASK_BROKER_URI=http://n8n-main:5679
- N8N_RUNNERS_AUTH_TOKEN=your-secret-here
# 等等
depends_on:
- n8n
volumes:
n8n_data:---|---
在外部模式下配置 n8n 容器#
以下是在以外部模式运行的 n8n 容器中可设置的主要环境变量:
| 环境变量 | 说明 |
|---|---|
N8N_RUNNERS_ENABLED=true | 启用任务运行器(task runners)。 |
N8N_RUNNERS_MODE=external | 使用外部模式的任务运行器。 |
N8N_RUNNERS_AUTH_TOKEN=<random secure shared secret> | 任务运行器用于连接到任务代理(broker)的共享密钥。 |
N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0 | 默认情况下,任务代理仅监听本地回环地址(localhost)。当使用多个容器时(例如通过 Docker Compose),需要使其能够接受外部连接。 |
完整环境变量列表请参见 任务运行器环境变量文档。
在外部模式下配置 runners 容器#
以下是在以外部模式运行的 runners 容器中可设置的主要环境变量:
| 环境变量 | 说明 |
|---|---|
N8N_RUNNERS_AUTH_TOKEN=<random secure shared secret> | 任务运行器用于连接到代理服务器的共享密钥。 |
N8N_RUNNERS_TASK_BROKER_URI=localhost:5679 | n8n 实例内部任务代理服务器的地址。 |
N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT=15 | 在关闭任务运行器进程前等待的无活动秒数。当有新任务需要执行时,启动器(launcher)将自动重新启动该运行器。设为 0 可禁用自动关机功能。 |
完整环境变量列表请参见 任务运行器环境变量文档。
在外部模式下配置 runners 容器中的启动器(launcher)#
启动器会从 runners 容器的环境变量中读取配置,并根据位于容器内 /etc/task-runners.json 路径的 默认启动器配置文件 将其传递给每个运行器。默认的启动器配置文件是锁定的,但你可能需要编辑此文件,例如添加第一方或第三方模块到允许列表(allowlist)。要自定义启动器配置文件,请挂载以下路径:
1| ``` path/to/n8n-task-runners.json:/etc/n8n-task-runners.json
---|---
有关启动器配置文件的更多信息,请参见 此处。
## 添加额外依赖项#
你可以自定义 `n8nio/runners` 镜像。为此,你可以在 n8n 仓库的 该目录 中找到 runners 的 Dockerfile。下文提到的清单文件也位于此目录中。
为了在 Code 节点中使用额外的包,你可以在构建时将这些包集成到自定义的 runners 镜像中:
* JavaScript:编辑 `docker/images/runners/package.json`(用于在 JS runner 中安装仅运行时依赖的 package.json 清单)
* Python (Native):编辑 `docker/images/runners/extras.txt`(以 requirements.txt 格式列出并安装到 Python runner 的 venv 中)
> 重要提示:出于安全考虑,任何外部库都必须显式允许才能在 Code 节点中使用。请更新 `n8n-task-runners.json` 文件,将你添加的包加入白名单(allowlist)。
### 1) JavaScript 包#
编辑运行时扩展清单文件 `docker/images/runners/package.json`:1 2 3 4 5 6 7 8
| ```
{
"name":"task-runner-runtime-extras",
"description":"JS task-runner 镜像的仅运行时依赖,在镜像构建时安装。",
"private":true,
"dependencies":{
"moment":"2.30.1"
}
}---|---
在 "dependencies" 下添加你需要的任意包(建议固定版本以确保可复现性),例如:
1
2
3
4| ``` "dependencies":{ "moment":"2.30.1", "uuid":"9.0.0" }
---|---
### 2) Python 包#
编辑依赖要求文件 `docker/images/runners/extras.txt`:1 2 3 4
| ```
# Python task runner 的仅运行时扩展(在镜像构建时安装)
numpy==2.3.2
# 可继续添加,每行一个,例如:
# pandas==2.2.2---|---
请固定版本号(如 ==2.3.2),以确保构建结果具有确定性(deterministic builds)。
3) 为 Code 节点设置包白名单#
打开 docker/images/runners/n8n-task-runners.json 文件,并将你的包添加到环境变量覆盖(env overrides)中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19| ``` { "task-runners":[ { "runner-type":"javascript", "env-overrides":{ "NODE_FUNCTION_ALLOW_BUILTIN":"crypto", "NODE_FUNCTION_ALLOW_EXTERNAL":"moment,uuid",// <-- 在此处添加 JS 包 } }, { "runner-type":"python", "env-overrides":{ "PYTHONPATH":"/opt/runners/task-runner-python", "N8N_RUNNERS_STDLIB_ALLOW":"json", "N8N_RUNNERS_EXTERNAL_ALLOW":"numpy,pandas"// <-- 在此处添加 Python 包 } } ] }
---|---
NODE_FUNCTION_ALLOW_BUILTIN:允许的 Node.js 内置模块列表,以逗号分隔。NODE_FUNCTION_ALLOW_EXTERNAL:允许的 JavaScript 包列表,以逗号分隔。N8N_RUNNERS_STDLIB_ALLOW:允许的 Python 标准库包列表,以逗号分隔。N8N_RUNNERS_EXTERNAL_ALLOW:允许的 Python 包列表,以逗号分隔。
4) 构建你的自定义镜像#
例如,从 n8n 仓库根目录执行:
1
2
3
4| ```
docker
\
---|---
### 5) 运行它#
例如:1 2 3 4 5 6
| ```
docker\
N8N_RUNNERS_AUTH_TOKEN=test\
N8N_RUNNERS_LAUNCHER_LOG_LEVEL=debug\
N8N_RUNNERS_TASK_BROKER_URI=http://host.docker.internal:5679\
5680:5680\---|---