适用于: IoT Edge 1.5
重要
IoT Edge 1.5 LTS 是 受支持的版本。 IoT Edge 1.4 LTS 的生命周期结束日期为 2024 年 11 月 12 日。 如果使用的是早期版本,请参阅 更新 IoT Edge。
本教程介绍如何开发和部署代码到 IoT Edge 设备。 使用 Azure IoT Edge 模块,可以部署直接在 IoT Edge 设备上运行业务逻辑的代码。 在 “将代码部署到 Linux 设备 快速入门”中,设置 IoT Edge 设备并从 Azure 市场部署了模块。
本文介绍两个 IoT Edge 开发工具的步骤:
- Azure IoT Edge 开发工具 命令行 (CLI),这是开发的首选。
- 适用于 Visual Studio Code 扩展的 Azure IoT Edge 工具 (处于 维护模式)。
使用本文开头的工具选择器按钮选择工具。
在本教程中,你将了解如何执行以下操作:
- 设置您的开发计算机
- 使用 IoT Edge 工具创建新项目
- 将项目生成为 Docker 容器 并将其存储在 Azure 容器注册表中
- 将代码部署到 IoT Edge 设备
本教程中创建的 IoT Edge 模块会筛选设备生成的温度数据。 仅当温度高于设定的阈值时,才会向上游发送消息。 边缘的此类分析有助于减少发送到云和存储在云中的数据量。
先决条件
开发计算机:
- 使用自己的计算机或虚拟机。
- 确保开发计算机支持 嵌套虚拟化 来运行容器引擎。
- 可以使用运行容器引擎的大多数作系统为 Linux 设备开发 IoT Edge 模块。 本教程使用 Windows 计算机,但它指出了 macOS 或 Linux 上的已知差异。
- 安装 Visual Studio Code
- 安装 Azure CLI。
Azure IoT Edge 设备:
- 在单独的设备上运行 IoT Edge。 将开发计算机和 IoT Edge 设备分开可模拟实际的部署方案,并帮助保持概念清晰。 使用快速入门文章 将代码部署到 Linux 设备 ,在 Azure 或 Azure 资源模板中创建 IoT Edge 设备,以部署已启用 IoT Edge 的 VM。
云资源:
- 使用免费层或标准层 Azure IoT 中心。
如果没有 Azure 帐户,请在开始前创建一个免费帐户。
提示
有关 Visual Studio Code 或 Visual Studio 2022 中交互式调试的指导:
本教程介绍 Visual Studio Code 的开发步骤。
关键概念
本教程逐步讲解如何开发 IoT Edge 模块。 IoT Edge 模块是包含可执行代码的容器。 将一个或多个模块部署到 IoT Edge 设备。 模块执行特定任务,例如从传感器引入数据、清理和分析数据,或将消息发送到 IoT 中心。 有关详细信息,请参阅 了解 Azure IoT Edge 模块。
开发 IoT Edge 模块时,了解开发计算机与模块部署的目标 IoT Edge 设备之间的差异。 要保存模块代码的容器必须与 目标设备的作系统(OS)匹配。 例如,最常见的方案是在 Windows 计算机上开发模块,以面向运行 IoT Edge 的 Linux 设备。 在这种情况下,容器作系统为 Linux。 完成本教程时,请记住 开发计算机 OS 和 容器 OS 之间的差异。
提示
如果你在 Windows 上使用适用于 Linux 的 IoT Edge,则方案中 的目标设备 是 Linux 虚拟机,而不是 Windows 主机。
本教程针对使用 Linux 容器运行 IoT Edge 的设备。 只要开发计算机运行 Linux 容器,就可以使用您偏好的操作系统。 建议使用 Visual Studio Code 通过 Linux 容器进行开发,因此本教程使用它。 还可以使用 Visual Studio,但这两个工具提供的支持存在差异。
下表列出了 Visual Studio Code 和 Visual Studio 中 Linux 容器 支持的开发方案。
Visual Studio Code | Visual Studio 2019/2022 | |
---|---|---|
Linux 设备体系结构 | Linux AMD64 Linux ARM32v7 Linux ARM64 |
Linux AMD64 Linux ARM32 Linux ARM64 |
Azure 服务 | Azure Functions Azure 流分析 Azure 机器学习 |
|
语言 | C C# 爪哇岛 Node.js Python语言 |
C C#(编程语言) |
详细信息 | 用于 Visual Studio Code 的 Azure IoT Edge | 适用于 Visual Studio 2019 的 Azure IoT Edge 工具 适用于 Visual Studio 2022 的 Azure IoT Edge 工具 |
安装容器引擎
IoT Edge 模块打包为容器,因此开发计算机上需要 Docker 兼容的容器管理系统 来生成和管理它们。 Docker Desktop 是开发的热门选择,因为它具有强大的功能支持。 Windows 上的 Docker Desktop 允许在 Linux 容器和 Windows 容器之间切换,以便为不同类型的 IoT Edge 设备开发模块。
使用 Docker 文档在开发计算机上安装 Docker:
安装适用于 Windows 的 Docker Desktop
- 安装适用于 Windows 的 Docker Desktop 时,系统会询问是想要使用 Linux 容器还是 Windows 容器。 可以随时更改此设置。 本教程使用 Linux 容器,因为模块面向 Linux 设备。 有关详细信息,请参阅 在 Windows 和 Linux 容器之间进行切换。
阅读 关于 Docker CE 获取多个 Linux 平台上的安装信息。
- 对于适用于 Linux 的 Windows 子系统(WSL),请安装适用于 Windows 的 Docker Desktop。
设置工具
安装基于 Python 的 Azure IoT Edge 开发工具 以创建 IoT Edge 解决方案。 可以使用两个选项:
- 使用首选预生成的 IoT Edge 开发容器
- 使用 iotedgedev 开发安装程序安装该工具
重要
适用于 Visual Studio Code 扩展的 Azure IoT Edge 工具处于维护模式。 首选开发工具是命令行 (CLI) Azure IoT Edge 开发工具。
使用适用于 Visual Studio Code 的 IoT 扩展开发 IoT Edge 模块。 这些扩展提供项目模板,自动创建部署清单,并让你监视和管理 IoT Edge 设备。 本部分将安装 Visual Studio Code 和 IoT 扩展,然后设置 Azure 帐户用于在 Visual Studio Code 中管理 IoT 中心资源。
安装 Azure IoT Edge 扩展。
安装 Azure IoT 中心 扩展。
安装扩展后,通过选择 “查看>命令面板”打开命令面板。
在命令面板中,搜索并选择 Azure IoT 中心:选择 IoT 中心。 按照提示选择 Azure 订阅和 IoT 中心。
通过选择活动栏中的图标或通过选择视图>资源管理器来打开 Visual Studio Code 的资源管理器部分。
在“资源管理器”部分的底部,展开折叠的“Azure IoT 中心/设备”菜单。 查看与通过命令面板选择的 IoT 中心关联的设备和 IoT Edge 设备。
安装特定于语言的工具
安装特定于你正在开发的语言的工具:
创建容器注册表
在本教程中,将使用 Azure IoT Edge 和 Azure IoT 中心 扩展生成模块并从文件创建 容器映像 。 然后将此映像推送到存储和管理映像的 注册表 。 最后,从注册表部署在 IoT Edge 设备上运行的映像。
重要
Azure IoT Edge Visual Studio Code 扩展处于 维护模式。
可以使用任意兼容 Docker 的注册表来保存容器映像。 两种常用的 Docker 注册表服务是 Azure 容器注册表 和 Docker 中心。 本教程使用 Azure 容器注册表。
如果还没有容器注册表,请执行以下步骤,以便在 Azure 中创建一个新的:
在 Azure 门户中,选择“ 创建资源>容器>容器注册表”。
提供以下所需值以创建容器注册表:
字段 值 订阅 从下拉列表中选择“订阅”。 资源组 对在 IoT Edge 快速入门和教程中创建的所有测试资源使用同一资源组。 例如 ,IoTEdgeResources。 注册表名称 提供唯一名称。 位置 选择靠近你的位置。 SKU 选择“基本”。 选择 “查看 + 创建”,然后选择 “创建”。
从 Azure 门户主页的“ 资源 ”部分选择新的容器注册表以将其打开。
在容器注册表的左窗格中,从位于“设置”下的菜单中选择“访问密钥”。
用切换按钮启用“管理员用户”,查看容器注册表的“用户名”和“密码”。
复制“登录服务器”、“用户名”和“密码”的值,并将其保存在方便的位置。 本教程将使用这些值来访问容器注册表。
创建新的模块项目
Azure IoT Edge 扩展为 Visual Studio Code 中支持的所有 IoT Edge 模块语言提供项目模板。 这些模板包含所有用于部署工作模块以测试 IoT Edge 的文件和代码,或者提供一个起点让您使用自己的业务逻辑自定义模板。
创建项目模板
IoT Edge 开发工具使用环境变量驱动的命令简化了 Azure IoT Edge 开发。 它有助于使用 IoT Edge 开发容器和 IoT Edge 解决方案基架(包括默认模块和所有必需的配置文件)开始 IoT Edge 开发。
在所需路径上为解决方案创建目录。 更改为
iotedgesolution
目录。mkdir c:\dev\iotedgesolution cd c:\dev\iotedgesolution
使用 iotedgedev solution init 命令创建解决方案并以选择的开发语言设置 Azure IoT 中心。
iotedgedev 解决方案 init 脚本会提示你完成几个步骤,包括:
- 向 Azure 进行身份验证
- 选择一个 Azure 订阅
- 选择或创建资源组
- 选择或创建 Azure IoT 中心
- 选择或创建 Azure IoT Edge 设备
使用 Visual Studio Code 和 Azure IoT Edge 扩展。 首先创建解决方案,然后在该解决方案中生成第一个模块。 每个解决方案可以包含多个模块。
- 选择“查看”“命令面板” 。
- 在“命令面板”中,输入并运行 Azure IoT Edge: New IoT Edge Solution 命令。
- 浏览到要在其中创建新解决方案的文件夹,然后选择选择文件夹。
- 输入解决方案的名称。
- 选择首选开发语言的模块模板作为解决方案中的第一个模块。
- 输入模块的名称。 选择容器注册表中唯一的名称。
- 输入模块的映像存储库的名称。 Visual Studio Code 使用“localhost:5000/<你的模块名称>”自动填充模块名。 将其替换为你自己的注册表信息。 如果使用本地 Docker 注册表进行测试,请使用 localhost。 如果使用 Azure 容器注册表,请使用注册表设置的 登录服务器 。 登录服务器类似于 <注册表名称>.azurecr.io。 仅替换字符串的 localhost:5000 部分,使最终结果类似于 注册表名称<.azurecr.io/模块名称>。
Visual Studio Code 采用你提供的信息,创建一个 IoT Edge 解决方案,然后在新窗口中加载它。
创建解决方案后,这些主文件位于解决方案中:
.vscode 文件夹包括配置文件launch.json。
模块文件夹包含每个模块的子文件夹。 在每个子文件夹中,module.json 文件控制模块的生成和部署方式。
.env 文件列出了环境变量。 默认情况下,容器注册表的环境变量为 localhost:5000。
两个模块部署文件 ,deployment.template.json 和 deployment.debug.template.json,列出要部署到设备的模块。 默认情况下,列表包括 IoT Edge 系统模块(edgeAgent 和 edgeHub)和示例模块,例如:
- filtermodule 是实现简单筛选器函数的示例模块。
- SimulatedTemperatureSensor 模块模拟可用于测试的数据。 有关如何运行部署清单的详细信息,请参阅 了解如何使用部署清单来部署模块和建立路由。 有关模拟温度模块的工作原理的详细信息,请参阅 SimulatedTemperatureSensor.csproj 源代码。
注意
安装的确切模块可能取决于所选语言。
设置 IoT Edge 运行时版本
最新的稳定 IoT Edge 系统模块版本为 1.5。 将系统模块设置为版本 1.5。
在 Visual Studio Code 中,打开 deployment.template.json 部署清单文件。 部署清单是一个 JSON 文档,描述要在目标 IoT Edge 设备上配置的模块。
更改系统运行时模块映像 edgeAgent 和 edgeHub 的运行时版本。 例如,如果要使用 IoT Edge 运行时版本 1.5,请更改部署清单文件中的以下行:
"systemModules": { "edgeAgent": { "image": "mcr.microsoft.com/azureiotedge-agent:1.5", "edgeHub": { "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
向 IoT Edge 代理提供注册表凭据
环境文件存储容器注册表的凭据,并将其与 IoT Edge 运行时共享。 运行时需要这些凭据才能将容器映像拉取到 IoT Edge 设备。
IoT Edge 扩展尝试从 Azure 中拉取容器注册表凭据并将其填充到环境文件中。
注意
仅当为模块提供了映像存储库时,才会创建环境文件。 如果接受 localhost 默认值在本地进行测试和调试,则不需要声明环境变量。
检查凭据是否存在。 如果没有,请立即添加:
如果 Azure 容器注册表是你的注册表,请设置 Azure 容器注册表用户名和密码。 通过 Azure 门户中容器注册表的“设置”“访问密钥”菜单获取这些值。
在模块解决方案中打开 .env 文件。
添加从 Azure 容器注册表复制的用户名和密码值。 例如:
CONTAINER_REGISTRY_SERVER="myacr.azurecr.io" CONTAINER_REGISTRY_USERNAME="myacr" CONTAINER_REGISTRY_PASSWORD="<registry_password>"
保存对 .env 文件的更改。
注意
本教程使用 Azure 容器注册表的管理员凭据,方便开发和测试方案。 为生产方案做好准备后,建议使用最低权限身份验证选项(如服务主体或存储库范围的令牌)。 有关详细信息,请参阅 管理对容器注册表的访问权限。
目标体系结构
选择针对每个解决方案的体系结构,因为这会影响容器的生成和运行方式。 默认值为 Linux AMD64。 对于本教程,请使用 Ubuntu 虚拟机作为 IoT Edge 设备,并保留默认 amd64。
如果需要更改解决方案的目标体系结构,请执行以下步骤。
打开命令面板并搜索 Azure IoT Edge:设置 Edge 解决方案的默认目标平台,或选择窗口底部侧栏中的快捷图标。
在命令面板中,从选项列表中选择目标体系结构。
在后面的步骤中创建容器映像时,将设置目标体系结构。
使用自定义代码更新模块
每个模板都包含从 SimulatedTemperatureSensor 模块获取模拟传感器数据并将其路由到 IoT 中心的示例代码。 示例模块接收消息并传递消息。 管道功能在 IoT Edge 中显示了一个重要概念:模块如何相互通信。
每个模块都可以在其代码中声明多个输入和输出队列。 设备上运行的 IoT Edge 中心将消息从一个模块的输出路由到一个或多个模块的输入。 声明输入和输出的特定代码因语言而异,但所有模块的概念都是相同的。 有关模块之间的路由的详细信息,请参阅 声明路由。
项目模板附带的示例 C# 代码使用适用于 .NET 的 IoT 中心 SDK 中的 ModuleClient 类 。
在 Visual Studio Code 资源管理器中,打开 模块>filtermodule>ModuleBackgroundService.cs。
在 filtermodule 命名空间之前,为稍后使用的类型添加三个 using 语句:
using System.Collections.Generic; // For KeyValuePair<> using Microsoft.Azure.Devices.Shared; // For TwinCollection using Newtonsoft.Json; // For JsonConvert
将 temperatureThreshold 变量添加到 ModuleBackgroundService 类。 此变量设置测量的温度必须超过的值才能将数据发送到 IoT 中心。
static int temperatureThreshold { get; set; } = 25;
添加 MessageBody、Machine 和 Ambient 类。 这些类将为传入消息的正文定义所需的架构。
class MessageBody { public Machine machine {get;set;} public Ambient ambient {get; set;} public string timeCreated {get; set;} } class Machine { public double temperature {get; set;} public double pressure {get; set;} } class Ambient { public double temperature {get; set;} public int humidity {get; set;} }
查找 ExecuteAsync 函数。 此函数可创建并配置 ModuleClient 对象,使模块能够连接到本地 Azure IoT Edge 运行时以发送和接收消息。 创建 ModuleClient 后,代码从模块孪生的所需属性中读取 temperatureThreshold 值。 代码注册一个回调,以通过名为 input1 的终结点从 IoT Edge 中心接收消息。
将对 ProcessMessageAsync 方法的调用替换为一种新方法,以更新终结点名称以及在输入到达时调用的方法。 此外添加 SetDesiredPropertyUpdateCallbackAsync 方法用于更新所需属性。 若要进行此更改,请使用以下代码替换 ExecuteAsync 方法的最后一行:
// Register a callback for messages that are received by the module. // await _moduleClient.SetInputMessageHandlerAsync("input1", PipeMessage, cancellationToken); // Read the TemperatureThreshold value from the module twin's desired properties var moduleTwin = await _moduleClient.GetTwinAsync(); await OnDesiredPropertiesUpdate(moduleTwin.Properties.Desired, _moduleClient); // Attach a callback for updates to the module twin's desired properties. await _moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertiesUpdate, null); // Register a callback for messages that are received by the module. Messages received on the inputFromSensor endpoint are sent to the FilterMessages method. await _moduleClient.SetInputMessageHandlerAsync("inputFromSensor", FilterMessages, _moduleClient);
将 onDesiredPropertiesUpdate 方法添加到 ModuleBackgroundService 类。 此方法从模块孪生接收所需属性的更新,并更新 temperatureThreshold 变量以匹配。 所有模块都有自己的孪生模块,因此可以直接从云配置在模块中运行的代码。
static Task OnDesiredPropertiesUpdate(TwinCollection desiredProperties, object userContext) { try { Console.WriteLine("Desired property change:"); Console.WriteLine(JsonConvert.SerializeObject(desiredProperties)); if (desiredProperties["TemperatureThreshold"]!=null) temperatureThreshold = desiredProperties["TemperatureThreshold"]; } catch (AggregateException ex) { foreach (Exception exception in ex.InnerExceptions) { Console.WriteLine(); Console.WriteLine("Error when receiving desired property: {0}", exception); } } catch (Exception ex) { Console.WriteLine(); Console.WriteLine("Error when receiving desired property: {0}", ex.Message); } return Task.CompletedTask; }
添加 FilterMessages 方法。 每当模块从 IoT Edge 中心接收消息,就会调用此方法。 此方法筛选掉那些所报告温度低于温度阈值(通过孪生模块进行设置)的消息。 它还会将 MessageType 属性添加到消息中,并将值设置为 Alert。
async Task<MessageResponse> FilterMessages(Message message, object userContext) { var counterValue = Interlocked.Increment(ref _counter); try { ModuleClient moduleClient = (ModuleClient)userContext; var messageBytes = message.GetBytes(); var messageString = Encoding.UTF8.GetString(messageBytes); Console.WriteLine($"Received message {counterValue}: [{messageString}]"); // Get the message body. var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString); if (messageBody != null && messageBody.machine.temperature > temperatureThreshold) { Console.WriteLine($"Machine temperature {messageBody.machine.temperature} " + $"exceeds threshold {temperatureThreshold}"); using (var filteredMessage = new Message(messageBytes)) { foreach (KeyValuePair<string, string> prop in message.Properties) { filteredMessage.Properties.Add(prop.Key, prop.Value); } filteredMessage.Properties.Add("MessageType", "Alert"); await moduleClient.SendEventAsync("output1", filteredMessage); } } // Indicate that the message treatment is completed. return MessageResponse.Completed; } catch (AggregateException ex) { foreach (Exception exception in ex.InnerExceptions) { Console.WriteLine(); Console.WriteLine("Error in sample: {0}", exception); } // Indicate that the message treatment is not completed. var moduleClient = (ModuleClient)userContext; return MessageResponse.Abandoned; } catch (Exception ex) { Console.WriteLine(); Console.WriteLine("Error in sample: {0}", ex.Message); // Indicate that the message treatment is not completed. ModuleClient moduleClient = (ModuleClient)userContext; return MessageResponse.Abandoned; } }
保存 ModuleBackgroundService.cs 文件。
在 Visual Studio Code 资源管理器的 IoT Edge 解决方案工作区中打开 deployment.template.json 文件。
由于我们更改了模块侦听的终结点的名称,因此还需要更新部署清单中的路由,以便 edgeHub 将消息发送到新终结点。
在 $edgeHub 模块孪生中找到 routes 节 。 更新 sensorTofiltermodule 路由以将 替换为
input1
:"sensorTofiltermodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/inputFromSensor\")"
将 filtermodule 模块孪生体添加至部署清单中。 在 modulesContent 节底部的 $edgeHub 模块孪生后面插入以下 JSON 内容:
"filtermodule": { "properties.desired":{ "TemperatureThreshold":25 } }
保存 deployment.template.json 文件。
生成并推送解决方案
你已更新模块代码和部署模板来帮助了解一些关键部署概念。 现在,已准备好生成模块容器映像并将其推送到容器注册表。
在 Visual Studio Code 中,打开 deployment.template.json 部署清单文件。 部署清单描述了在目标 IoT Edge 设备上配置的模块。 在部署之前,需要使用正确的 createOptions
值更新 Azure 容器注册表凭据和模块映像。 有关 createOption 值的详细信息,请参阅 如何为 IoT Edge 模块配置容器创建选项。
如果使用 Azure 容器注册表来存储模块映像,请将凭据添加到 deployment.template.json 中的 modulesContentedgeAgent>settingsregistryCredentials 部分。 将 myacr 替换为自己的注册表名称,并提供密码和 登录服务器 地址。 例如:
"registryCredentials": {
"myacr": {
"username": "myacr",
"password": "<your_acr_password>",
"address": "myacr.azurecr.io"
}
}
将以下字符串化内容添加到列出的每个系统(edgeHub 和 edgeAgent)和自定义模块(filtermodule 和 tempSensor)的 createOptions 值或替换此值。 请根据需要更改这些值。
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
例如,filtermodule 配置应类似于:
"filtermodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}
生成模块 Docker 映像
通过选择“终端”“新建终端”打开 Visual Studio Code 集成终端。>
使用 dotnet publish
命令生成适用于 Linux 和 amd64 体系结构的容器映像。 将目录更改为项目中的 filtermodule 目录,并运行 dotnet publish 命令。
dotnet publish --os linux --arch x64 /t:PublishContainer
目前, iotedgedev 工具模板面向 .NET 7.0。 如果要以不同版本的 .NET 为目标,可以编辑 filtermodule.csproj 文件并更改 TargetFramework 和 PackageReference 值。 例如,若要以 .NET 8.0 为目标,filtermodule.csproj 文件应如下所示:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Devices.Client" Version="1.42.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
</Project>
使用容器注册表信息、版本和体系结构标记 docker 映像。 将 myacr 替换为自己的注册表名称。
docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.1-amd64
推送模块 Docker 映像
向 Docker 提供容器注册表凭据,以便它可以推送要存储在注册表中的容器映像。
使用 Azure 容器注册表 (ACR) 凭据登录到 Docker。
docker login -u <ACR username> -p <ACR password> <ACR login server>
可能会收到一条安全警告,推荐使用
--password-stdin
。 虽然它是为生产方案推荐的最佳做法,但它超出了本教程的范畴。 有关详细信息,请参阅 docker 登录 参考。登录到 Azure 容器注册表。 需要 安装 Azure CLI 才能使用
az
命令。 此命令要求在 设置>访问密钥的容器注册表中找到用户名和密码。az acr login -n <ACR registry name>
提示
如果你在学习本教程过程中的任何时候退出登录,请重复 Docker 和 Azure 容器注册表登录步骤以继续。
将 模块映像推送到本地注册表或容器注册表。
docker push <ImageName>
例如:
# Push the Docker image to the local registry docker push localhost:5000/filtermodule:0.0.1-amd64 # Or push the Docker image to an Azure Container Registry. Replace myacr with your Azure Container Registry name. az acr login --name myacr docker push myacr.azurecr.io/filtermodule:0.0.1-amd64
更新部署模板
使用容器注册表映像位置更新部署模板 deployment.template.json。 例如,如果使用 Azure 容器注册表 myacr.azurecr.io 并且图像为 filtermodule:0.0.1-amd64,请将 filtermodule 配置更新为:
"filtermodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "myacr.azurecr.io/filtermodule:0.0.1-amd64",
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}
}
在 Visual Studio Code 资源管理器中,右键单击 deployment.template.json 文件,然后选择“ 生成和推送 IoT Edge 解决方案”。
“生成并推送”命令会启动三项操作。 首先,它会在解决方案中创建一个名为 config 的新文件夹,用以保存完整的部署清单,这个清单是由部署模板和其他解决方案文件中的信息生成的。 其次,它会运行 docker build
,以基于目标体系结构的相应 dockerfile 生成容器映像。 然后,它会运行 docker push
,以将映像存储库推送到容器注册表。
首次执行此过程可能需要几分钟时间,但下次运行命令时速度会变快。
可选:更新模块和映像
如果对模块代码进行更改,则需要重新生成模块映像并将其推送到容器注册表。 使用本部分中的步骤更新生成和容器映像。 如果未对模块代码进行任何更改,则可以跳过此部分。
在新建的配置文件夹中打开 deployment.amd64.json 文件。 文件名会反映目标体系结构,因此,选择其他体系结构时会有所不同。
请注意,具有占位符的两个参数现在都包含了适当的值。 registryCredentials 节包含从 .env 文件拉取的注册表用户名和密码。 filtermodule 具有来自 module.json 文件的名称、版本和体系结构标记的完整映像存储库。
在 filtermodule 文件夹中打开 module.json 文件。
更改模块映像的版本号。 例如,将补丁版本号递增为
"version": "0.0.2"
,就像对模块代码进行了小修补一样。提示
模块版本支持版本控制,允许在将更新部署到生产环境之前在少量设备上测试更改。 如果在生成并推送之前未递增模块版本,则会替代容器注册表中的存储库。
保存对 module.json 文件的更改。
使用 0.0.2 版本标记生成和推送更新后的映像。 例如,若要为本地注册表或 Azure 容器注册表生成并推送映像,请使用以下命令:
# Build the container image for Linux and amd64 architecture.
dotnet publish --os linux --arch x64
# For local registry:
# Tag the image with version 0.0.2, x64 architecture, and the local registry.
docker tag filtermodule localhost:5000/filtermodule:0.0.2-amd64
# For Azure Container Registry:
# Tag the image with version 0.0.2, x64 architecture, and your container registry information. Replace **myacr** with your own registry name.
docker tag filtermodule myacr.azurecr.io/filtermodule:0.0.2-amd64
再次右键单击 deployment.template.json 文件,然后再次选择“ 生成和推送 IoT Edge 解决方案”。
再次打开 deployment.amd64.json 文件。 请注意,再次运行生成并推送命令时,生成系统不会创建新文件。 反而,同一文件会更新以反映更改。 filtermodule 映像现在指向容器的 0.0.2 版。
若要进一步验证生成和推送命令的用途,请转到 Azure 门户 并导航到容器注册表。
在容器注册表中,选择“存储库”,然后选择“filtermodule”。 验证映像的两个版本是否都已推送到注册表。
疑难解答
如果在生成并推送模块映像时遇到错误,这通常与开发计算机上的 Docker 配置有关。 使用以下检查来检查配置:
- 是否使用从容器注册表复制的凭据运行
docker login
命令? 这些凭据与用于登录 Azure 的凭据不同。 - 你的容器存储库是否正确? 它是否拥有正确的容器注册表名称和正确的模块名称? 打开 filtermodule 文件夹中要检查的 module.json 文件。 存储库值应类似于 <registry name>.azurecr.io/filtermodule。
- 如果为模块使用的名称不是 filtermodule,那么使用的名称在整个解决方案中是否保持一致?
- 计算机运行的容器类型与要生成的容器类型是否相同? 本教程适用于 Linux IoT Edge 设备,因此 Visual Studio Code 应在侧栏中显示 amd64 或 arm32v7,Docker Desktop 应运行 Linux 容器。
将模块部署到设备
你已确认生成的容器映像存储在容器注册表中,现在可将它们部署到设备。 确保 IoT Edge 设备已启动并运行。
使用 IoT Edge Azure CLI set-modules 命令将模块部署到 Azure IoT 中心。 例如,若要将 deployment.template.json 文件中定义的模块部署到 IoT Edge 设备 my-device 的 IoT 中心 my-iot-hub,请使用以下命令。 将 hub-name、device-id 和 login IoT 中心连接字符串的值替换为自己的值。
az iot edge set-modules --hub-name my-iot-hub --device-id my-device --content ./deployment.template.json --login "HostName=my-iot-hub.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=<SharedAccessKey>"
提示
在 Azure 门户中查找 IoT 中心连接字符串,包括共享访问密钥。 转到 IoT 中心>“安全设置”“共享访问策略”>“iothubowner”。
在 Visual Studio Code 资源管理器中的“Azure IoT 中心”部分下,展开“设备”可查看 IoT 设备的列表。
右键单击想要在其中部署的 IoT Edge 设备,然后选择“为单个设备创建部署” 。
在文件资源管理器中,导航到 配置 文件夹,然后选择 deployment.amd64.json 文件。
请勿使用 deployment.template.json 文件,它不包含容器注册表凭据或模块映像值。 如果面向 Linux ARM32 设备,则部署清单的名称 deployment.arm32v7.json。
在设备下,展开“模块”可查看已部署的正在运行的模块的列表。 选择“刷新”按钮。 应会看到新的 tempSensor 和 filtermodule 模块在设备上运行。
模块启动可能需要几分钟时间。 IoT Edge 运行时接收其新的部署清单,从容器运行时拉取模块映像,然后启动每个新模块。
查看设备消息
示例模块代码通过其输入队列获取消息,并通过其输出队列发送消息。 部署清单设置从 tempSensor 将消息发送到 filtermodule 的路由,然后将消息从 filtermodule 转发到 IoT 中心。 使用 Azure IoT Edge 和 Azure IoT 中心扩展,可以查看设备发往 IoT 中心的消息。
在 Visual Studio Code 资源管理器中,选择要监视的 IoT Edge 设备,然后选择“ 开始监视内置事件终结点”。
观看 Visual Studio Code 中的输出窗口,查看消息到达 IoT 中心。
查看设备上的更改
若要查看设备上发生的情况,请使用本节中的命令检查设备上运行的 IoT Edge 运行时和模块。
这些命令适用于 IoT Edge 设备,而不是开发计算机。 如果为 IoT Edge 设备使用虚拟机,请立即连接到虚拟机。 在 Azure 中,转到虚拟机的“概述”页,然后选择“连接”以访问安全 shell 连接 。
查看部署到设备的所有模块,并检查其状态:
iotedge list
你将看到四个模块:两个 IoT Edge 运行时模块、 tempSensor 和 filtermodule。 这四项都应列为正在运行。
检查特定模块的日志:
iotedge logs <module name>
模块名称区分大小写。
tempSensor 和 filtermodule 日志显示正在处理的消息。 edgeAgent 模块启动其他模块,因此其日志具有有关部署清单的信息。 如果模块未列出或未运行,请检查 edgeAgent 日志中是否存在错误。 edgeHub 模块管理模块与 IoT 中心之间的通信。 如果模块正在运行,但消息未到达 IoT 中心,请检查 edgeHub 日志中是否存在错误。
清理资源
若要继续阅读下一篇建议的文章,请保留创建的资源和配置并重复使用它们。 还可以继续使用相同的 IoT Edge 设备作为测试设备。
否则,请删除本文中使用的本地配置和 Azure 资源以避免费用。
删除 Azure 资源
删除 Azure 资源和资源组的操作不可逆。 请确保不要意外删除错误的资源组或资源。 如果在具有要保留的资源的现有资源组中创建 IoT 中心,请仅删除 IoT 中心资源本身,而不是资源组。
若要删除资源,请执行以下操作:
登录到 Azure 门户,然后选择 “资源组”。
选择包含 IoT Edge 测试资源的资源组的名称。
查看资源组包含的资源列表。 若要删除这一切,可以选择“删除资源组”。 如果只需删除部分,可以选择每个资源以单独删除。
后续步骤
在本教程中,你将在开发计算机上设置 Visual Studio Code,并使用用于筛选 IoT Edge 设备生成的原始数据的代码部署第一个 IoT Edge 模块。
继续学习下一教程,了解如何使用 Azure IoT Edge 部署 Azure 云服务来处理和分析边缘的数据。