Article
n8n 终于还是部署到 Docker 了,经验就是要反反复复地去验证:要想少走弯路,就按官方推荐的最佳实践
n8n 更新到 2.x 之后,Task Runner 把执行环境从主线程里拆了出去,尤其对 Python 的支持,理论上,可以随心所欲的写 Python、添加依赖,跑外部工具。
我最初设想:飞书发一个视频链接 -> n8n 下载视频 -> 提取字幕 -> 处理完后飞书通知我,听起来完全在 n8n 的能力覆盖范围。真正开始做,才发现这是典型的“看起来很顺畅,跑起来贼折腾”的艰辛之旅。

一、为什么放弃在手机上折腾,找回 Docker
一开始我是在手机跑的,简单流程验证一下就跑通的还行,简单的 Python Code 节点也很快能跑通。但问题很快就找上门了:手机一旦息屏,性能就直线断崖式下坠,任务就无休止的转圈圈了。
当然这不是 n8n 的问题,是运行环境本身不稳定。不一直插着充电,CPU被限制、系统后台不可控,这些都直接影响任务的执行。
忍无可忍立马切换,还是先在电脑上把完整流程跑稳定,再考虑迁移部署到手机上。
当前,用 Windows + Docker Desktop 是当前试错成本最低、变量最可控的方式。
二、先跑通官方 Task Runner:一次只做一件事
在真正增加依赖之前,先不改动,按照官方的配置在 Task Runner 里把 Python Code 节点真长的跑起来。
-
打开官网,查看 Task runners 的部署配置,重点理解它的原理架构,然后再去摸索具体实现的步骤。
-
直接用SQLite,不引入额外的复杂度。
-
直接用官方推荐的 docker-compose 范式。
-
然后问问 AI:已经用了sqlite,升级使用Task runners,给出具体的可实操的方法步骤。
-
最后再结合一些网络实践博文。
Task Runner 的实质就是:n8n 只服务负责调度,Runner 负责执行,task broker 是二者之间的桥梁,通过它来进行通信。
心中已有丘壑,接下来就是卷起袖子一个字干。
在 Windows 系统装 Docker Desktop, 然后 Cursor 新建一个 n8n 的工程,编写 docker-compose.yml。
先把 Task runners 的 Hello World 跑起来,能运行 Python Code 节点。数据直接用从手机上拷贝过来的,做一个数据卷。然后配置任务代理 task broker 的环境变量。

启动之后,在 Docker 查看容器的状态和日志,确定服务都正常启动。

然后,打开 localhost:5678,添加一个 Code in Python 节点,运行后就看到如下的返回结果了。

按照官方的推荐的方式运行,还是很容易和简单的。docker compose 一运行,嘎嘎顺,就跑起来了,Python Code节点立马就能获取到返回结果。
当然,此时 Code 运行是受约束的,如调用系统的库,就会抛出安全错误。

感觉一直在路上,又一直在走回头路。次次头铁次次青。如果想顺心,就按官方提供的,一样的方式,一样的版本去使用操作。
三、进阶:系统依赖和外部库
接下来就进入深水区了。
1、官方 Runner 镜像的限制
下载视频我们需要用到 yt-dlp,同时依赖还要安装 ffmpeg。而 n8n 官方太热心,把镜像中的系统软件管理工具 apk 也给删掉了。

当然这不是疏忽,而是刻意的:可以减少体积,限制执行环境能力,降低安全风险。
2、安装依赖
与 AI 探讨后,最终参考官方 Dockerfile 的 runtime 阶段。使用两个阶段构建,把官方 runners 源镜像的程序拷贝到 python-alpine 镜像内,然后再安装我们需要依赖 ffmpeg、yt-dlp。
基于官方镜像行为安全可控,依赖打包一次性的固化在镜像中复用。

四、Allowlist:容易忽视的坑
安装了自己的依赖包,还不能在 Code 节点中使用。
Task Runner默认启用了严格包运行列表(allowlist),默认是空值,禁止所有的外部依赖。就算依赖包已经安装,只要不在列表里面,Python Code节点也就会拒绝。

官网文档里面是直接改 n8n-task-runners.json,这里并不推荐这么做。这个任务启动配置文件是要打包到镜像的!
我们修改为支持通过环境变量传入 allowlist,在容器启动是配置,而不是写死的镜像,这样更加灵活一点。
先把源文件下载下来,放到 runners 目录下,然后在这个基础上修改。

把镜像 image 修改为 build,指定到修改后的 runners 构建目录,同时把容许列表设置为 *,在 Code 节点中容许使用所有 python 的包,等正式运行时再收紧约束范围。

这样改动小,而且镜像稳定,策略灵活可变。
五、验证结果:一切竟在掌控
然后,就是运行 docker compose up -d --build 构建。

现在查看 python 版本就可以获取到了。

查看 yt_dlp 的版本也正常。

到此,终于有了一个稳定高效的开发环境了。
六、再想
我们简单的过了一遍在 Windows 使用 Docker 部署 n8n 2.1.4,自定义镜像构建脚本添加我们需要的 python 和系统程序的依赖,通过容器环境变量设置 allowlist ,可以在启动时灵活的指定允许列表。
这次折腾让我又温习了一遍:想顺心,先按官方方式来实现;想自由,那就自己承担这个复杂度。
当然,追求极致极简,是我们程序员的使命。
走不通的时刻,把基础地基夯实了,在它基础上建立高楼才能行稳致远。等高楼的建造方案成熟后,再去优化。
成长之路上,总在稳与狂之间反复摆动。
Related
Related posts
-
无需 Docker:n8n 2.x internal 模式下 Python Task Runner 配置实践
2025-12-25
-
杀鸡焉用牛刀:DuckDB 正取代部分 Spark 场景
2026-02-16
-
被 n8n 任务 60s 超时反复折磨后的排查记录:从报错、堆栈到源码,理清 TASK_TIMEOUT 的真实用途与位置
2026-01-10
-
跟着 n8n 案例来学习子流程 Sub-workflow
2025-12-31