跳到正文
W Winse Blog
automation ops dev 1 min read

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 ,可以在启动时灵活的指定允许列表。 

这次折腾让我又温习了一遍:想顺心,先按官方方式来实现;想自由,那就自己承担这个复杂度。

当然,追求极致极简,是我们程序员的使命。

走不通的时刻,把基础地基夯实了,在它基础上建立高楼才能行稳致远。等高楼的建造方案成熟后,再去优化。

成长之路上,总在稳与狂之间反复摆动。

在 GitHub 上讨论

欢迎通过 GitHub Issue 留言或反馈。每条讨论都会关联到对应文章的源文件路径。

2025-12-29-n8n-终于还是部署到-Docker-了,经验就是要反反复复地去验证:要想少走弯路,就按官方推荐的最佳实践.md

Related posts