教程:将 Azure Functions 作为 IoT Edge 模块进行部署

适用于:IoT Edge 1.4 复选标记 IoT Edge 1.4

可以使用 Azure Functions 部署代码,以直接将业务逻辑实现到 Azure IoT Edge 设备。 本教程将引导你在模拟的 IoT Edge 设备上创建和部署用于筛选传感器数据的 Azure 函数。 请使用在快速入门中创建的模拟 IoT Edge 设备。 本教程介绍如何执行下列操作:

  • 使用 Visual Studio Code 创建 Azure 函数。
  • 使用 Visual Studio Code 和 Docker 创建 Docker 映像并将其发布到容器注册表。
  • 将模块从容器注册表部署到 IoT Edge 设备。
  • 查看筛选的数据。

函数体系结构示意图,其中显示了如何暂存和部署函数模块。

在本教程中创建的 Azure 函数可以筛选由设备生成的温度数据。 该函数只在温度高于指定阈值的情况下,向 Azure IoT 中心上游发送消息。

如果没有 Azure 试用版订阅,请在开始前创建一个试用版订阅

先决条件

在开始学习本教程之前,请完成介绍如何设置用于开发 Linux 容器的开发环境的教程:使用 Linux 容器开发 IoT Edge 模块。 完成该教程后,应已准备好以下必备组件:

要使用 Azure Functions 开发 IoT Edge 模块,请在开发计算机上安装额外的必备组件:

创建函数项目

在先决条件部分安装的适用于 Visual Studio Code 的 Azure IoT Edge 提供管理功能和一些代码模板。 在本部分,请使用 Visual Studio Code 创建包含 Azure 函数的 IoT Edge 解决方案。

创建新项目

按照以下步骤创建可自定义的 C# 函数解决方案模板。

  1. 在开发计算机上打开 Visual Studio Code。

  2. 选择“视图”>“命令面板”,打开 Visual Studio Code 命令面板。

  3. 在命令面板中,键入并运行“Azure IoT Edge:新建 IoT Edge 解决方案”命令。 按照命令面板中的提示创建解决方案:

    • 选择文件夹:在适用于 Visual Studio Code 的开发计算机上选择创建解决方案文件的位置。
    • 提供解决方案名称:为解决方案添加描述性名称,例如 FunctionSolution,或接受默认名称。|
    • 选择模块模板:选择“Azure Functions - C#”。
    • 提供模块名称|将模块命名为 CSharpFunction
    • 为模块提供 Docker 映像存储库。 映像存储库包含容器注册表的名称和容器映像的名称。 容器映像是在上一步预先填充的。 将 localhost:5000 替换为 Azure 容器注册表中的“登录服务器”值。 可以在 Azure 门户容器注册表的“概述”页面中检索“登录服务器”。 最终的字符串类似于 <注册表名称>.azurecr.cn/csharpfunction。

    屏幕截图显示了在 Visual Studio Code 中添加 Docker 映像存储库名称的位置。

添加注册表凭据

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

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

  1. 在 Visual Studio Code 资源管理器中,打开 .env 文件。
  2. 使用从 Azure 容器注册表复制的 usernamepassword 值更新相关字段。 可以通过转到 Azure 中的容器注册表并查看“设置”>“访问密钥”页来再次找到它们。
  3. 保存此文件。

注意

本教程使用 Azure 容器注册表的管理员登录凭据,这对于开发和测试方案非常方便。 为生产方案做好准备后,建议使用最低权限身份验证选项(如服务主体)。 有关详细信息,请参阅管理容器注册表的访问权限

将目标体系结构设置为 AMD64

只有基于 Linux AMD64 的容器支持在 IoT Edge 上运行 Azure Functions 模块。 Visual Studio Code 的默认目标体系结构是 Linux AMD64,但我们将在此处显式将其设置为 Linux AMD64。

  1. 打开命令面板并搜索“Azure IoT Edge:为 Edge 解决方案设置默认的目标平台”。

  2. 在命令面板中,从选项列表中选择 AMD64 目标体系结构。

使用自定义代码更新模块

让我们添加一些额外的代码,以便 CSharpFunction 模块在边缘处理消息,然后再将消息转发到 IoT 中心。

  1. 在 Visual Studio Code 资源管理器中,打开“模块”>“CSharpFunction”>“CSharpFunction.cs”。

  2. CSharpFunction.cs 文件的内容替换为以下代码。 此代码接收有关环境温度和计算机温度的遥测,只有在计算机温度高于定义的阈值时才将消息转发到 IoT 中心。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.EdgeHub;
    using Microsoft.Azure.WebJobs.Host;
    using Microsoft.Extensions.Logging;
    using Newtonsoft.Json;
    
    namespace Functions.Samples
    {
        public static class CSharpFunction
        {
            [FunctionName("CSharpFunction")]
            public static async Task FilterMessageAndSendMessage(
                [EdgeHubTrigger("input1")] Message messageReceived,
                [EdgeHub(OutputName = "output1")] IAsyncCollector<Message> output,
                ILogger logger)
            {
                const int temperatureThreshold = 20;
                byte[] messageBytes = messageReceived.GetBytes();
                var messageString = System.Text.Encoding.UTF8.GetString(messageBytes);
    
                if (!string.IsNullOrEmpty(messageString))
                {
                    logger.LogInformation("Info: Received one non-empty message");
                    // Get the body of the message and deserialize it.
                    var messageBody = JsonConvert.DeserializeObject<MessageBody>(messageString);
    
                    if (messageBody != null && messageBody.machine.temperature > temperatureThreshold)
                    {
                        // Send the message to the output as the temperature value is greater than the threshold.
                        using (var filteredMessage = new Message(messageBytes))
                        {
                             // Copy the properties of the original message into the new Message object.
                             foreach (KeyValuePair<string, string> prop in messageReceived.Properties)
                             {filteredMessage.Properties.Add(prop.Key, prop.Value);}
                             // Add a new property to the message to indicate it is an alert.
                             filteredMessage.Properties.Add("MessageType", "Alert");
                             // Send the message.
                             await output.AddAsync(filteredMessage);
                             logger.LogInformation("Info: Received and transferred a message with temperature above the threshold");
                        }
                    }
                }
            }
        }
        //Define the expected schema for the body of incoming messages.
        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;}
        }
    }
    
  3. 保存文件。

生成并推送 IoT Edge 解决方案

在上一部分,你已经创建了一个 IoT Edge 解决方案并修改了 CSharpFunction,该函数会筛选出报告的计算机温度低于可接受阈值的消息。 现在需将解决方案生成为容器映像并将其推送到容器注册表。

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

  2. 在终端中输入以下命令,以登录到 Docker。 使用 Azure 容器注册表中的用户名、密码和登录服务器登录。 可以在 Azure 门户中从注册表的“访问密钥”部分检索这些值。

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

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

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

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

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

查看容器映像

将容器映像推送到容器注册表以后,Visual Studio Code 会输出一条成功消息。 若要自行确认操作是否成功,可以在注册表中查看映像。

  1. 在 Azure 门户中,浏览到 Azure 容器注册表。
  2. 选择“服务”>“存储库”。
  3. 列表中应会显示 csharpfunction 存储库。 选择此存储库可查看更多详细信息。
  4. 在“标记”部分,应会显示 0.0.1-amd64 标记。 此标记指示生成的映像的版本和平台。 这些值在 CSharpFunction 文件夹的 module.json 文件中设置。

部署并运行解决方案

可以使用 Azure 门户将函数模块部署到 IoT Edge 设备,就像在快速入门中所做的一样。 也可以在 Visual Studio Code 中部署和监视模块。 以下各部分使用先决条件中列出的适用于 Visual Studio Code 的 Azure IoT Edge 和 IoT 中心。 如果尚未安装该扩展,请立即安装。

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

  2. 右键单击 IoT Edge 设备的名称,然后选择“为单个设备创建部署”。

  3. 浏览到包含 CSharpFunction 的解决方案文件夹。 打开 config 文件夹,选择 deployment.amd64.json 文件,然后选择“选择 Edge 部署清单”。

  4. 在设备下,展开“模块”可查看已部署的正在运行的模块的列表。 单击“刷新”按钮。 此时应看到新的 CSharpFunctionSimulatedTemperatureSensor 模块以及 $edgeAgent$edgeHub 一起运行。

    新模块显示可能需要一些时间。 IoT Edge 设备必须从 IoT 中心检索其新的部署信息,启动新容器,然后将状态报告回 IoT 中心。

    显示如何在 Visual Studio Code 中查看已部署模块的屏幕截图。

查看生成的数据

要查看从所有设备到达 IoT 中心的所有消息,请在命令面板中运行“Azure IoT Hub:开始监视内置事件终结点”。 若要停止监视消息,请在命令面板中运行 Azure IoT Hub:停止监视内置事件终结点

也可通过筛选视图来查看从特定设备到达 IoT 中心的所有消息。 右键单击 Visual Studio Code 资源管理器的“Azure IoT 中心”>“设备”部分,然后选择“启动监视内置事件终结点”。

清理资源

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

否则,可以删除本文中创建的本地配置和 Azure 资源,以避免收费。

删除 Azure 资源

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

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

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

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

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

后续步骤

在本教程中,你已创建一个 Azure 函数模块,其中包含用于筛选 IoT Edge 设备生成的原始数据的代码。

继续阅读后续教程,了解如何使用 Azure IoT Edge 通过其他方式将数据转化为边缘业务见解。