了解如何在 IoT Edge 中部署模块和建立路由Learn how to deploy modules and establish routes in IoT Edge

每个 IoT Edge 设备至少运行两个模块:$edgeAgent 和 $edgeHub,它们构成了 IoT Edge 运行时。Each IoT Edge device runs at least two modules: $edgeAgent and $edgeHub, which are part of the IoT Edge runtime. IoT Edge 设备可以为任意数量的进程运行多个附加模块。IoT Edge device can run multiple additional modules for any number of processes. 使用部署清单告知设备要安装哪些模块以及如何将它们配置为协同工作。Use a deployment manifest to tell your device which modules to install and how to configure them to work together.

部署清单是一个 JSON 文档,用于描述以下内容:The deployment manifest is a JSON document that describes:

  • IoT Edge 代理 模块孪生,其中包括三个组件:The IoT Edge agent module twin, which includes three components:
    • 在设备上运行的每个模块的容器映像。The container image for each module that runs on the device.
    • 用于访问包含模块映像的专用容器注册表的凭据。The credentials to access private container registries that contain module images.
    • 有关如何创建和管理每个模块的说明。Instructions for how each module should be created and managed.
  • IoT Edge 中心 模块孪生:描述消息如何在模块之间流动,并最终传送到 IoT 中心。The IoT Edge hub module twin, which includes how messages flow between modules and eventually to IoT Hub.
  • 任何附加模块孪生的所需属性(可选)。The desired properties of any additional module twins (optional).

必须使用部署清单配置所有 IoT Edge 设备。All IoT Edge devices must be configured with a deployment manifest. 在使用有效清单进行配置前,新安装的 IoT Edge 运行时会报告错误代码。A newly installed IoT Edge runtime reports an error code until configured with a valid manifest.

在 Azure IoT Edge 教程中,你将通过 Azure IoT Edge 门户中的向导生成部署清单。In the Azure IoT Edge tutorials, you build a deployment manifest by going through a wizard in the Azure IoT Edge portal. 此外,也可以使用 REST 或 IoT 中心服务 SDK 以编程方式应用部署清单。You can also apply a deployment manifest programmatically using REST or the IoT Hub Service SDK. 有关详细信息,请参阅了解 IoT Edge 部署For more information, see Understand IoT Edge deployments.

创建部署清单。Create a deployment manifest

从较高层面讲,部署清单是配置了所需属性的模块孪生的列表。At a high level, a deployment manifest is a list of module twins that are configured with their desired properties. 部署清单告知某个 IoT Edge 设备(或一组设备)要安装哪些模块,以及如何配置这些模块。A deployment manifest tells an IoT Edge device (or a group of devices) which modules to install and how to configure them. 部署清单包含每个模块孪生的所需属性。Deployment manifests include the desired properties for each module twin. IoT Edge 设备将报告每个模块的报告属性。IoT Edge devices report back the reported properties for each module.

每个部署清单中需要两个模块:$edgeAgent$edgeHubTwo modules are required in every deployment manifest: $edgeAgent, and $edgeHub. 这些模块属于管理 IoT Edge 设备及其上运行的模块的 IoT Edge 运行时。These modules are part of the IoT Edge runtime that manages the IoT Edge device and the modules running on it. 有关这些模块的详细信息,请参阅了解 IoT Edge 运行时及其体系结构For more information about these modules, see Understand the IoT Edge runtime and its architecture.

除了两个运行时模块以外,还可以添加最多 50 个你自己的要在 IoT Edge 设备上运行的模块。In addition to the two runtime modules, you can add up to 50 modules of your own to run on an IoT Edge device.

仅包含 IoT Edge 运行时(edgeAgent 和 edgeHub)的部署清单是有效的。A deployment manifest that contains only the IoT Edge runtime (edgeAgent and edgeHub) is valid.

部署清单遵循以下结构:Deployment manifests follow this structure:

{
  "modulesContent": {
    "$edgeAgent": { // required
      "properties.desired": {
        // desired properties of the IoT Edge agent
        // includes the image URIs of all deployed modules
        // includes container registry credentials
      }
    },
    "$edgeHub": { //required
      "properties.desired": {
        // desired properties of the IoT Edge hub
        // includes the routing information between modules, and to IoT Hub
      }
    },
    "module1": {  // optional
      "properties.desired": {
        // desired properties of module1
      }
    },
    "module2": {  // optional
      "properties.desired": {
        // desired properties of module2
      }
    }
  }
}

配置模块Configure modules

定义 IoT Edge 运行时如何在部署中安装模块。Define how the IoT Edge runtime installs the modules in your deployment. IoT Edge 代理是管理 IoT Edge 设备的安装、更新和状态报告的运行时组件。The IoT Edge agent is the runtime component that manages installation, updates, and status reporting for an IoT Edge device. 因此,$edgeAgent 模块孪生包含所有模块的配置和管理信息。Therefore, the $edgeAgent module twin contains the configuration and management information for all modules. 此信息包括 IoT Edge 代理本身的配置参数。This information includes the configuration parameters for the IoT Edge agent itself.

$edgeAgent 属性遵循此结构:The $edgeAgent properties follow this structure:

{
  "modulesContent": {
    "$edgeAgent": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "runtime": {
          "settings":{
            "registryCredentials":{
              // give the IoT Edge agent access to container images that aren't public
            }
          }
        },
        "systemModules": {
          "edgeAgent": {
            // configuration and management details
          },
          "edgeHub": {
            // configuration and management details
          }
        },
        "modules": {
          "module1": {
            // configuration and management details
          },
          "module2": {
            // configuration and management details
          }
        }
      }
    },
    "$edgeHub": { ... },
    "module1": { ... },
    "module2": { ... }
  }
}

IoT Edge 代理架构版本 1.1 随 IoT Edge 版本 1.0.10 一起发布,并启用了模块启动顺序。The IoT Edge agent schema version 1.1 was released along with IoT Edge version 1.0.10, and enables module startup order. 对于运行版本 1.0.10 或更高版本的 IoT Edge 部署,建议使用架构版本 1.1。Schema version 1.1 is recommended for any IoT Edge deployment running version 1.0.10 or later.

模块配置和管理Module configuration and management

在 IoT Edge 代理所需的属性列表中,你定义要将哪些模块部署到 IoT Edge 设备以及如何配置和管理它们。The IoT Edge agent desired properties list is where you define which modules are deployed to an IoT Edge device and how they should be configured and managed.

有关可以或必须包含的所需属性的完整列表,请参阅 IoT Edge 代理和 IoT Edge 中心的属性For a complete list of desired properties that can or must be included, see Properties of the IoT Edge agent and IoT Edge hub.

例如:For example:

{
  "modulesContent": {
    "$edgeAgent": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "runtime": { ... },
        "systemModules": {
          "edgeAgent": { ... },
          "edgeHub": { ... }
        },
        "modules": {
          "module1": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "startupOrder": 2,
            "settings": {
              "image": "myacr.azurecr.cn/module1:latest",
              "createOptions": "{}"
            }
          },
          "module2": { ... }
        }
      }
    },
    "$edgeHub": { ... },
    "module1": { ... },
    "module2": { ... }
  }
}

每个模块都具有 settings 属性,其中包含模块 image、容器注册表中容器映像的地址,以及任何用于在启动时配置映像的 createOptions 。Every module has a settings property that contains the module image, an address for the container image in a container registry, and any createOptions to configure the image on startup. 若要了解详细信息,请参阅如何配置 IoT Edge 模块的容器创建选项For more information, see How to configure container create options for IoT Edge modules.

EdgeHub 模块和自定义模块还具有三个属性,这些属性告诉 IoT Edge 代理如何管理它们:The edgeHub module and custom modules also have three properties that tell the IoT Edge agent how to manage them:

  • 状态:首次部署后,模块是应该运行还是停止。Status: Whether the module should be running or stopped when first deployed. 必需。Required.

  • RestartPolicy:如果 IoT Edge 代理停止,则何时以及是否应重新启动该模块。RestartPolicy: When and if the IoT Edge agent should restart the module if it stops. 必需。Required.

  • StartupOrder:在 IoT Edge 版本 1.0.10 中引入。StartupOrder: Introduced in IoT Edge version 1.0.10. 首次部署时,IoT Edge 代理应按哪个顺序启动模块。Which order the IoT Edge agent should start the modules when first deployed. 此顺序是使用整数进行声明的,其中先启动给定启动值为 0 的模块,然后再启动更高值的模块。The order is declared with integers, where a module given a startup value of 0 is started first and then higher numbers follow. EdgeAgent 模块没有启动值,因为它始终先启动。The edgeAgent module doesn't have a startup value because it always starts first. 可选。Optional.

    IoT Edge 代理按启动值的顺序启动模块,但不会等待每个模块完成启动才转到下一个模块。The IoT Edge agent initiates the modules in order of the startup value, but does not wait for each module to finish starting before going to the next one.

    如果某些模块依赖于其他模块,启动顺序会很有用。Startup order is helpful if some modules depend on others. 例如,你可能希望 edgeHub 模块先启动,以便在其他模块启动时准备好路由消息。For example, you may want the edgeHub module to start first so that it's ready to route messages when the other modules start. 或者,你可能想先启动某个存储模块,然后再启动向其发送数据的模块。Or you may want to start a storage module before the modules that send data to it. 但是,你应该始终将模块设计为处理其他模块的故障。However, you should always design your modules to handle failures of other modules. 容器的性质使其可能在任何时间停止并重新启动任何次数。It's the nature of containers that they may stop and restart at any time, and any number of times.

声明路由Declare routes

IoT Edge 中心管理模块、IoT 中心与所有叶设备之间的通信。The IoT Edge hub manages communication between modules, IoT Hub, and any leaf devices. 因此,$edgeHub 模块孪生包含名为 routes 的所需属性,该属性声明如何在部署中传递消息。Therefore, the $edgeHub module twin contains a desired property called routes that declares how messages are passed within a deployment. 可以在同一个部署中创建多个路由。You can have multiple routes within the same deployment.

使用以下语法在 $edgeHub 所需属性中声明路由:Routes are declared in the $edgeHub desired properties with the following syntax:

{
  "modulesContent": {
    "$edgeAgent": { ... },
    "$edgeHub": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "routes": {
          "route1": "FROM <source> WHERE <condition> INTO <sink>",
          "route2": {
            "route": "FROM <source> WHERE <condition> INTO <sink>",
            "priority": 0,
            "timeToLiveSecs": 86400
          }
        },
        "storeAndForwardConfiguration": {
          "timeToLiveSecs": 10
        }
      }
    },
    "module1": { ... },
    "module2": { ... }
  }
}

IoT Edge 中心架构版本 1.1 随 IoT Edge 版本 1.0.10 一起发布,并启用了路由优先级和生存时间。The IoT Edge hub schema version 1.1 was released along with IoT Edge version 1.0.10, and enables route prioritization and time to live. 对于运行版本 1.0.10 或更高版本的 IoT Edge 部署,建议使用架构版本 1.1。Schema version 1.1 is recommended for any IoT Edge deployment running version 1.0.10 or later.

每一个路由都需要一个消息源和一个消息去往的接收器 。Every route needs a source where the messages come from and a sink where the messages go. 条件是可用于筛选消息的可选片断。The condition is an optional piece that you can use to filter messages.

你可以将优先级分配给要确保优先处理消息的路由。You can assign priority to routes that you want to make sure process their messages first. 在上游连接较弱或受限且有需要优先于标准遥测消息进行处理的关键数据的情况下,此功能很有用。This feature is helpful in scenarios where the upstream connection is weak or limited and you have critical data that should be prioritized over standard telemetry messages.

Source

源指定消息来自何处。The source specifies where the messages come from. IoT Edge 可以路由来自模块或叶设备的消息。IoT Edge can route messages from modules or leaf devices.

通过 IoT SDK,模块可以使用 ModuleClient 类为其消息声明特定的输出队列。Using the IoT SDKs, modules can declare specific output queues for their messages using the ModuleClient class. 输出队列不是必需的,但对于管理多个路由很有帮助。Output queues aren't necessary, but are helpful for managing multiple routes. 叶设备可以使用 IoT SDK 的 DeviceClient 类将消息发送到 IoT Edge 网关设备,就像它们将消息发送到 IoT 中心一样。Leaf devices can use the DeviceClient class of the IoT SDKs to send messages to IoT Edge gateway devices in the same way that they would send messages to IoT Hub. 有关详细信息,请参阅了解和使用 Azure IoT 中心 SDKFor more information, see Understand and use Azure IoT Hub SDKs.

源属性可采用以下任何值:The source property can be any of the following values:

Source 说明Description
/* 所有设备到云的消息,或者来自任何模块或叶设备的孪生更改通知All device-to-cloud messages or twin change notifications from any module or leaf device
/twinChangeNotifications 来自任何模块或叶设备的任何孪生更改(报告属性)Any twin change (reported properties) coming from any module or leaf device
/messages/* 由模块或叶设备通过某种输出或不通过任何输出发送的任何设备到云的消息Any device-to-cloud message sent by a module through some or no output, or by a leaf device
/messages/modules/* 由带部分输出或不带输出的模块发送的任何设备到云的消息Any device-to-cloud message sent by a module through some or no output
/messages/modules/<moduleId>/* 由特定模块通过某种输出或不通过任何输出发送的任何设备到云的消息Any device-to-cloud message sent by a specific module through some or no output
/messages/modules/<moduleId>/outputs/* 由特定模块通过某种输出发送的任何设备到云的消息Any device-to-cloud message sent by a specific module through some output
/messages/modules/<moduleId>/outputs/<output> 由特定模块通过特定输出发送的任何设备到云的消息Any device-to-cloud message sent by a specific module through a specific output

条件Condition

条件在路由声明中是可选的。The condition is optional in a route declaration. 若要将所有消息从源传递到接收器,完全省略 WHERE 子句即可。If you want to pass all messages from the source to the sink, just leave out the WHERE clause entirely. 或者,可以使用 IoT 中心查询语言来筛选满足条件的特定消息或消息类型。Or you can use the IoT Hub query language to filter for certain messages or message types that satisfy the condition. IoT Edge 路由不支持基于孪生标记或属性筛选消息。IoT Edge routes don't support filtering messages based on twin tags or properties.

在 IoT Edge 中的模块之间传递的消息与在设备和 Azure IoT 中心之间传递的消息的格式是一样的。The messages that pass between modules in IoT Edge are formatted the same as the messages that pass between your devices and Azure IoT Hub. 所有消息都是 JSON 格式的,并具备 systemProperties、appProperties 和 body 参数 。All messages are formatted as JSON and have systemProperties, appProperties, and body parameters.

可使用以下语法围绕三个参数中的任何一个生成查询:You can build queries around any of the three parameters with the following syntax:

  • 系统属性:$<propertyName>{$<propertyName>}System properties: $<propertyName> or {$<propertyName>}
  • 应用程序属性:<propertyName>Application properties: <propertyName>
  • 正文属性:$body.<propertyName>Body properties: $body.<propertyName>

请参考设备到云消息路由查询表达式,查看针对消息属性创建查询的示例。For examples about how to create queries for message properties, see Device-to-cloud message routes query expressions.

有一个 IoT Edge 特定的示例,即筛选从叶设备到网关设备的消息的情况。An example that is specific to IoT Edge is when you want to filter for messages that arrived at a gateway device from a leaf device. 来自模块的消息包含名为 connectionModuleId 的系统属性。Messages that come from modules include a system property called connectionModuleId. 因此,若要将消息从叶设备直接路由到 IoT 中心,请使用以下路由来排除模块消息:So if you want to route messages from leaf devices directly to IoT Hub, use the following route to exclude module messages:

FROM /messages/* WHERE NOT IS_DEFINED($connectionModuleId) INTO $upstream

接收器Sink

接收器定义消息发送到的位置。The sink defines where the messages are sent. 只有模块和 IoT 中心可以接收消息。Only modules and IoT Hub can receive messages. 无法将消息路由到其他设备。Messages can't be routed to other devices. 接收器属性中没有通配符选项。There are no wildcard options in the sink property.

接收器属性可采用以下任何值:The sink property can be any of the following values:

接收器Sink 说明Description
$upstream 将消息发送到 IoT 中心Send the message to IoT Hub
BrokeredEndpoint("/modules/<moduleId>/inputs/<input>") 将消息发送到特定模块的特定输入Send the message to a specific input of a specific module

IoT Edge 提供至少一次保证。IoT Edge provides at-least-once guarantees. IoT Edge 中心在本地存储消息,以防路由无法将消息传送到其接收器。The IoT Edge hub stores messages locally in case a route can't deliver the message to its sink. 例如,如果 IoT Edge 中心无法连接到 IoT 中心,或者目标模块未连接。For example, if the IoT Edge hub can't connect to IoT Hub, or the target module isn't connected.

IoT Edge 中心会一直存储消息,直到达到在 IoT Edge 中心所需属性storeAndForwardConfiguration.timeToLiveSecs 属性中指定的时间。IoT Edge hub stores the messages up to the time specified in the storeAndForwardConfiguration.timeToLiveSecs property of the IoT Edge hub desired properties.

优先级和生存时间Priority and time-to-live

可以使用仅定义路由的字符串或使用路由字符串、优先级整数和生存时间整数的对象声明路由。Routes can be declared with either just a string defining the route, or as an object that takes a route string, a priority integer, and a time-to-live integer.

选项 1:Option 1:

"route1": "FROM <source> WHERE <condition> INTO <sink>",

带有 IoT Edge 中心架构版本 1.1 的 IoT Edge 版本 1.0.10 中引入的选项 2:Option 2, introduced in IoT Edge version 1.0.10 with IoT Edge hub schema version 1.1:

"route2": {
  "route": "FROM <source> WHERE <condition> INTO <sink>",
  "priority": 0,
  "timeToLiveSecs": 86400
}

优先级 值可以是 0-9,其中 0 是最高优先级。Priority values can be 0-9, inclusive, where 0 is the highest priority. 消息的排队基于其终结点。Messages are queued up based on their endpoints. 在处理任何针对同一终结点的优先级 1 消息之前,将先处理针对特定终结点的所有优先级 0 消息。All priority 0 messages targeting a specific endpoint will be processed before any priority 1 messages targeting the same endpoint are processed, and down the line. 如果同一终结点的多个路由具有相同优先级,则将以先到先得的方式处理它们的消息。If multiple routes for the same endpoint have the same priority, their messages will be processed in a first-come-first-served basis. 如果未指定优先级,则将路由分配给最低优先级。If no priority is specified, the route is assigned to the lowest priority.

除非显式设置,否则 timeToLiveSecs 属性将从 IoT Edge 中心的 storeAndForwardConfiguration 继承其值 。The timeToLiveSecs property inherits its value from IoT Edge hub's storeAndForwardConfiguration unless explicitly set. 该值可以是任何正整数。The value can be any positive integer.

有关如何管理优先级队列的详细信息,请参阅参考页面以了解路由优先级和生存时间For detailed information about how priority queues are managed, see the reference page for Route priority and time-to-live.

定义或更新所需属性Define or update desired properties

部署清单指定部署到 IoT Edge 设备的每个模块的所需属性。The deployment manifest specifies desired properties for each module deployed to the IoT Edge device. 部署清单中的所需属性会覆盖模块孪生中当前存在的任何所需属性。Desired properties in the deployment manifest overwrite any desired properties currently in the module twin.

如果未在部署清单中指定模块孪生的所需属性,则 IoT 中心不会以任何方式修改模块孪生。If you do not specify a module twin's desired properties in the deployment manifest, IoT Hub won't modify the module twin in any way. 可以编程方式设置所需属性。Instead, you can set the desired properties programmatically.

将使用用来修改设备孪生的相同机制来修改模块孪生。The same mechanisms that allow you to modify device twins are used to modify module twins. 有关详细信息,请参阅模块孪生开发人员指南For more information, see the module twin developer guide.

部署清单示例Deployment manifest example

以下示例演示了有效部署清单文档的外观。The following example shows what a valid deployment manifest document may look like.

{
  "modulesContent": {
    "$edgeAgent": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "runtime": {
          "type": "docker",
          "settings": {
            "minDockerVersion": "v1.25",
            "loggingOptions": "",
            "registryCredentials": {
              "ContosoRegistry": {
                "username": "myacr",
                "password": "<password>",
                "address": "myacr.azurecr.cn"
              }
            }
          }
        },
        "systemModules": {
          "edgeAgent": {
            "type": "docker",
            "settings": {
              "image": "mcr.microsoft.com/azureiotedge-agent:1.1",
              "createOptions": ""
            }
          },
          "edgeHub": {
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "startupOrder": 0,
            "settings": {
              "image": "mcr.microsoft.com/azureiotedge-hub:1.1",
              "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
            }
          }
        },
        "modules": {
          "SimulatedTemperatureSensor": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "startupOrder": 2,
            "settings": {
              "image": "mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0",
              "createOptions": "{}"
            }
          },
          "filtermodule": {
            "version": "1.0",
            "type": "docker",
            "status": "running",
            "restartPolicy": "always",
            "startupOrder": 1,
            "env": {
              "tempLimit": {"value": "100"}
            },
            "settings": {
              "image": "myacr.azurecr.cn/filtermodule:latest",
              "createOptions": "{}"
            }
          }
        }
      }
    },
    "$edgeHub": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "routes": {
          "sensorToFilter": {
            "route": "FROM /messages/modules/SimulatedTemperatureSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filtermodule/inputs/input1\")",
            "priority": 0,
            "timeToLiveSecs": 1800
          },
          "filterToIoTHub": {
            "route": "FROM /messages/modules/filtermodule/outputs/output1 INTO $upstream",
            "priority": 1,
            "timeToLiveSecs": 1800
          }
        },
        "storeAndForwardConfiguration": {
          "timeToLiveSecs": 100
        }
      }
    }
  }
}

后续步骤Next steps