教程:使用 Linux 容器开发 IoT Edge 模块

适用于:“是”图标 IoT Edge 1.1 “是”图标 IoT Edge 1.2

使用 Visual Studio Code 开发代码并将其部署到运行 IoT Edge 的设备。

在快速入门中,你已创建了 IoT Edge 设备,并部署了来自 Azure 市场的模块。 本教程逐步介绍如何开发自己的代码并将其部署到 IoT Edge 设备。 本文是学习其他教程的有用先决条件,其他教程将更详细地介绍特定编程语言或 Azure 服务。

本教程使用 将 C# 模块部署到 Linux 设备 的示例。 之所以选择此示例,是因为它是 IoT Edge 解决方案中最常见的开发人员方案。 即使你计划使用其他语言或部署 Azure 服务,本教程仍然有助于了解开发工具和概念。 阅读开发过程的介绍,然后选择偏好的语言或 Azure 服务来深入了解细节。

在本教程中,你将了解如何执行以下操作:

  • 设置开发计算机。
  • 使用适用于 Visual Studio Code 的 IoT Edge Tools 创建新项目。
  • 将项目作为容器生成并将其存储在 Azure 容器注册表中。
  • 将代码部署到 IoT Edge 设备。

先决条件

开发计算机:

  • 可以使用自己的计算机或虚拟机,具体取决于开发首选项。
    • 请确保开发计算机支持嵌套虚拟化。 此功能对于运行容器引擎是必需的,你将在下一部分中安装。
  • 大多数可以运行容器引擎的操作系统都可用于为 Linux 设备开发 IoT Edge 模块。 本教程使用 Windows 计算机,但指出 macOS 或 Linux 上的已知差异。
  • 安装 Git,以便在本教程稍后部分拉取模块模板包。
  • 适用于 Visual Studio Code 的 C# 扩展(由 OmniSharp 提供支持)
  • .NET Core 2.1 SDK

Azure IoT Edge 设备:

  • 我们建议不要在开发计算机上运行 IoT Edge,而应使用单独的设备。 开发计算机和 IoT Edge 设备之间的这一区分可更准确地反映真实部署方案,并有助于区分不同的概念。
  • 如果没有第二台可用的设备,请按照快速入门文章的说明在 Azure 中使用 Linux 虚拟机创建 IoT Edge 设备。

云资源:

如果没有 Azure 订阅,可在开始前创建一个试用帐户

关键概念

本教程详细介绍如何开发 IoT Edge 模块。 IoT Edge 模块有时简称模块,它是一个包含可执行代码的容器 。 可以将一个或多个模块部署到 IoT Edge 设备。 模块执行特定的任务,例如,从传感器引入数据、清理和分析数据,或者将消息发送到 IoT 中心。 有关详细信息,请参阅了解 Azure IoT Edge 模块

开发 IoT Edge 模块时,了解开发计算机和最终将部署模块的目标 IoT Edge 设备之间的差异非常重要。 为保存模块代码而生成的容器必须与 目标设备 的操作系统 (OS) 匹配。 例如,最常见的方案是在 Windows 计算机上开发面向运行 IoT Edge 的 Linux 设备的模块。 在这种情况下,容器操作系统将为 Linux。 在学习本教程的过程中,请记住 开发计算机 OS容器 OS 之间的差异。

提示

如果使用的是 IoT Edge for Linux on Windows,则方案中的“目标设备”是 Linux 虚拟机,而不是 Windows 主机。

本教程针对使用 Linux 容器运行 IoT Edge 的设备。 只要开发计算机可以运行 Linux 容器,就可以使用首选操作系统。 我们建议通过 Linux 容器使用 Visual Studio Code 进行开发,因此这就是本教程将要使用的工具。 还可以使用 Visual Studio,但这两个工具提供的支持存在差异。

下表列出了 Visual Studio Code 和 Visual Studio 支持的 Linux 容器 开发方案。

Visual Studio Code Visual Studio 2017/2019
Linux 设备体系结构 Linux AMD64
Linux ARM32
Linux AMD64
Linux ARM32
Azure 服务 Azure Functions
Azure 流分析
Azure 机器学习
语言 C
C#
Java
Node.js
Python
C
C#
详细信息 适用于 Visual Studio Code 的 Azure IoT Edge 适用于 Visual Studio 2017 的 Azure IoT Edge Tools
适用于 Visual Studio 2019 的 Azure IoT Edge 工具

备注

公共预览版中提供对 Linux ARM64 设备的支持。 有关详细信息,请参阅在 Visual Studio Code(预览版)中开发和调试 ARM64 IoT Edge 模块

本教程讲解适用于 Visual Studio Code 的开发步骤。 如果想要使用 Visual Studio,请参阅使用 Visual Studio 2019 为 Azure IoT Edge 开发和调试模块中的说明。

安装容器引擎

IoT Edge 模块被打包为容器,因此,需要在开发计算机上安装容器引擎来生成和管理容器。 Docker Desktop 提供广泛的功能支持且非常流行,因此我们建议使用它进行开发。 使用 Windows 上的 Docker Desktop 可在 Linux 容器和 Windows 容器之间切换,以便轻松地为不同类型的 IoT Edge 设备开发模块。

按照 Docker 文档的说明在开发计算机上安装:

设置 VS Code 和工具

使用适用于 Visual Studio Code 的 IoT 扩展开发 IoT Edge 模块。 这些扩展提供项目模板、自动化部署清单的创建,并允许监视和管理 IoT Edge 设备。 本部分将安装 Visual Studio Code 和 IoT 扩展,然后设置 Azure 帐户用于在 Visual Studio Code 中管理 IoT 中心资源。

  1. 在开发计算机上安装 Visual Studio Code

  2. 安装完成后,选择“查看” > “扩展” 。

  3. 搜索 Azure IoT Tools,它实际上是一个扩展集合,可帮助与 IoT 中心和 IoT 设备进行交互,以及开发 IoT Edge 模块。

  4. 选择“安装” 。 每个随附的扩展均单独安装。

  5. 完成扩展安装后,通过选择“查看” > “命令面板”来打开命令面板 。

  6. 在命令面板中,搜索并选择 Azure:Sign in 命令。 根据提示登录到 Azure 帐户。

  7. 再次在命令面板中搜索并选择 Azure IoT Hub:Select IoT Hub 命令。 按照提示选择 Azure 订阅和 IoT 中心。

  8. 通过选择左侧活动栏中的图标,或选择“查看” > “资源管理器”,打开 Visual Studio Code 的“资源管理器”部分 。

  9. 在“资源管理器”部分的底部,展开折叠的“Azure IoT 中心/设备”菜单。 应该看到与通过命令面板选择的 IoT 中心关联的设备和 IoT Edge 设备。

    查看 IoT 中心中的设备

创建容器注册表

本教程将使用 Azure IoT Tools 扩展来生成模块并从文件创建 容器映像。 然后将该映像推送到用于存储和管理映像的 注册表。 最后,从注册表部署在 IoT Edge 设备上运行的映像。

可以使用任意兼容 Docker 的注册表来保存容器映像。 两个常见 Docker 注册表服务分别是 Azure 容器注册表Docker 中心。 本教程使用 Azure 容器注册表。

如果还没有容器注册表,请执行以下步骤,以便在 Azure 中创建一个新的:

  1. Azure 门户中,选择“创建资源” > “容器” > “容器注册表”。

  2. 提供以下值,以便创建容器注册表:

    字段
    订阅 从下拉列表中选择“订阅”。
    资源组 建议对在 IoT Edge 快速入门和教程中创建的所有测试资源使用同一资源组。 例如,IoTEdgeResources
    注册表名称 提供唯一名称。
    位置 选择靠近你的位置。
    SKU 选择“基本”。
  3. 选择“创建”。

  4. 创建容器注册表后,浏览到它,然后从左窗格中,选择“设置”下菜单中的“访问密钥” 。

  5. 单击以允许管理员用户查看容器注册表的“用户名”和“密码”。

  6. 复制“登录服务器”、“用户名”和“密码”的值,并将其保存在方便的位置 。 本教程将使用这些值来访问容器注册表。

    复制容器注册表的登录服务器、用户名和密码

创建新的模块项目

Azure IoT Edge Tools 扩展为 Visual Studio Code 中支持的所有 IoT Edge 模块语言提供项目模板。 这些模板包含将工作模块部署到测试 IoT Edge 所需的所有文件和代码,或为你提供使用自己的业务逻辑自定义模板的起点。

本教程使用 C# 模块模板,因为它是最常用的模板。

创建项目模板

在 Visual Studio Code 命令面板中,搜索并选择 Azure IoT Edge: New IoT Edge Solution 命令。 按照提示操作并使用以下值创建解决方案:

字段
选择文件夹 在适用于 VS Code 的开发计算机上选择用于创建解决方案文件的位置。
提供解决方案名称 输入解决方案的描述性名称,或者接受默认的 EdgeSolution
选择模块模板 选择“C# 模块”。
提供模块名称 接受默认的 SampleModule
为模块提供 Docker 映像存储库 映像存储库包含容器注册表的名称和容器映像的名称。 容器映像是基于你在上一步中提供的名称预先填充的。 将 localhost:5000 替换为 Azure 容器注册表中的“登录服务器”值。 可以在 Azure 门户的容器注册表的“概述”页中检索“登录服务器”值。

最终的映像存储库看起来类似于 <registry name>.azurecr.cn/samplemodule。

提供 Docker 映像存储库

在 Visual Studio Code 窗口中加载新解决方案后,请花时间熟悉其创建的文件:

  • .vscode 文件夹包含名为 launch.json 的文件,该文件用于调试模块。

  • modules 文件夹包含用于解决方案中每个模块的文件夹。 现在应该只有 SampleModule,或为模块提供的任何名称。 SampleModule 文件夹包含主程序代码、模块元数据和多个 Docker 文件。

  • .env 文件保存容器注册表凭据。 这些凭据与 IoT Edge 设备共享,以便它可以访问并拉取容器映像。

  • deployment.debug.template.json 文件和 deployment.template.json 文件是帮助创建部署清单的模板。 部署清单 是一个文件,可准确定义想要在设备上部署的模块、应如何配置它们以及它们如何相互通信及与云通信。 模板文件使用指针来表示某些值。 将模板转换为真正的部署清单时,指针将替换为从其他解决方案文件中获取的值。 找到部署模板中的两个常用占位符:

    • 在“注册表凭据”部分中,将根据创建解决方案时提供的信息自动填充地址。 但是,用户名和密码引用 .env 文件中存储的变量。 此配置是出于安全考量,因为 .env 文件被 Git 忽略,但部署模板未被忽略。
    • 在“SampleModule”部分中,即使在创建解决方案时提供了映像存储库,也未填充容器映像。 此占位符指向 SampleModule 文件夹中的 module.json 文件。 如果转到该文件,将看到“映像”字段确实包含存储库,但也包含由容器的版本和平台组成的标记值。 可以在开发周期中手动迭代版本,并使用我们在本部分稍后介绍的开关选择容器平台。

向 IoT Edge 代理提供注册表凭据

环境文件存储容器注册表的凭据,并将其与 IoT Edge 运行时共享。 运行时需要这些凭据才能将容器映像拉取到 IoT Edge 设备中。

备注

如果你未将 localhost:5000 值替换为 Azure 容器注册表中的登录服务器值,则在创建项目模板步骤中,部署清单的 .env 文件和 registryCredentials 部分将缺失 。

IoT Edge 扩展尝试从 Azure 中拉取容器注册表凭据并将其填充到环境文件中。 检查凭据是否已包含在内。 如果没有,请立即添加:

  1. 打开模块解决方案中的 .env 文件。
  2. 添加从 Azure 容器注册表中复制的 usernamepassword 值。
  3. 将更改保存到 .env 文件。

选择目标体系结构

目前,Visual Studio Code 可以为 Linux AMD64 和 ARM32v7 设备开发 C# 模块。 需要选择每种解决方案的目标体系结构,因为这会影响容器的生成和运行方式。 默认值为 Linux AMD64。

  1. 打开命令面板并搜索 Azure IoT Edge:Set Default Target Platform for Edge Solution,或选择窗口底部侧栏中的快捷方式图标。

    选择侧栏中的体系结构图标

  2. 在命令面板中,从选项列表中选择目标体系结构。 在本教程中,我们使用 Ubuntu 虚拟机作为 IoT Edge 设备,因此将保留默认的“amd64” 。

查看示例代码

创建的解决方案模板包含 IoT Edge 模块的示例代码。 此示例模块仅接收消息,然后传递消息。 管道功能演示 IoT Edge 中的一个重要概念,即模块之间相互通信的方式。

每个模块可以在其代码中声明多个 输入输出 队列。 在设备上运行的 IoT Edge 中心将来自一个模块的输出的消息路由到一个或多个模块的输入。 用于声明输入和输出的特定代码因语言而异,但所有模块的概念都相同。 有关在模块之间路由的详细信息,请参阅声明路由

项目模板附带的示例 C# 代码使用适用于 .NET 的 IoT 中心 SDK 中的 ModuleClient 类

  1. 打开 Program.cs 文件,该文件位于 modules/SampleModule/ 文件夹中。

  2. 在 program.cs 中,找到 SetInputMessageHandlerAsync 方法。

  3. SetInputMessageHandlerAsync 方法会设置一个输入队列,用来接收传入消息。 查看此方法,并了解它如何初始化名为 input1 的输入队列。

    在 SetInputMessageCallback 构造函数中找到输入名称

  4. 接下来,找到 SendEventAsync 方法。

  5. SendEventAsync 方法会处理收到的消息,并设置一个输出队列,用来传递这些消息。 查看此方法,可以看到它会初始化名为 output1 的输出队列。

    在 SendEventToOutputAsync 中找到输出名称

  6. 打开 deployment.template.json 文件。

  7. 找到 $edgeAgent 所需属性的 modules 属性。

    此处应该列出两个模块。 一个模块是 SimulatedTemperatureSensor 模块,该模块默认包含在所有模板中,提供可用于测试模块的模拟温度数据。 另一个模块是作为此解决方案一部分创建的 SampleModule 模块。

  8. 在文件底部,找到 $edgeHub 模块的所需属性。

    IoT Edge 中心模块的其中一个函数可在部署中的所有模块之间路由消息。 查看 routes 属性中的值。 一个路由 SampleModuleToIoTHub 使用通配符 (*) 来指示来自 SampleModule 模块中任何输出队列的任何消息。 这些消息进入 $upstream(用于指示 IoT 中心的预留名称)。 另一个路由 sensorToSampleModule 接收来自 SimulatedTemperatureSensor 模块的消息,并将它们路由到在 SampleModule 代码中初始化的 input1 输入队列。

    查看 deployment.template.json 中的路由

生成并推送解决方案

你已查看模块代码和部署模板来了解一些关键部署概念。 现在,已准备好生成 SampleModule 容器映像并将其推送到容器注册表。 借助适用于 Visual Studio Code 的 IoT Tools 扩展,此步骤还会根据模板文件中的信息和解决方案文件中的模块信息生成部署清单。

登录 Docker

向 Docker 提供容器注册表凭据,以便它可以推送要存储在注册表中的容器映像。

  1. 选择“查看” > “终端”,打开 Visual Studio Code 集成终端 。

  2. 使用创建注册表后保存的 Azure 容器注册表凭据登录 Docker。

    docker login -u <ACR username> -p <ACR password> <ACR login server>
    

    可能会收到一条安全警告,推荐使用 --password-stdin。 这条最佳做法是针对生产方案建议的,这超出了本教程的范畴。 有关详细信息,请参阅 docker login 参考。

  3. 登录到 Azure 容器注册表

    az acr login -n <ACR registry name>
    

生成并推送

Visual Studio Code 现在有权访问容器注册表,因此可以将解决方案代码转换为容器映像。

  1. 在 Visual Studio Code 资源管理器中右键单击 deployment.template.json 文件,然后选择“生成并推送 IoT Edge 解决方案” 。

    生成并推送 IoT Edge 模块

    “生成并推送”命令会启动三项操作。 首先,它在解决方案中创建名为 config 的新文件夹,用于保存基于部署模板和其他解决方案文件中的信息生成的完整部署清单。 其次,它会运行 docker build,以基于目标体系结构的相应 dockerfile 生成容器映像。 然后,它会运行 docker push,以将映像存储库推送到容器注册表。

    首次执行此过程可能需要几分钟时间,但下次运行命令时速度会变快。

  2. 打开新建的 config 文件夹中的 deployment.amd64.json 文件。 文件名反映目标体系结构,因此,如果选择其他体系结构,则会有所不同。

  3. 请注意,具有占位符的两个参数现在都填充了适当的值。 registryCredentials 部分具有从 .env 文件中拉取的注册表用户名和密码。 SampleModule 具有完整的映像存储库,以及 module.json 文件的名称、版本和体系结构标记。

  4. 打开 SampleModule 文件夹中的 module.json 文件。

  5. 更改模块映像的版本号。 (版本,而不是 $schema-version。)例如,将补丁版本号递增为 0.0.2,就像我们对模块代码进行了小修补一样。

    提示

    模块版本支持版本控制,允许在将更新部署到生产环境之前在少量设备上测试更改。 如果在生成并推送之前未递增模块版本,则会替代容器注册表中的存储库。

  6. 将更改保存到 module.json 文件。

  7. 再次右键单击 deployment.template.json 文件,然后再次选择“生成并推送 IoT Edge 解决方案” 。

  8. 再次打开 deployment.amd64.json 文件。 请注意,再次运行“生成并推送”命令时未创建新文件, 而是更新了同一文件以反映更改。 SampleModule 映像现在指向容器的 0.0.2 版。

  9. 若要进一步验证“生成并推送”命令执行的操作,请转到 Azure 门户并导航到容器注册表。

  10. 在容器注册表中,依次选择“存储库”和“samplemodule” 。 验证映像的两个版本是否都已推送到注册表。

    在容器注册表中查看两个映像版本

疑难解答

如果在生成并推送模块映像时遇到错误,这通常与开发计算机上的 Docker 配置有关。 使用以下检查来检查配置:

  • 是否使用从容器注册表复制的凭据运行 docker login 命令? 这些凭据与用于登录 Azure 的凭据不同。
  • 你的容器存储库是否正确? 它是否拥有正确的容器注册表名称和正确的模块名称? 打开 SampleModule 文件夹中的 module.json 文件进行检查。 存储库值应类似于 <registry name>.azurecr.cn/samplemodule
  • 如果为模块使用的名称不是 SampleModule,那么使用的名称在整个解决方案中是否保持一致?
  • 计算机运行的容器类型与要生成的容器类型是否相同? 本教程适用于 Linux IoT Edge 设备,因此,Visual Studio Code 应在侧栏指明 amd64arm32v7,且 Docker Desktop 应运行 Linux 容器。

将模块部署到设备

因为已确认生成的容器映像存储在容器注册表中,所以现在可将它们部署到设备中。 确保 IoT Edge 设备已启动并运行。

  1. 在 Visual Studio Code 资源管理器中的“Azure IoT 中心”部分下,展开“设备”可查看 IoT 设备的列表。

  2. 右键单击想要在其中部署的 IoT Edge 设备,然后选择“为单个设备创建部署” 。

    为单个设备创建部署

  3. 在文件资源管理器中,导航到 config 文件夹,然后选择 deployment.amd64.json 文件。

    不要使用 deployment.template.json 文件,该文件不包含容器注册表凭据或模块映像值。 如果面向 Linux ARM32 设备,则部署清单将命名为 deployment.arm32v7.json。

  4. 在设备下,展开“模块”可查看已部署的正在运行的模块的列表。 单击“刷新”按钮。 应看到新的 SimulatedTemperatureSensor 和 SampleModule 模块在设备上运行。

    启动模块可能需要数分钟时间。 IoT Edge 运行时需要接收其新的部署清单,从容器运行时下拉模块映像,然后启动每个新模块。

    查看在 IoT Edge 设备上运行的模块

查看设备消息

SampleModule 代码通过其输入队列接收消息,并通过其输出队列传递消息。 部署清单声明了从 SimulatedTemperatureSensor 将消息传递到 SampleModule,再将消息从 SampleModule 转发到 IoT 中心的路由。 适用于 Visual Studio Code 的 Azure IoT Tools 允许查看从各个设备到达 IoT 中心的消息。

  1. 在 Visual Studio Code 资源管理器中,右键单击想要监视的 IoT Edge 设备,然后选择“开始监视内置事件终结点” 。

  2. 观察 Visual Studio Code 的输出窗口,查看到达 IoT 中心的消息。

    查看传入的设备到云消息

查看设备上的更改

如果想要查看设备本身发生的情况,请使用本部分中的命令检查设备上运行的 IoT Edge 运行时和模块。

本部分中的命令适用于 IoT Edge 设备,而不适用于开发计算机。 如果为 IoT Edge 设备使用虚拟机,请立即连接到虚拟机。 在 Azure 中,转到虚拟机的“概述”页,然后选择“连接”以访问安全 shell 连接 。

  • 查看部署到设备的所有模块,并检查其状态:

    iotedge list
    

    应该看到四个模块:两个 IoT Edge 运行时模块、SimulatedTemperatureSensor 和 SampleModule。 全部四个模块都应列为“正在运行”。

  • 检查特定模块的日志:

    iotedge logs <module name>
    

    IoT Edge 模块区分大小写。

    SimulatedTemperatureSensor 和 SampleModule 日志应显示其正在处理的消息。 edgeAgent 模块负责启动其他模块,因此其日志将包含有关实施部署清单的信息。 如果有任何模块未列出或未运行,则 edgeAgent 日志可能包含相关错误信息。 edgeHub 模块负责模块和 IoT 中心之间的通信。 如果模块已启动并运行,但消息未到达 IoT 中心,则 edgeHub 日志可能包含相关错误信息。

清理资源

如果打算继续学习下一篇建议的文章,可以保留已创建的资源和配置,以便重复使用。 还可以继续使用相同的 IoT Edge 设备作为测试设备。

否则,可以删除本文中使用的本地配置和 Azure 资源,以免产生费用。

删除 Azure 资源

删除 Azure 资源和资源组的操作不可逆。 请确保不要意外删除错误的资源组或资源。 如果在现有的包含要保留资源的资源组中创建了 IoT 中心,请只删除 IoT 中心资源本身,而不要删除资源组。

若要删除资源,请执行以下操作:

  1. 登录到 Azure 门户,然后选择“资源组”。

  2. 选择包含 IoT Edge 测试资源的资源组的名称。

  3. 查看包含在资源组中的资源的列表。 若要删除这一切,可以选择“删除资源组”。 如果只需删除部分内容,可以单击要单独删除的每个资源。

后续步骤

在本教程中,在开发计算机上设置了 Visual Studio Code 并从中部署了第一个 IoT Edge 模块。 你已经了解基本概念,请尝试向模块添加功能,以便它可以分析通过它传递的数据。 选择首选语言: