适用于: IoT Edge 1.1
重要
IoT Edge 1.1 终止支持日期为 2022 年 12 月 13 日。 请查看 Microsoft 产品生命周期,了解此产品、服务、技术或 API 的受支持情况。 有关更新到最新版本的 IoT Edge 的详细信息,请参阅 更新 IoT Edge。
在本文中,我们将创建三个 IoT Edge 模块,这些模块接收来自下游 IoT 设备的消息,通过机器学习模型运行数据,然后将见解转发到 IoT 中心。
IoT Edge 中心促进模块间通信。 使用 IoT Edge 中心作为消息代理使模块彼此独立。 模块只需指定它们接受消息的输入和写入消息的输出。
我们希望 IoT Edge 设备为我们完成四项任务:
- 从下游设备接收数据。
- 预测发送数据的设备的剩余使用寿命(RUL)。
- 将设备的剩余使用寿命(RUL)消息发送到 IoT 中心。 仅当 RUL 低于指定级别时,才能修改此函数以发送数据。
- 将下游设备数据保存到 IoT Edge 设备上的本地文件。 此数据文件会定期上传到 IoT 中心,以优化机器学习模型的训练。 使用文件上传而不是常量消息流式处理更具成本效益。
为了完成这些任务,我们使用三个自定义模块:
RUL 分类器: 我们在 训练和部署 Azure 机器学习模型 创建的 turboFanRulClassifier 模块是一个标准机器学习模块,该模块公开名为“amlInput”的输入和名为“amlOutput”的输出。 “amlInput”要求其输入与我们发送到基于 ACI 的 Web 服务的输入完全一致。 同样,“amlOutput”返回与 Web 服务相同的数据。
Avro 编写器: 此模块接收“avroModuleInput”输入上的消息,并将消息以 Avro 格式保存到磁盘,以便稍后上传到 IoT 中心。
路由器模块: 路由器模块接收来自下游设备的消息,然后将消息格式化并发送到分类器。 然后,该模块从分类器接收消息,并将消息转发到 Avro 编写器模块。 最后,该模块仅将 RUL 预测发送到 IoT 中心。
输入:
- deviceInput:接收来自下游设备的消息
- rulInput: 从“amlOutput”接收消息
输出:
- 分类: 将消息发送到“amlInput”
- writeAvro: 将消息发送到“avroModuleInput”
- toIotHub: 将消息发送到$upstream,它将消息传递到已连接的 IoT 中心
下图显示了完整解决方案的模块、输入、输出和 IoT Edge 中心路由:
本文中的步骤通常由云开发人员执行。
本教程此部分,您将学习如何:
- 从自定义代码创建 IoT Edge 模块。
- 从自定义模块生成 Docker 映像。
- 重新配置 IoT 中心路由以支持自定义模块。
- 生成、发布和部署自定义模块。
先决条件
本文是有关在 IoT Edge 上使用 Azure 机器学习的教程的系列教程的一部分。 本系列中的每个文章都基于上一篇文章中的工作。 如果已直接访问本文,请先查看本系列的 第一篇文章。
创建新的 IoT Edge 解决方案
在执行我们两个 Azure Notebook 中的第二个 Notebook 时,我们创建并发布了一个包含 RUL 模型的容器镜像。 Azure 机器学习作为映像创建过程的一部分打包了该模型,以便将映像部署为 Azure IoT Edge 模块。
在此步骤中,我们将使用“Azure 机器学习”模块创建 Azure IoT Edge 解决方案,并将该模块指向使用 Azure Notebooks 发布的映像。
打开开发虚拟机的远程桌面会话。
在 Visual Studio Code 中打开文件夹 C:\source\IoTEdgeAndMlSample。
右键单击资源管理器面板的空白区域,然后选择 新的 IoT Edge 解决方案。
接受 EdgeSolution的默认解决方案名称。
选择 Azure 机器学习 作为模块模板。
将模块命名为 turbofanRulClassifier。
选择机器学习工作区。 此工作区是在 教程中创建的 turboFanDemo 工作区:训练和部署 Azure 机器学习模型
选择运行 Azure Notebook 时创建的映像。
查看解决方案并注意已创建的文件:
deployment.template.json: 此文件包含解决方案中每个模块的定义。 此文件中需要注意三个部分:
注册表凭据: 定义解决方案中使用的自定义容器注册表集。 现在,它应包含机器学习工作区中的注册表,该工作区是 Azure 机器学习映像的存储位置。 可以拥有任意数量的容器注册表,但为简单起见,我们将将此注册表用于所有模块。
"registryCredentials": { "<your registry>": { "username": "$CONTAINER_REGISTRY_USERNAME_<your registry>", "password": "$CONTAINER_REGISTRY_PASSWORD_<your registry>", "address": "<your registry>.azurecr.io" } }
模块: 本部分包含一组随此解决方案一起使用的用户定义的模块。 turbofanRulClassifier 模块定义指向容器注册表中的映像。 当我们向解决方案添加更多模块时,它们将显示在本节中。
"modules": { "turbofanRulClassifier": { "version": "1.0", "type": "docker", "status": "running", "restartPolicy": "always", "settings": { "image": "turbofandemo2cd74296.azurecr.io/edgemlsample:1", "createOptions": {} } } }
路由: 在本教程中,我们将处理大量的路由。 路由定义模块相互通信的方式。 模板定义的现有路由与我们需要的路由不匹配。 删除
turbofanRulClassifierToIoTHub
路由。"$edgeHub": { "properties.desired": { "schemaVersion": "1.0", "routes": { "turbofanRulClassifierToIoTHub": "FROM /messages/modules/turbofanRulClassifier/outputs/* INTO $upstream" }, "storeAndForwardConfiguration": { "timeToLiveSecs": 7200 } } }
deployment.debug.template.json: 此文件是 deployment.template.json的调试版本。 通常,我们应该将此文件与 deployment.template.json 文件的内容保持同步,但本教程不需要这样做。
.env: 此文件应提供用于访问注册表的用户名和密码。
CONTAINER_REGISTRY_USERNAME_<your registry name>=<ACR username> CONTAINER_REGISTRY_PASSWORD_<your registry name>=<ACR password>
注释
本教程使用 Azure 容器注册表的管理员登录凭据,这对于开发和测试方案非常方便。 为生产方案做好准备后,建议使用最低权限身份验证选项(如服务主体)。 有关详细信息,请参阅管理容器注册表的访问权限。
右键单击 Visual Studio Code 资源管理器中的 deployment.template.json 文件,然后选择 生成 IoT Edge 解决方案。
请注意,此命令使用 deployment.amd64.json 文件创建配置文件夹。 此文件是解决方案的具体部署模板。
添加路由器模块
接下来,我们将路由器模块添加到解决方案。 路由器模块处理解决方案的多个责任:
- 从下游设备接收消息: 当消息从下游设备到达 IoT Edge 设备时,路由器模块接收消息并开始协调消息的路由。
- 将消息发送到 RUL 分类器模块: 从下游设备接收新消息时,路由器模块会将消息转换为 RUL 分类器预期的格式。 路由器将消息发送到 RUL 分类器进行 RUL 预测。 分类器进行预测后,它会将消息发送回路由器模块。
- 将 RUL 消息发送到 IoT 中心:当路由器从分类器接收消息时,它将转换消息以仅包含基本信息、设备 ID 和 RUL,并将缩写的消息发送到 IoT 中心。 此处尚未进一步优化,仅在 RUL 预测低于阈值时(例如,RUL 小于 100 个周期时)才会将消息发送到 IoT 中心。 这样筛选就会减少消息量,降低 IoT 中心的成本。
- 将消息发送到 Avro Writer 模块: 为了保留下游设备发送的所有数据,路由器模块会将从分类器接收到的整个消息发送到 Avro Writer 模块,该模块将使用 IoT Hub 文件上传功能来持久保存和上传数据。
路由器模块是解决方案的一个重要部分,可确保消息按正确的顺序进行处理。
创建模块并复制文件
右键单击 Visual Studio Code 中的模块文件夹,然后选择 添加 IoT Edge 模块。
为模块模板选择 C# 模块。
将模块 命名为 turbofanRouter。
出现 Docker 映像存储库提示时,请使用机器学习工作区中的注册表(可以在 deployment.template.json 文件的 registryCredentials 节点中找到注册表)。 此值是完全限定的注册表地址,例如 <注册表>.azurecr.io/turbofanrouter。
注释
在本文中,我们使用由 Azure 机器学习工作区创建的 Azure 容器注册表。 这纯粹是为了方便起见。 我们本可以创建一个新的容器注册表,并在其中发布模块。
在终端中使用命令提示符 shell 将示例模块中的文件复制到解决方案中。
copy c:\source\IoTEdgeAndMlSample\EdgeModules\modules\turbofanRouter\*.cs c:\source\IoTEdgeAndMlSample\EdgeSolution\modules\turbofanRouter\
接受提示以覆盖“program.cs”文件。
生成路由器模块
在 Visual Studio Code 中,选择 终端>配置默认生成任务。
从模板 中选择创建 tasks.json 文件。
选择 .NET Core。
将 tasks.json 的内容替换为以下代码。
{ "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "shell", "group": { "kind": "build", "isDefault": true }, "args": [ "build", "${workspaceFolder}/modules/turbofanRouter" ], "presentation": { "reveal": "always" }, "problemMatcher": "$msCompile" } ] }
保存并关闭 tasks.json。
使用
Ctrl + Shift + B
或 终端运行构建任务>运行构建任务。
设置模块路由
如上所述,IoT Edge 运行时使用 deployment.template.json 文件中配置的路由来管理松散耦合模块之间的通信。 在本部分中,我们将深入探讨如何为 turbofanRouter 模块设置路由。 我们将首先介绍输入渠道,然后转向输出。
输入
在 Program.cs 的 Init() 方法中,我们注册模块的两个回调:
await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromLeafDevice, LeafDeviceInputMessageHandler, ioTHubModuleClient); await ioTHubModuleClient.SetInputMessageHandlerAsync(EndpointNames.FromClassifier, ClassifierCallbackMessageHandler, ioTHubModuleClient);
第一个回调侦听发送到 deviceInput 接收端的消息。 在上图中,我们看到我们要将消息从任何下游设备路由到此输入。 在 deployment.template.json 文件中,添加一个路由,指示边缘中心将任何不是由 IoT Edge 模块发送的消息,路由到 turbofanRouter 模块中名为“deviceInput”的输入端。
"leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")"
接下来,将来自 rulClassifier 模块的消息路由添加到 turbofanRouter 模块中:
"classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amloutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")"
输出
向 $edgeHub 路由参数添加四个附加路由,以处理路由器模块的输出。
Program.cs定义方法 SendMessageToClassifier(),该方法使用模块客户端使用路由将消息发送到 RUL 分类器:
"routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")"
SendRulMessageToIotHub() 使用模块客户端通过路由仅将设备的 RUL 数据发送到 IoT 中心:
"routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream"
SendMessageToAvroWriter() 使用模块客户端发送消息,并将 RUL 数据添加到 avroFileWriter 模块。
"routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")"
HandleBadMessage() 将失败的消息上游发送到 IoT Hub,在那里它们可以被路由以供日后处理。
"deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
将所有路由组合在一起时,“$edgeHub”节点应类似于以下 JSON:
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
"leafMessagesToRouter": "FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/deviceInput\")",
"classifierToRouter": "FROM /messages/modules/turbofanRulClassifier/outputs/amlOutput INTO BrokeredEndpoint(\"/modules/turbofanRouter/inputs/rulInput\")",
"routerToClassifier": "FROM /messages/modules/turbofanRouter/outputs/classOutput INTO BrokeredEndpoint(\"/modules/turbofanRulClassifier/inputs/amlInput\")",
"routerToIoTHub": "FROM /messages/modules/turboFanRouter/outputs/hubOutput INTO $upstream",
"routerToAvro": "FROM /messages/modules/turbofanRouter/outputs/avroOutput INTO BrokeredEndpoint(\"/modules/avroFileWriter/inputs/avroModuleInput\")",
"deadLetter": "FROM /messages/modules/turboFanRouter/outputs/deadMessages INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 7200
}
}
}
注释
添加 turbofanRouter 模块创建了以下附加路由:turbofanRouterToIoTHub": "FROM /messages/modules/turbofanRouter/outputs/* INTO $upstream
。 删除此路由,只保留上面列出的 deployment.template.json 文件中的路由。
添加 Avro Writer 模块
Avro Writer 模块在我们的解决方案中具有两项职责,用于存储消息和上传文件。
存储消息:当 Avro 编写器模块收到消息时,它会以 Avro 格式将消息写入本地文件系统。 我们使用绑定装载,该装载会将目录(在本例中为 /data/avrofiles)装载到模块容器中的路径中。 此装载允许模块写入本地路径(/avrofiles),并让这些文件直接从 IoT Edge 设备访问。
上传文件:Avro Writer 模块使用 Azure IoT 中心文件上传功能将文件上传到 Azure 存储帐户。 成功上传文件后,模块将从磁盘中删除该文件
创建模块和复制文件
在 Visual Studio Code 中,选择 视图>命令面板,然后搜索并选择 Python:选择解释器。
选择已安装的 Python 版本 3.7 或更高版本。
右键单击 Visual Studio Code 中的模块文件夹,然后选择 添加 IoT Edge 模块。
选择“Python 模块”。
将模块命名为
avroFileWriter
。当系统提示输入 Docker 映像存储库时,请使用添加路由器模块时所用的注册表。
将文件从示例模块复制到解决方案中。
copy C:\source\IoTEdgeAndMlSample\EdgeModules\modules\avroFileWriter\*.py C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avroFileWriter\
请接受对 main.py 的覆盖。
请注意,已将 filemanager.py 和 schema.py 添加到解决方案,并更新了 main.py。
注释
打开 Python 文件时,系统可能会提示你安装 pylint。 无需安装 linter 即可完成本教程。
数据文件的绑定装载
如前所述,写入模块依赖绑定装载,将 Avro 文件写入设备的文件系统。
将目录添加到设备
在 Azure 门户中,启动您的 IoT Edge 设备的虚拟机(如果它未运行)。 使用 SSH 连接到它。 连接需要您可以从 Azure 门户的 VM 概述页面复制的 DNS 名称。
ssh -l <user>@<vm name>.<region>.cloudapp.azure.com
登录后,创建将保存已保存的下游设备消息的目录。
sudo mkdir -p /data/avrofiles
更新目录权限,使其可由容器写入。
sudo chmod ugo+rw /data/avrofiles
验证目录现在是否具有用户、组和所有者的写入权限(w)。
ls -la /data
目录权限
将目录添加到模块
若要将目录添加到模块的容器,我们将修改与 avroFileWriter 模块关联的 Dockerfiles。 有三个 Dockerfile 与模块相关联:Dockerfile.amd64、Dockerfile.amd64.debug 和 Dockerfile.arm32v7。 如果要调试或部署到 arm32 设备,则应保持这些文件同步。 本文仅重点介绍 Dockerfile.amd64。
在开发 VM 上,打开 C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\Dockerfile.amd64 文件。
修改文件,使其如以下示例所示:
FROM ubuntu:xenial WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/* RUN pip3 install --upgrade pip COPY requirements.txt ./ RUN pip install -r requirements.txt COPY . . RUN useradd -ms /bin/bash moduleuser RUN mkdir /avrofiles && chown moduleuser /avrofiles USER moduleuser CMD [ "python3", "-u", "./main.py" ]
mkdir
和chown
命令指示 Docker 生成过程在映像中创建名为 /avrofiles 的顶级目录,然后将模块用户设为该目录的所有者。 请务必在使用useradd
命令将模块用户添加到镜像后,以及在上下文切换为模块用户(USER moduleuser)之前插入这些命令。如果需要,请对 Dockerfile.amd64.debug 和 Dockerfile.arm32v7 进行相应的更改。
将绑定配置添加到 avroFileWriter
创建绑定的最后一步是使用绑定信息更新 deployment.template.json(和 deployment.debug.template.json)文件。
打开 deployment.template.json。
通过添加将容器目录 /avrofiles 指向边缘设备上的本地目录的
Binds
参数来修改 avroFileWriter 的模块定义。 模块定义应与此示例匹配:"avroFileWriter": { "version": "1.0", "type": "docker", "status": "running", "restartPolicy": "always", "settings": { "image": "${MODULES.avroFileWriter}", "createOptions": { "HostConfig": { "Binds": [ "/data/avrofiles:/avrofiles" ] } } } }
绑定挂载以访问 config.yaml
我们需要为编写器模块再添加一个绑定。 此绑定使模块能够从 IoT Edge 设备上的 /etc/iotedge/config.yaml 文件读取连接字符串。 我们需要连接字符串来创建 IoTHubClient,以便我们可以调用 upload_blob_async 方法将文件上传到 IoT 中心。 添加此绑定的步骤类似于上一部分中的步骤。
更新目录权限
使用 SSH 连接到 IoT Edge 设备。
ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
向 config.yaml 文件添加读取权限。
sudo chmod +r /etc/iotedge/config.yaml
验证权限是否已正确设置。
ls -la /etc/iotedge/
确保 config.yaml 的文件权限为 -r--r--r--。
将目录添加到模块
在开发计算机上,打开 Dockerfile.amd64 文件。
向文件添加一组附加的
mkdir
和chown
命令,如下所示:FROM ubuntu:xenial WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends libcurl4-openssl-dev python3-pip libboost-python1.58-dev libpython3-dev && rm -rf /var/lib/apt/lists/\* RUN pip3 install --upgrade pip COPY requirements.txt ./ RUN pip install -r requirements.txt COPY . . RUN useradd -ms /bin/bash moduleuser RUN mkdir /avrofiles && chown moduleuser /avrofiles RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig USER moduleuser CMD "python3", "-u", "./main.py"]
对 Dockerfile.amd64.debug 和 Dockerfile.arm32v7 进行相应的更改。
更新模块配置
打开 deployment.template.json 文件。
修改 avroFileWriter 的模块定义,通过在
Binds
参数中添加第二行,将容器目录(/app/iotconfig)指向设备上的本地目录(/etc/iotedge)。"avroFileWriter": { "version": "1.0", "type": "docker", "status": "running", "restartPolicy": "always", "settings": { "image": "${MODULES.avroFileWriter}", "createOptions": { "HostConfig": { "Binds": [ "/data/avrofiles:/avrofiles", "/etc/iotedge:/app/iotconfig" ] } } } }
对 deployment.debug.template.json进行相应的更改。
安装依赖项
编写器模块依赖于两个 Python 库,fastavro 和 PyYAML。 我们需要在开发计算机上安装依赖项,并指示 Docker 生成过程在模块的映像中安装它们。
PyYAML
在开发计算机上,打开
C:\source\IoTEdgeAndMlSample\EdgeSolution\modules\avoFileWriter\requirements.txt
文件,并在文件的新行上添加“pyyaml”。azure-iothub-device-client~=1.4.3 pyyaml
打开 Dockerfile.amd64 文件,并添加
pip install
命令以升级 setuptools。FROM ubuntu:xenial WORKDIR /app RUN apt-get update && \ apt-get install -y --no-install-recommends libcurl4-openssl-dev python3-pip libboost-python1.58-dev libpython3-dev && \ rm -rf /var/lib/apt/lists/\* RUN pip3 install --upgrade pip RUN pip install -U pip setuptools COPY requirements.txt ./ RUN pip install -r requirements.txt COPY . . RUN useradd -ms /bin/bash moduleuser RUN mkdir /avrofiles && chown moduleuser /avrofiles RUN mkdir -p /app/iotconfig && chown moduleuser /app/iotconfig USER moduleuser CMD [ "python3", "-u", "./main.py" ]
在命令提示符下,将 pyyaml 安装到开发计算机。
pip install pyyaml
Fastavro
在 requirements.txt中,在 pyyaml 后面添加 fastavro。
azure-iothub-device-client~=1.4.3 pyyaml fastavro
将 fastavro 安装到开发计算机。
pip install fastavro
重新配置 IoT 中心
通过将 IoT Edge 设备和模块引入系统,我们已更改了有关将数据发送到中心以及出于什么目的的预期。 我们需要在中心重新配置路由来处理新的现实。
注释
我们在部署模块之前重新配置中心,因为某些中心设置(特别是文件上传)需要正确设置,以便 avroFileWriter 模块正常运行
在 IoT 中心为 RUL 消息设置路由
在路由器和分类器到位后,我们预期只接收包含设备 ID 和设备 RUL 预测的常规消息。 我们希望将 RUL 数据路由到其自己的存储位置,我们可以根据需要监视设备的状态、生成报告和触发警报。 同时,我们希望仍由尚未附加到 IoT Edge 设备的下游设备直接发送的任何设备数据继续路由到当前存储位置。
创建 RUL 消息路由
在 Azure 门户中,导航到 IoT 中心。
在左侧窗格的菜单中,在 中心设置下,选择 消息路由。
在“路由”选项卡上,选择添加 。
将路由命名为[RulMessageRoute]。
选择 在 终结点 选择器右侧添加终结点,然后选择 存储。
在“添加存储终结点”页面上,将终结点命名为 ruldata。
选择「选取容器」。
在 存储帐户 页上,找到在本教程中使用的存储帐户,其名称类似于 iotedgeandml<唯一后缀>。
选择 ruldata 容器,然后单击 选择。
返回 添加存储终结点 页,然后选择 创建 来创建存储终结点。
返回 添加路由 页面后,对于 路由查询,请将
true
替换为以下查询:IS_DEFINED($body.PredictedRul) AND NOT IS_DEFINED($body.OperationalSetting1)
展开“测试”部分,然后展开 消息正文 部分。 将消息正文替换为我们预期消息的示例:
{ "ConnectionDeviceId": "aaLeafDevice_1", "CorrelationId": "b27e97bb-06c5-4553-a064-e9ad59c0fdd3", "PredictedRul": 132.62721409309165, "CycleTime": 64.0 }
选择 测试路由。 如果测试成功,则会看到“消息与查询匹配”。
单击“ 保存”。
更新 turbofanDeviceDataToStorage 路由
我们不想将新的预测数据路由到旧存储位置,因此请更新路由以防止它。
在 IoT 中心 消息路由 页中,选择 路由 选项卡。
选择 turbofanDeviceDataToStorage,或者你为初始设备数据路径指定的任何名称。
将路由查询更新为
IS_DEFINED($body.OperationalSetting1)
展开“测试”部分,然后展开 消息正文 部分。 将消息替换为我们预期消息的一个示例:
{ "Sensor13": 2387.96, "OperationalSetting1": -0.0008, "Sensor6": 21.61, "Sensor11": 47.2, "Sensor9": 9061.45, "Sensor4": 1397.86, "Sensor14": 8140.39, "Sensor18": 2388.0, "Sensor12": 522.87, "Sensor2": 642.42, "Sensor17": 391.0, "OperationalSetting3": 100.0, "Sensor1": 518.67, "OperationalSetting2": 0.0002, "Sensor20": 39.03, "DeviceId": 19.0, "Sensor5": 14.62, "PredictedRul": 212.00132402791962, "Sensor8": 2388.01, "Sensor16": 0.03, "CycleTime": 42.0, "Sensor21": 23.3188, "Sensor15": 8.3773, "Sensor3": 1580.09, "Sensor10": 1.3, "Sensor7": 554.57, "Sensor19": 100.0 }
选择 测试路由。 如果测试成功,则会看到“消息与查询匹配”。
选择 保存。
设置文件上传
配置 IoT 中心文件上传功能,使文件编写器模块能够将文件上传到存储。
在 IoT 中心的左窗格菜单中,在 中心设置下,选择 文件上传。
选择 Azure 存储容器。
从列表中选择存储帐户。
选择以 azureml-blobstore 开头并附加 GUID 的容器,然后单击 选择。
选择 保存。 门户会在保存完成后通知你。
注释
我们不会为本教程启用上传通知,但请参阅 接收文件上传通知,了解有关如何处理文件上传通知的详细信息。
生成、发布和部署模块
完成配置更改后,即可生成映像并将其发布到 Azure 容器注册表。 生成过程使用 deployment.template.json 文件来确定需要生成哪些模块。 每个模块(包括版本)的设置位于模块文件夹中的 module.json 文件中。 构建过程首先在与 module.json 文件中找到的当前配置匹配的 Docker 文件上运行 Docker 构建,以创建镜像。 然后,它将映像从 module.json 文件发布到注册表,其版本标记与 module.json 文件中的版本标记匹配。 最后,它生成特定于配置的部署清单(例如,deployment.amd64.json),我们将部署到 IoT Edge 设备。 IoT Edge 设备从部署清单中读取信息,并基于说明下载模块、配置路由和设置任何所需属性。 此部署方法有两个副作用,你应该注意:
部署滞后时间: 由于 IoT Edge 运行时在开始重新配置之前必须识别其所需属性的更改,因此在部署模块后可能需要一些时间,直到运行时选取它们并开始更新 IoT Edge 设备。
模块版本很重要: 如果使用与上一模块相同的版本标记将模块的新版本发布到容器注册表,运行时将不会下载该模块的新版本。 它会比较本地镜像的版本标签和部署清单中所需镜像的版本标签。 如果这些版本匹配,则运行时不执行任何操作。 因此,每次想要部署新更改时,必须递增模块的版本。 通过更改要更改的模块 module.json 文件中 标记 属性下的 版本 属性来递增版本。 然后生成并发布模块。
{ "$schema-version": "0.0.1", "description": "", "image": { "repository": "<your registry>.azurecr.io/avrofilewriter", "tag": { "version": "0.0.1", "platforms": { "amd64": "./Dockerfile.amd64", "amd64.debug": "./Dockerfile.amd64.debug", "arm32v7": "./Dockerfile.arm32v7" } }, "buildOptions": [] }, "language": "python" }
构建和发布
在开发 VM 上,启动 Docker(如果它未运行)。
在 Visual Studio Code 中,使用命令提示符启动新的终端,并登录到 Azure 容器注册表(ACR)。
可以在 Azure 门户中找到所需的用户名、密码和登录服务器值。 容器注册表名称的格式为“turbofandemo<唯一 ID>”。 在左窗格菜单中的 “设置”下,选择 “访问键” 查看它们。
docker login -u <ACR username> -p <ACR password> <ACR login server>
- 在 Visual Studio Code 中,右键单击 deployment.template.json 并选择 生成和推送 IoT Edge 解决方案。
查看注册表中的模块
生成成功完成后,我们将能够使用 Azure 门户查看已发布的模块。
打开本教程的 Azure 容器注册表。 容器注册表名称的格式为“turbofandemo<唯一 ID>”。
在左窗格菜单中,在 服务下,选择 存储库。
请注意,创建的两个模块(avrofilewriter 和 turbofanrouter)显示为存储库。
选择 turbofanrouter,注意您已发布一个标记为 0.0.1-amd64 的镜像。
将模块部署到 IoT Edge 设备
我们已在解决方案中生成并配置了模块,现在我们将模块部署到 IoT Edge 设备。
在 Visual Studio Code 中,右键单击配置文件夹中的 deployment.amd64.json 文件。
选择 为单个设备创建部署。
请您选择 IoT Edge 设备,aaTurboFanEdgeDevice。
在 Visual Studio Code 资源管理器中刷新 Azure IoT 中心设备面板。 应会看到已部署三个新模块,但尚未运行。
几分钟后再次刷新,你将看到模块正在运行。
中查看正在运行的模块
注释
模块启动并稳定运行状态可能需要几分钟时间。 在此期间,你可能会看到模块在尝试与 IoT Edge 中心模块建立连接时启动和停止。
诊断故障
在本部分中,我们分享了一些方法,用于了解某个或多个模块出现的问题。 通常,可以首先通过 Visual Studio Code 中的状态识别出故障。
识别失败的模块
Visual Studio Code: 查看 Azure IoT 中心设备面板。 如果大多数模块处于正在运行状态但已停止,则需要进一步调查该已停止的模块。 如果所有模块长时间处于停止状态,则可能也表示失败。
Azure 门户: 在门户中导航到你的 IoT 中心,然后查找设备详细信息页(在 IoT Edge 下,深入查看设备),你可能会发现某个模块报告了错误或从未向 IoT 中心报告任何信息。
通过设备进行诊断
通过登录到 IoT Edge 设备(在本例中为 Linux VM),可以访问有关模块状态的大量信息。 我们使用的主要机制是 Docker 命令,可用于检查设备上的容器和映像。
登录到 IoT Edge 设备:
ssh -l <user>@IoTEdge-<extension>.<region>.cloudapp.azure.com
列出所有正在运行的容器。 我们预期会看到每个模块的容器,其中包含与模块对应的名称。 此外,此命令列出了容器(包括版本)的确切映像,以便与预期匹配。 还可以通过在命令中将“container”替换为“image”来列出镜像。
sudo docker container ls
获取容器的日志。 此命令输出容器中已写入 StdErr 和 StdOut 的任何内容。 此命令适用于已启动并因某种原因而停止的容器。 此外,这也有助于了解 edgeAgent 或 edgeHub 容器正在发生的情况。
sudo docker container logs <container id>
检查容器。 此命令提供大量有关图像的信息。 可以根据要查找的内容筛选数据。 例如,如果要查看 avroFileWriter 上的绑定是否正确,可以使用以下命令:
sudo docker container inspect -f "{{ json .Mounts }}" avroFileWriter | python -m json.tool
连接到正在运行的容器。 如果要在容器运行时检查容器,此命令非常有用:
sudo docker exec -it avroFileWriter bash
清理资源
本教程是一组的一部分,其中每篇文章都基于上一篇文章中完成的工作。 请等待清理所有资源,直到完成最终教程。
后续步骤
在本文中,我们在 Visual Studio Code 中创建一个 IoT Edge 解决方案,其中包含三个模块:分类器、路由器和文件编写器/上传程序。 我们设置了路由,以允许模块在边缘设备上相互通信。 我们修改了边缘设备的配置,并更新了 Dockerfiles,以安装依赖项并将绑定挂载添加到模块的容器中。
接下来,我们更新了 IoT 中心的配置,以便根据类型路由消息,并处理文件上传。 一切准备就绪后,我们已将模块部署到 IoT Edge 设备,并确保模块正常运行。
继续阅读下一篇文章,开始发送数据并查看解决方案。