本指南假设你对Docker和Docker命令行有基本的了解。它描述了Node-RED在Docker下运行的多种方式,并支持多种架构(amd64, arm32v6, arm32v7, arm64v8 和 s390x)。
注意: 从Node-RED 1.0开始,Docker Hub上的仓库名称已被更改为 nodered/node-red
。
快速开始
要在Docker中运行Node-RED,请执行以下命令:
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red
这个命令的解释:
docker run
:运行容器。-it
:连接终端会话,以便我们能够查看输出。-p 1880:1880
:将本地端口1880连接到容器内部暴露的1880端口。-v node_red_data:/data
:将名为node_red_data
的Docker卷挂载到容器的/data
目录,以持久化流程的更改。--name mynodered
:为这个容器指定一个友好的名称。nodered/node-red
:基于当前的Node-RED v1.2.0镜像。
运行此命令后,你会看到一个终端窗口显示Node-RED的运行实例。
你可以通过浏览器访问 http://{host-ip}:1880
来打开Node-RED的界面。
命名容器为“mynodered”可以更方便地管理它。此命令只能运行一个实例,但我们可以一步步来。
如果你觉得没问题,你可以使用 Ctrl-pCtrl-q
组合键来分离终端,而容器将在后台继续运行。
要重新连接到终端,请运行:
docker attach mynodered
如果需要重新启动容器(例如,重启后):
docker start mynodered
需要停止时执行:
docker stop mynodered
镜像版本
Node-RED的镜像基于官方的Node.js Alpine Linux镜像,以保持尽可能小的体积。但这意味着一些用于原生模块编译的标准依赖项被移除了。若你需要添加原生依赖,可以查看Node-RED Docker项目的README.md中有关docker-custom的部分。
具体的镜像、标签和Manifest信息,请查阅GitHub项目的README。
例如,如果你在Raspberry PI 3B(架构为arm32v7)上运行,只需执行以下命令来拉取并运行容器:
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red:latest
Docker会根据运行的主机环境自动选择匹配的镜像标签。
但要注意,Docker的某些架构检测存在缺陷,例如Raspberry Pi Zero或1的arm32v6。对于这些设备,你需要明确指定镜像标签:
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red:1.2.0-10-arm32v6
管理用户数据
运行Node-RED后,我们需要确保添加的节点或流程数据不会在容器被销毁时丢失。这可以通过将容器内的数据目录挂载到容器外部的卷来实现。
要将Node-RED的用户目录保存到容器外部的主机目录,例如/home/pi/.node-red
,可以使用:
docker run -it -p 1880:1880 -v /home/pi/.node-red:/data --name mynodered nodered/node-red
请注意,从0.20升级到1.0版本的用户需要确保已有的/data
目录拥有正确的权限,这通常是1000:1000。可以使用以下命令来调整:
sudo chown -R 1000:1000 /path/to/your/node-red/data
更多关于权限的详细信息,请参考官方文档。
使用命名数据卷
Docker还支持使用命名数据卷在容器外部存储持久化或共享数据。若要创建一个新的命名数据卷来保存用户数据,并使用此卷运行新的容器,可以这样操作:
# 创建一个新的命名数据卷
$ docker volume create --name node_red_data
# 显示当前所有的数据卷
$ docker volume ls
# 输出
DRIVER VOLUME NAME
local node_red_data
# 使用该数据卷运行新的容器
$ docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red
若要备份从挂载的数据卷中的数据,您可以在容器运行时这样操作:
# 从运行的容器中备份数据到指定的目录
$ docker cp mynodered:/data /your/backup/directory
使用Node-RED创建并部署了一些示例流程后,您可以销毁容器并启动一个新的实例,而不会丢失用户数据:
$ docker stop mynodered
$ docker rm mynodered
$ docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red
更新
由于 /data
现在是在容器外部保存的,所以更新基础容器镜像变得非常简单:
$ docker pull nodered/node-red
$ docker stop mynodered
$ docker rm mynodered
$ docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red
Docker Stack / Docker Compose
以下是一个Docker Compose文件示例,您可以使用docker stack
或docker-compose
来运行它。更多关于Docker stack和Docker compose的信息,请参考官方Docker文档。
# Node-RED Stack 或 Compose
# 使用docker stack部署
# docker stack deploy node-red --compose-file docker-compose-node-red.yml
# 使用docker-compose启动
# docker-compose -f docker-compose-node-red.yml -p myNoderedProject up
version: "3.7"
services:
node-red:
image: nodered/node-red:latest
environment:
- TZ=Europe/Amsterdam
ports:
- "1880:1880"
networks:
- node-red-net
volumes:
- node-red-data:/data
volumes:
node-red-data:
networks:
node-red-net:
以上的compose文件:
- 创建了一个node-red服务
- 使用最新的node-red镜像
- 设置时区为Europe/Amsterdam
- 将容器的1880端口映射到主机的1880端口
- 创建了一个node-red-net网络,并将容器连接到这个网络
- 将容器内部的目录持久化到Docker卷node-red-data
有时,您可能希望使用Dockerfile将本地资源复制到Node-RED Docker镜像中(例如,如果您希望整个项目保存在git仓库中)。为此,您需要使本地目录如下所示:
Dockerfile
README.md
package.json # 在你自己的package.json中添加流程所需的任何额外节点。
flows.json # Node-RED保存您的流程的正常位置
flows_cred.json # 您的流程可能需要的凭证
settings.js # 您的设置文件
注意:如果您希望将/data卷外部挂载,此方法不适用。如果您需要使用外部卷进行持久化存储,请将您的设置和流程文件复制到该卷。
以下的Dockerfile基于基本的Node-RED Docker镜像,但还将您自己的文件放到该镜像中:
FROM nodered/node-red
# 将package.json复制到工作目录,以便npm为Node-RED构建所有已添加的节点模块
COPY package.json .
RUN npm install --unsafe-perm --no-update-notifier --no-fund --only=production
# 将您的Node-RED项目文件复制到适当的位置
# 注意:只有在您后面不将/data作为外部卷挂载时,这样做才有效。
# 如果需要使用外部卷进行持久化,则将设置和流文件复制到该卷。
COPY settings.js /data/settings.js
COPY flows_cred.json /data/flows_cred.json
COPY flows.json /data/flows.json
# 您应该通过您的package.json文件添加额外的节点,但您也可以在此处添加它们:
# WORKDIR /usr/src/node-red
# RUN npm install node-red-node-smooth
注意:package.json
文件必须在脚本部分中包含一个启动选项。例如,默认容器如下:
"scripts": {
"start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS",
...
}
Dockerfile顺序和构建速度
虽然不是必需的,但最好早点执行COPY package... npm install...
步骤,因为尽管在Node-RED中工作时flows.json
经常发生变化,但package.json
只有在项目模块变化时才会发生变化。由于更改package.json
时需要执行的步骤有时可能会消耗很长时间,因此最好在Dockerfile中尽早执行那些时间消耗较大的、通常不会改变的步骤,这样那些构建镜像可以被重用,从而使后续的整体构建更快。
凭证、密钥和环境变量
当然
,您永远不应该在任何地方硬编码凭证。例如,如果您需要在Node-RED项目中使用密钥,则上述Dockerfile允许您在settings.js
中这样做:
module.exports = {
credentialSecret: process.env.NODE_RED_CREDENTIAL_SECRET
};
然后,当您在Docker中运行它时,您可以添加一个环境变量到运行命令中:
docker run -e "NODE_RED_CREDENTIAL_SECRET=您的密钥内容"
构建和运行
正常地构建这个Dockerfile:
docker build -t 您的镜像名:您的标签 .
为了进行本地开发,并确保任何更改都可以立即被应用,只需从您正在工作的本地目录中进入项目目录,然后执行:
docker run --rm -e "NODE_RED_CREDENTIAL_SECRET=您的密钥内容" -p 1880:1880 -v `pwd`:/data --name 您的容器名 您的镜像名
启动
可以将环境变量传递到容器中,以配置Node-RED的运行时。
使用环境参数(FLOWS)设置流配置文件,默认为‘flows.json’。您可以使用以下命令行标志在运行时更改它:
docker run -it -p 1880:1880 -v node_red_data:/data -e FLOWS=my_flows.json nodered/node-red
注意:如果您设置了FLOWS=""
,那么可以通过settings.js
文件中的flowFile
属性来设置流文件。
还有其他一些有用的环境变量,例如:
-e NODE_RED_ENABLE_SAFE_MODE=false # 设为true则在安全模式(不运行)下启动Node-RED
-e NODE_RED_ENABLE_PROJECTS=false # 设为true则启动支持项目功能的Node-RED
您可以使用环境参数(NODE_OPTIONS)将Node.js运行时参数传递到容器。例如,要固定Node.js垃圾回收器使用的堆大小,您可以使用以下命令:
docker run -it -p 1880:1880 -v node_red_data:/data -e NODE_OPTIONS="--max_old_space_size=128" nodered/node-red
无头运行
要在后台(即无头)运行,只需在大多数先前的命令中将-it
替换为-d
,例如:
docker run -d -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red
容器Shell
一旦以无头方式运行,您可以使用以下命令重新进入容器:
$ docker exec -it mynodered /bin/bash
bash-4.4$
这将在容器内部给出一个命令行,您可以运行您想要的npm安装命令,例如:
bash-4.4$ npm install node-red-dashboard
bash-4.4$ exit
$ docker stop mynodered
$ docker start mynodered
刷新浏览器页面应该会在调色板中显示新添加的节点。
多个实例
运行:
docker run -d -p 1880 nodered/node-red
将在本地创建一个运行实例。注意:我们没有指定一个名称。
此容器将有一个ID号并在一个随机端口上运行…要找出哪个端口,请运行docker ps
。
$ docker ps
您现在可以指向在返回的tcp端口上的主机机器,所以在上面的示例中浏览http://{主机ip}:32768。
连接容器
您可以使用Docker用户定义的桥接器在docker运行时“内部”连接容器。
使用桥接器之前,需要创建它。以下命令将创建一个名为iot
的新桥:
docker network create iot
然后,需要使用--network
命令行选项将所有需要通信的容器添加到同一个桥上:
docker run -itd --network iot --name mybroker eclipse-mosquitto mosquitto -c /mosquitto-no-auth.conf
然后运行nodered docker,也添加到同一个桥上:
docker run -itd -p 1880:1880 --network iot --name mynodered nodered/node-red
在同一个用户定义的桥上的容器可以利用桥提供的内置名称解析,并使用--name
选项指定的容器名称作为目标主机名。
在上面的示例中,可以使用主机名mybroker
从Node-RED应用程序访问代理。
然后,一个简单的流,如下所示,显示了连接到代理的mqtt节点:
[{"id":"c51cbf73.d90738","type":"mqtt in","z":"3fa278ec.8cbaf","name":"","topic":"test","broker":"5673f1d5.dd5f1","x":290,"y":240,"wires":[["7781c73.639b8b8"]]},{"id":"7008d6ef.b6ee38","type":"mqtt out","z":"3fa278ec.8cbaf","name":"","topic":"test","qos":"","retain":"","broker":"5673f1d5.dd5f1","x":517,"y":131,"wires":[]},{"id":"ef5b970c.7c864","type":"inject","z":"3fa278ec.8cbaf","name":"","repeat":"","crontab":"","once":false,"topic":"","payload":"","payloadType":"date","x":290,"y":153,"wires":[["7008d6ef.b6ee38"]]},{"id":"7781c73.639b8b8","type":"debug","z":"3fa278ec.8cbaf","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":505,"y":257,"wires":[]},{"id":"5673f1d5.dd5f1","type":"mqtt-broker","z":"","name":"","broker":"mybroker","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"15","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","closeTopic":"","closeRetain":"false","closePayload":"","willTopic":"","willQos":"0","willRetain":"false","willPayload":""}]
这样,内部代理就不会暴露在docker主机之外了 - 当然,如果您希望您的计算机之外的其他系统能够使用代理,您可以在代理运行命令中添加-p 1883:1883
。
树莓派 - 原生GPIO支持
| v1.0 - BREAKING: 树莓派的原生GPIO支持已被弃用 | | — | 替代原生GPIO的是node-red-node-pi-gpiod
。
原生GPIO支持的缺点是:
- 您的Docker容器需要部署在您希望控制gpio的同一个Docker节点/主机上。
- 访问您的Docker节点/主机的/dev/mem。
privileged=true
对于docker stack
命令不受支持。
node-red-node-pi-gpiod
修复了所有这些缺点。它可以从单个Node-RED容器与多个树莓派的gpio进行交互,并且多个容器可以在同一个Pi上访问不同的gpio。
快速迁移到node-red-node-pi-gpiod
- 通过Node-RED调色板安装
node-red-node-pi-gpiod
。 - 在主机Pi上安装并运行。有关详细的安装说明,请参阅README。
- 使用
pi gpiod
节点替换所有原生gpio节点。 - 将节点配置为连接到
pi gpiod
。通常,主机机器将有一个IP172.17.0.1
端口8888
,但并不总是这样。您可以使用以下命令来检查:
docker exec -it mynodered ip route show default | awk '/default/ {print $3}'
注意:有一个名为gpiod
的贡献项目,如果需要,可以在其自己的容器中运行gpiod
,而不是在主机上。
串行端口 - Dialout - 添加组
如果您需要访问主机的串行端口,可能需要将容器添加到对应的组中。这可以通过在启动命令中添加相应的参数来实现。例如,dialout --group-add dialout
:
docker run -it -p 1880:1880 -v node_red_data:/data --group-add dialout --name mynodered nodered/node-red
常见问题和建议
以下是用户报告的常见问题及可能的解决方案列表:
- 用户权限错误
查看wiki以获取关于权限的详细信息。
如果您在打开文件或访问主机设备时看到“权限被拒绝”的错误,请尝试以root用户身份运行容器。
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered -u node-red:dialout nodered/node-red
参考资料:
- https://github.com/node-red/node-red-docker/issues/15
- https://github.com/node-red/node-red-docker/issues/8
- 访问主机设备
如果您希望从容器内部访问主机的某个设备,例如串行端口,请使用以下命令行标志来传递访问权限。
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered --device=/dev/ttyACM0 nodered/node-red
参考资料:https://github.com/node-red/node-red/issues/15
- 设置时区
如果您想要修改默认时区,请使用TZ
环境变量并提供相应的时区。
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered -e TZ=America/New_York nodered/node-red
或者在docker-compose文件中:
node-red:
environment:
- TZ=America/New_York
您必须登录才能发表评论。