Docker是目前流行的一种容器技术,支持开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或者Windows机器上,也可以实现虚拟化。Docker完全使用沙箱机制,相互之间不会有任何接口,几乎没有性能开销,可以很容易地在机器和数据中心运行。最重要的是,Docker不依赖于任何语言、框架或操作系统。
在Docker中安装Node-RED,后续可以方便地无缝移植到其他设备(包括云端设备)。这也成为广大Node-RED开发者首选的安装方式。截至2022年11月,Node-RED被安装在Docker中的次数已经超过2.3亿(见图2-15)。这是Node-RED创始人Nick O'Leary在2022年Node-RED全球大会上发布的惊人数据。
本节假定你对Docker和Docker命令行有一定的了解,介绍了Node-RED在Docker下运行的多种方式,并且支持多种架构(amd64、arm32v6、arm32v7、arm64v8和s390x)。
图2-15 Nick O'Leary发布在2022年Node-RED被安装在Docker中的次数
注意:
从Node-RED 1.0开始,Docker Hub上的存储库已重命名为nodered/node-red。
要以最简单的形式在Docker中运行,只需执行以下命令:
命令解析如下。
● docker run:运行此容器。
●-it:终端会话,方便查看运行数据。
●-p 1880:1880:Node-RED访问的本地端口。
●-v node_red_data:/data:挂载一个名为node_red_data的容器到/data目录。
●--name mynodered:Node-RED服务的别名。
● nodered/node-red:Node-RED镜像的版本号为3.0.2。
运行该命令应该会出现一个终端窗口,其中包含正在运行的Node-RED实例,示例如下:
这样做的好处是通过给该镜像一个名字(mynodered)可以实现更容易的操作,并且通过指定端口,让我们知道访问的地址。当服务启动以后,我们可以通过组合键“Ctrl+P”来分离终端。终端分离后,容器将继续在后台运行。要重新连接到终端(以查看日志记录),可运行以下命令:
如果你需要重新启动容器(例如,在重新启动Docker守护程序之后),可运行以下命令:
并在需要时再次停止它:
Node-RED镜像基于官方Node.js Alpine Linux镜像。使用Alpine Linux镜像可减小构建Node-RED镜像的大小,但会删除本机模块编译所需的标准依赖项。此时,如果要添加其他依赖的模块,请在正在运行的容器上单独安装这些模块或构建新镜像。
例如:假设你的容器是具有ARM 32 v7as架构的Raspberry Pi 3B,只需运行以下命令来拉取镜像(名称为1.2.0-10-arm32v7),然后运行容器,具体如下:
上述命令用于在Docker容器中运行最新版本的Node-RED。指令和参数说明如下。
● docker run:运行Docker容器。
●-it:以交互方式运行容器,绑定标准输入和终端。
●-p 1880:1880:将容器的端口1880映射到主机的端口1880,允许通过主机访问Node-RED。
●-v node_red_data:/data:将名为node_red_data的Docker卷挂载到容器的/data目录,用于持久化存储Node-RED的数据。
●--name mynodered:为容器指定名称为mynodered。
● nodered/node-red:latest:要运行的Node-RED Docker镜像的名称和标签(latest表示最新版本)。
相同的命令可在amd 64系统上运行,因为Docker发现它可在amd 64主机上运行并拉取相匹配的镜像(1.2.0-10-amd64)。这样做的好处是你不需要知道或指定正在运行的架构,而是使用docker run命令和docker compose命令完成跨系统的运行。
当然,你也可以指定完整的镜像名称进行启动,例如:
上述命令说明和参数含义如下。
● docker run:运行Docker容器。
●-it:以交互方式运行容器,绑定标准输入和终端。
●-p 1880:1880:将容器的端口1880映射到主机的端口1880,允许通过主机访问Node-RED。
●-v node_red_data:/data:将名为node_red_data的Docker卷挂载到容器的/data目录,用于持久化存储Node-RED的数据。
●--name mynodered:为容器指定名称为mynodered。
● nodered/node-red:1.2.0-10-arm32v6:要运行的Node-RED Docker镜像的名称和版本。
一旦让Node-RED与Docker一起运行,我们需要确保在容器被销毁时用户数据(任何添加的节点或流)不会丢失。可以通过将数据目录挂载到容器外部的卷来持久保存用户数据。这可以通过绑定安装或命名数据卷来完成。Node-RED使用容器的/data目录来存储用户配置数据。
要将容器内的Node-RED用户目录保存到容器外的主机目录,可以使用以下命令。要允许访问此主机目录,容器内的node-red用户(默认uid=1000)必须与主机目录的所有者有相同的UID。
在此示例中,主机/home/pi/.node-red目录绑定到容器的/data目录。
注意:
从Node-RED 0.20版迁移到1.0版的用户需要确保任何现有/data目录都有正确的所有权。从Node-RED 1.0开始,可以通过命令sudo chown-R 1000:1000强制赋予UID=1000的用户读取权限,其中UID为1000为容器内Node-RED用户的ID。
Docker还支持使用命名数据卷,在容器外存储持久化数据或共享数据。
以下命令用于创建Docker卷并在容器中运行Node-RED。
上述命令说明如下。
● docker volume create--name node_red_data:创建名为node_red_data的Docker卷,用于持久化存储Node-RED的数据。
● docker volume ls:列出所有的Docker卷,以确认node_red_data卷已经创建成功。
● docker run-it-p 1880:1880-v node_red_data:/data--name mynodered nodered/node-red:在容器中运行Node-RED,并将node_red_data卷挂载到容器的/data目录,以实现数据的持久化存储。同时,将容器的端口1880映射到主机的端口1880,允许通过主机访问Node-RED。容器的名称被指定为mynodered。
如果你需要从已安装的卷中备份数据,你可以在容器运行时访问它,命令如下:
现在,我们可以销毁容器并启动新实例,而不会丢失用户数据,命令如下:
随着新版本发布,Node-RED镜像需要保持更新。由于/data目录现在保存在容器外部,因此更新基础容器镜像非常简单。可以使用以下命令完成Node-RED镜像更新。
有时用本地目录中的文件填充Node-RED Docker镜像可能很有用(例如,如果你希望将整个项目保存在Git存储库中)。比如,本地目录结构如下所示。
注意:
如果你想在外部挂载/data卷,此方法不适用。如果你需要使用外部卷进行持久化,可将你的设置和流文件复制到该卷。
以下Dockerfile构建在基本Node-RED Docker镜像之上,同时将你自己的文件移动到该镜像中:
注意:
package.json文件必须在脚本部分包含启动选项。默认容器设置如下:
为了提高Docker构建速度,我们可以选择提前执行类似COPY package、npm install的操作,因为尽管flows.json文件在Node-RED中工作时会被经常更改,但package.json文件只有在更改项目中的模块时才会更改。由于package.json文件有变化时执行npm install命令会很耗时,因此最好在Dockerfile中尽早执行耗时且通常不会更改的步骤,以便可以重用这些步骤来构建镜像,从而使后续的整体构建速度更快。
当然,你永远不想在任何地方硬编码安全凭证,所以如果需要在Node-RED项目中使用安全凭证,可以在Dockerfile的settings.js文件中进行如下配置:
当在Docker中运行时,你可以将一个环境变量添加到run命令中:
Docker Compose用来实现多容器控制,对Docker集群快速编排,以轻松、高效地管理容器。Docker Stack用于解决大规模部署和管理服务。
有了Docker Compose,你可以把所有繁杂的Docker操作全用命令自动化完成。Docker Compose文件通常位于项目根目录中,并且文件名为docker-compose.yml。这是默认的命名,用于定义和配置Docker容器的组合和运行方式。注意,项目可能有不同的名称或组织结构,因此docker-compose.yml文件的位置可能会有所不同。你如果无法在项目根目录中找到docker-compose.yml文件,可以尝试搜索项目子目录或与项目相关的其他位置。下面是Docker Compose文件的示例。该文件可以由Docker Stack或Docker Compose来运行。有关Docker Stack和Docker Compose的更多信息,请参阅Docker的官方网址:https://docs.docker.com/compose/、https://docs.docker.com/engine/reference/commandline/stack/。
上述文件作用如下。
● 创建一个Node-RED服务。
● 拉取最新的Node-RED镜像。
● 将时区设置为欧洲/阿姆斯特丹。
● 将容器端口1880映射到主机端口1880。
● 创建一个node-red-net网络并将容器链接到该网络。
● 将容器内/data目录持久化到Docker中的node-red-data卷。
Dockerfile的构建命令如下:
●-t your-image-name:your-tag:指定构建的镜像名称和标签,你可以根据需要自定义名称和标签。
●.:表示当前目录,这是Dockerfile所在的位置。
请确保在包含Dockerfile的目录中执行此命令,并将your-image-name替换为你想指定的镜像名称,将your-tag替换为你想指定的镜像标签。执行该命令后,Docker将根据Dockerfile中的指令构建镜像。
在Docker中启动Node-RED的命令如下,包括指定凭证、端口、数据目录、镜像名称:
启动命令包含了一些参数。它们可以直接修改Node-RED的运行环境来达到不同的Node-RED启动效果和需求(比如指定流程配置文件)。流程配置文件是使用环境参数(FLOWS)设置的。该参数默认值为flows.json,可以在运行时使用以下命令进行更改。
注意:
如果设置-e FLOWS="",则可以通过文件中的flowFile属性设置settings.js流文件。
其他有用的环境变量如下。
●-e NODE_RED_ENABLE_SAFE_MODE=false#设置为true,表示以安全模式启动Node-RED。
●-e NODE_RED_ENABLE_PROJECTS=false #设置为true,表示启动Node-RED并启用项目功能。
●-e NODE_OPTIONS将Node.js运行时参数传递给容器。要修复Node.js垃圾收集器使用的堆大小,你可以使用以下命令:
可以将Node-RED镜像设置为后台运行。后台运行只需将参数-it替换为-d,例如:
一旦Node-RED镜像在后台运行,你可以使用以下命令重新访问容器。
此时,在容器内使用npm命令,如果要退出,则使用exit命令。
刷新浏览器页面,现在应该会在节点面板中显示新添加的节点。
运行Node-RED实例:
上述命令将在本地运行一个新的Node-RED实例。注意:此时没有指定实例名称。
这个容器将有一个ID号并在一个随机端口上运行。要找出是哪个端口,可运行docker ps命令:
上述命令用于列出正在运行的容器。执行结果如下:
执行结果显示容器的相关信息,包括容器ID、镜像、命令、创建时间、状态和端口映射等。在示例中,容器ID为860258cab092,镜像为nodered/node-red,命令为"npm start----user...",状态为Up,端口映射为0.0.0.0:32768->1880/tcp,容器名称为dazzling_euler。
注意,只有正在运行的容器才会显示在输出中。如果没有显示任何容器,说明当前没有正在运行的容器,此时访问http://{host ip}:32768就可以进入Node-RED系统实例,通过这个方式可以进入多个Node-RED系统,因为它们使用不同的端口。
你可以使用Docker用户定义的网桥(https://docs.docker.com/network/bridge/)在Docker运行时内部链接容器。
在使用网桥之前,需要创建它。下面的命令将创建一个名为iot的网桥:
然后,所有需要通信的容器都需要使用--network命令行选项添加到同一个网桥,如将一个MQTT协议的网络嫁接到容器中名为iot的网桥:
然后运行nodered docker,也添加到同一个网桥iot:
同一个用户定义的桥上的容器可以利用桥提供的内置名称解析,并使用容器名称(--name选项指定)作为目标主机名。在上面的示例中,可以使用主机名mybroker从Node-RED应用程序访问代理。
比如,Node-RED的MQTT节点中就可以配置MQTT Server地址为mybroker,不用担心内部代理暴露在Docker之外,如图2-16所示。
图2-16 Node-RED中对MQTT节点重新命名MQTT Server名称
树莓派的Node-RED也可以通过Docker来安装。在这种安装环境下,Node-RED要使用树莓派的GPIO,就需要安装扩展节点node-red-node-pi-gpiod。节点安装方法参见2.10节。
使用node-red-node-pi-gpiod可以从单个Node-RED容器与多个Raspberry Pi的GPIO进行交互,并且多个容器可以访问同一个树莓派上的不同GPIO。
要访问主机串行端口,你可能需要将容器添加到dialout组中。这可以通过添加--group-add dialout到启动命令来完成,例如:
如果要从容器内的主机访问设备(例如串行端口),请使用以下命令行来传递访问权限。