在Docker中运行Node-RED
本指南假定你对Docker和 Docker命令行 已有基本了解。它介绍在Docker中运行Node-RED的多种方式,并支持多种架构:amd64、arm32v6、arm32v7、arm64v8和s390x。
从Node-RED 1.0开始,Docker Hub 上的仓库更名为 nodered/node-red。
快速开始
最简单的Docker运行方式是执行:
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实例。
Welcome to Node-RED
===================
10 Oct 12:57:10 - [info] Node-RED version: v1.2.0
10 Oct 12:57:10 - [info] Node.js version: v10.22.1
10 Oct 12:57:10 - [info] Linux 4.19.76-linuxkit x64 LE
10 Oct 12:57:11 - [info] Loading palette nodes
10 Oct 12:57:16 - [info] Settings file : /data/settings.js
10 Oct 12:57:16 - [info] Context store : 'default' [module=memory]
10 Oct 12:57:16 - [info] User directory : /data
10 Oct 12:57:16 - [warn] Projects disabled : editorTheme.projects.enabled=false
10 Oct 12:57:16 - [info] Flows file : /data/flows.json
10 Oct 12:57:16 - [info] Creating new flow file
10 Oct 12:57:17 - [warn]
---------------------------------------------------------------------
Your flow credentials file is encrypted using a system-generated key.
If the system-generated key is lost for any reason, your credentials
file will not be recoverable, you will have to delete it and re-enter
your credentials.
You should set your own key using the 'credentialSecret' option in
your settings file. Node-RED will then re-encrypt your credentials
file using your chosen key the next time you deploy a change.
---------------------------------------------------------------------
10 Oct 12:57:17 - [info] Starting flows
10 Oct 12:57:17 - [info] Started flows
10 Oct 12:57:17 - [info] Server now running at http://127.0.0.1:1880/
[...]
随后可在浏览器访问 http://{host-ip}:1880,打开熟悉的Node-RED界面。
这样做的优势在于,给实例命名为 mynodered,操作起来更方便;固定宿主机端口也使访问地址明确。当然,这意味着一次只能运行一个实例。我们先一步一步来。
如果运行结果符合预期,可以按 Ctrl-p、Ctrl-q 脱离终端,容器会继续在后台运行。
要重新连接终端查看日志,运行:
docker attach mynodered
如果需要重新启动容器,例如系统或Docker守护进程重启后,运行:
docker start mynodered
需要时再次停止容器:
docker stop mynodered
镜像变体
Node-RED镜像基于 官方Node.js Alpine Linux镜像,以尽量缩小体积。使用Alpine Linux减小了镜像,但也移除了编译原生模块需要的标准依赖。如果要添加具有原生依赖的模块,可以在运行中的容器安装缺少的软件包,或扩展Node-RED镜像构建新镜像。见 docker-custom,它扩展了Node-RED Docker项目中的 README.md。
详细镜像、标签和清单信息见 GitHub项目README。
例如,你运行的是采用 arm32v7 架构的Raspberry Pi 3B,只需运行下面命令拉取镜像(标签为 1.2.0-10-arm32v7)并启动容器。
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red:latest
同一命令也可在amd64系统上使用,因为Docker会检测宿主机的amd64架构,拉取标签匹配的镜像 1.2.0-10-amd64。
这样不必知道或指定正在使用的架构,使docker run命令和docker compose文件更灵活,也更便于在不同系统之间共享。
注意:原文所述的Docker架构检测存在一个针对 arm32v6 的问题,例如Raspberry Pi Zero或1。对这些设备,原文要求指定完整镜像标签,例如:
docker run -it -p 1880:1880 -v node_red_data:/data --name mynodered nodered/node-red:1.2.0-10-arm32v6
从Node-RED v3.1.0开始,我们还提供基于Debian的镜像,适用于包含原生组件、在Alpine上工作不佳的节点。
管理用户数据
在Docker中运行Node-RED后,需要确保容器销毁时添加的节点和流程不会丢失。将数据目录挂载到容器外的卷,可以持久保存用户数据。可以使用绑定挂载,也可以使用具名数据卷。
Node-RED使用容器内的 /data 目录保存用户配置数据。
使用宿主机目录持久化(绑定挂载)
要将容器内的Node-RED用户目录保存到容器外的宿主机目录,可以使用下面命令。为允许访问此目录,容器内Node-RED用户的uid(默认1000)必须与宿主机目录所有者的uid相同。
docker run -it -p 1880:1880 -v /home/pi/.node-red:/data --name mynodered nodered/node-red
此例将宿主机目录 /home/pi/.node-red 绑定到容器目录 /data。
注意:从0.20迁移到1.0的用户,需要确保已有 /data 目录的所有权正确。从1.0开始,所有者应为 1000:1000,可以使用命令 sudo chown -R 1000:1000 path/to/your/node-red/data 强制设置。
权限详情见 Wiki。
使用具名数据卷
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官方的 Docker stack 和 Docker compose 文档。
################################################################################
# Node-RED Stack or Compose
################################################################################
# docker stack deploy node-red --compose-file docker-compose-node-red.yml
# 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网络,将容器连接到该网络。 - 将容器内
/data目录持久保存到Docker的node-red-data卷。
复制本地资源的Dockerfile
有时需要用本地目录中的文件填充Node-RED Docker镜像,例如希望把整个项目保存在git仓库中。这时,本地目录应类似:
Dockerfile
README.md
package.json # add any extra nodes your flow needs into your own package.json.
flows.json # the normal place Node-RED store your flows
flows_cred.json # credentials your flows may need
settings.js # your settings file
注意:此方法不适合将 /data 卷挂载到外部的情况。如果需要外部卷进行持久化,应把设置与流程文件复制到该卷中。
下面的Dockerfile以基础Node-RED Docker镜像为起点,并将你的文件放到镜像中的对应位置:
FROM nodered/node-red
# Copy package.json to the WORKDIR so npm builds all
# of your added nodes modules for Node-RED
WORKDIR /data
COPY package.json /data
RUN npm install --no-update-notifier --no-fund --only=production
WORKDIR /usr/src/node-red
# Copy _your_ Node-RED project files into place
# NOTE: This will only work if you DO NOT later mount /data as an external volume.
# If you need to use an external volume for persistence then
# copy your settings and flows files to that volume instead.
COPY settings.js /data/settings.js
COPY flows_cred.json /data/flows_cred.json
COPY flows.json /data/flows.json
注意:package.json 文件的scripts部分必须包含start选项。例如默认容器如下:
"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 后执行的 npm install 有时耗时较长,将这种通常不变、耗时的步骤放在Dockerfile前面,可重用对应构建层,使后续整体构建更快。
凭据、秘密与环境变量
你当然不希望在任何地方硬编码凭据。如果Node-RED项目需要凭据,上面的Dockerfile允许在 settings.js 中这样写:
module.exports = {
credentialSecret: process.env.NODE_RED_CREDENTIAL_SECRET // add exactly this
}
然后在Docker运行时,给 run 命令增加环境变量:
docker run -e "NODE_RED_CREDENTIAL_SECRET=your_secret_goes_here"
构建与运行
按通常方式构建此Dockerfile:
docker build -t your-image-name:your-tag .
本地开发时,如果希望修改立即写入当前本地工作目录,先用 cd 进入项目目录,再运行:
docker run --rm -e "NODE_RED_CREDENTIAL_SECRET=your_secret_goes_here" -p 1880:1880 -v `pwd`:/data --name a-container-name your-image-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
注意:设置 -e FLOWS="" 后,可以通过 settings.js 文件的 flowFile 属性指定流程文件。
其他有用的环境变量包括:
-e NODE_RED_ENABLE_SAFE_MODE=false:设为true时,以安全模式启动Node-RED,不运行流程。-e NODE_RED_ENABLE_PROJECTS=false:设为true时,启用项目功能。
Node.js运行时参数可以通过环境参数 NODE_OPTIONS 传入容器。例如,要固定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 install命令,例如:
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
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
860258cab092 nodered/node-red "npm start -- --user…" 10 seconds ago Up 9 seconds 0.0.0.0:32768->1880/tcp dazzling_euler
现在可以在浏览器访问宿主机上返回的TCP端口。上例访问 http://{host 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
除非希望让外部访问,否则不必全局暴露1883端口;下面会使用内部通信。
接着启动Node-RED Docker容器,并加入同一桥接网络:
docker run -itd -p 1880:1880 --network iot --name mynodered nodered/node-red
同一用户定义桥接网络中的容器,可以使用网络内置的名称解析,将通过 –name 指定的容器名称作为目标主机名。
上例中,Node-RED应用可使用主机名 mybroker 访问代理。
下面的简单流程展示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 等选项。
Raspberry Pi原生GPIO支持
| v1.0重大变更:已移除Raspberry Pi原生GPIO支持 |
|---|
原生GPIO的替代方案是 node-red-node-pi-gpiod。
原生GPIO支持的不足包括:
- Docker容器必须部署在要控制GPIO的同一Docker节点或宿主机上。
- 需要访问Docker节点或宿主机的
/dev/mem。 docker stack命令不支持privileged=true。
node-red-node-pi-gpiod 解决这些问题。借助它,一个Node-RED容器可以与多个Raspberry Pi的GPIO交互,也可以让多个容器访问同一Pi上的不同GPIO。
迁移到 node-red-node-pi-gpiod 的简要步骤
- 通过Node-RED调色板安装
node-red-node-pi-gpiod。 - 在宿主Pi上安装并运行
PiGPIOd daemon。详细安装方法见该模块的 README。 - 将所有原生GPIO节点替换为
pi gpiod节点。 - 配置
pi gpiod节点连接PiGPIOd daemon。宿主机通常使用IP地址172.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。
如果打开文件或访问宿主机设备时出现 permission denied 错误,原文建议尝试以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
参考资料: https://groups.google.com/forum/#!topic/node-red/ieo5IVFAo2o
原文:Running under Docker,Node-RED项目。中文译文。原文与示例由Node-RED项目维护;来源仓库采用 Apache License 2.0。文中的版本号、日志和命令示例保留原文范围。











暂无评论内容