Azure IoT Edge 常见问题的解决方案

注意

本文引用了 CentOS,这是一个处于生命周期结束 (EOL) 状态的 Linux 发行版。 请相应地考虑你的使用和规划。 有关详细信息,请参阅 CentOS 生命周期结束指南

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

重要

IoT Edge 1.5 LTS 和 IoT Edge 1.4 LTS 是受支持的版本。 IoT Edge 1.4 LTS 的生命周期结束日期为 2024 年 11 月 12 日。 如果你使用的是较低的版本,请参阅更新 IoT Edge

使用本文可识别并解决使用 IoT Edge 解决方案时的常见问题。 如需了解如何从 IoT Edge 设备查找日志和错误,请参阅对 IoT Edge 设备进行故障排除

预配和部署

IoT Edge 模块部署成功后,会从设备中消失

症状

为 IoT Edge 设备设置模块后即表示已成功部署模块,但几分钟后,它们将从设备以及 Azure 门户中的设备详细信息中消失。 除了定义的模块外,其他模块也可能会出现在设备上。

原因

如果针对某个设备进行自动部署,则自动部署的优先级高于为单个设备手动设置模块。 Azure 门户中的“设置模块”功能或 Visual Studio Code 中的“为单个设备创建部署”功能会暂时生效。 你会看到定义的模块在设备上启动。 然后,自动部署的优先级开始生效,并覆盖该设备的所需属性。

解决方案

每个设备仅使用一种类型的部署机制,即自动部署或单设备部署。 如果你有针对某个设备的多个自动部署,则可以更改优先级或目标说明,以确保正确的部署应用于给定的设备。 还可以更新设备孪生,使其不再与自动部署的目标描述匹配。

有关详细信息,请参阅了解单个设备或大规模的 IoT Edge 自动部署

IoT Edge 运行时

IoT Edge 代理在一分钟后停止

症状

edgeAgent 模块会启动并成功运行大约一分钟,然后停止。 日志表明,IoT Edge 代理尝试通过 AMQP 连接到 IoT 中心,并且尝试使用 AMQP 通过 WebSocket 进行连接。 该操作失败时,IoT Edge 代理将会退出。

示例 edgeAgent 日志:

2017-11-28 18:46:19 [INF] - Starting module management agent.
2017-11-28 18:46:19 [INF] - Version - 1.0.7516610 (03c94f85d0833a861a43c669842f0817924911d5)
2017-11-28 18:46:19 [INF] - Edge agent attempting to connect to IoT Hub via AMQP...
2017-11-28 18:46:49 [INF] - Edge agent attempting to connect to IoT Hub via AMQP over WebSocket...

原因

主机网络上的某个网络配置阻止 IoT Edge 代理到达该网络。 代理首先会尝试通过 AMQP(端口 5671)进行连接。 如果连接失败,它将尝试 WebSocket(端口 443)。

IoT Edge 运行时会为每个模块设置要在其中进行通信的网络。 在 Linux 上,此网络是一个桥网络。 在 Windows 上,它使用 NAT。 此问题在其中的 Windows 容器使用 NAT 网络的 Windows 设备上更为常见。

解决方案

确保分配给此桥/NAT 网络的 IP 地址具有通向 Internet 的路由。 有时候,主机上的 VPN 配置会替代 IoT Edge 网络。

Edge 代理模块报告“配置文件为空”,且设备上不会启动任何模块

症状

  • 设备在启动部署中定义的模块时出现问题。 只有 edgeAgent 在运行,但它持续报告“配置文件为空...”。

  • 在设备上运行 sudo iotedge check 时,它会报告“容器引擎未配置 DNS 服务器设置,这可能会影响到 IoT 中心的连接”。有关最佳做法,请参阅 https://aka.ms/iotedge-prod-checklist-dns

原因

  • 默认情况下,IoT Edge 在模块自身的隔离容器网络中启动模块。 在此专用网络中,设备可能会遇到 DNS 名称解析方面的问题。
  • 如果正在使用 IoT Edge 的快照安装,则 Docker 配置文件是不同的位置。 请参阅解决方案选项 3。

解决方案

选项 1:在容器引擎设置中设置 DNS 服务器

在容器引擎设置中为环境指定 DNS 服务器,该设置将应用于引擎启动的所有容器模块。 创建一个名为 daemon.json 的文件,然后指定要使用的 DNS 服务器。 例如:

{
    "dns": ["1.1.1.1"]
}

此 DNS 服务器设置为可公开访问的 DNS 服务。 但是,某些网络(如公司网络)安装了自己的 DNS 服务器,不允许访问公共 DNS 服务器。 因此,如果边缘设备无法访问公共 DNS 服务器,请将其替换为可访问的 DNS 服务器地址。

daemon.json 放入设备的 /etc/docker 目录。

如果该位置已包含 daemon.json 文件,请在其中添加 dns 密钥,然后保存该文件。

重启容器引擎以使更新生效。

sudo systemctl restart docker

选项 2:在每个模块的 IoT Edge 部署中设置 DNS 服务器

可以针对 IoT Edge 部署中每个模块的 createOptions 设置 DNS 服务器。 例如:

"createOptions": {
  "HostConfig": {
    "Dns": [
      "x.x.x.x"
    ]
  }
}

警告

如果使用此方法并指定错误的 DNS 地址,edgeAgent 将失去与 IoT 中心的连接,并且无法接收新部署来解决此问题。 若要解决此问题,可以重新安装 IoT Edge 运行时。 在安装新的 IoT Edge 实例之前,请务必从之前的安装中删除所有 edgeAgent 容器。

请确保也为 edgeAgentedgeHub 模块设置此配置。

选项 3:传递 docker 配置文件的位置以检查命令

如果 IoT Edge 作为快照安装,请使用--container-engine-config-file参数指定 Docker 配置文件的位置。 例如,如果 Docker 配置文件位于/var/snap/docker/current/config/daemon.json,请运行以下命令:iotedge check --container-engine-config-file '/var/snap/docker/current/config/daemon.json'

目前,即使设置了配置文件位置,警告消息仍会继续显示在iotedge 检查的输出中。 检查报告错误,因为 IoT Edge 管理单元没有 Docker 管理单元的读取访问权限。 如果在发布过程中使用iotedge 检查,可以使用--ignore container-engine-dns container-engine-logrotate参数禁止显示警告消息。

配置了 LTE 连接的 Edge 代理模块报告“Edge 代理配置为空”并导致“暂时性网络错误”

症状

配置了 LTE 连接的设备在启动部署中定义的模块时出现问题。 edgeAgent 无法连接到 IoT 中心,并报告“Edge 代理配置为空”和“发生暂时性网络错误”。

原因

某些网络存在数据包开销,导致默认 Docker 网络 MTU (1500) 过高和数据包分段,从而导致无法访问外部资源。

解决方案

  1. 检查 Docker 网络的 MTU 设置。

    docker network inspect <network name>

  2. 检查设备上物理网络适配器的 MTU 设置。

    ip addr show eth0

注意

Docker 网络的 MTU 不能高于设备的 MTU。 有关详细信息,请联系 ISP。

如果你发现 Docker 网络和设备的 MTU 大小不同,请尝试以下解决方法:

  1. 创建新网络。 例如,应用于对象的

    docker network create --opt com.docker.network.driver.mtu=1430 test-mtu

    在此示例中,设备的 MTU 设置为 1430。 因此,Docker 网络的 MTU 设置为 1430。

  2. 停止并删除 Azure 网络。

    docker network rm azure-iot-edge

  3. 重新创建 Azure 网络。

    docker network create --opt com.docker.network.driver.mtu=1430 azure-iot-edge

  4. 删除所有容器并重启 aziot-edged 服务。

    sudo iotedge system stop && sudo docker rm -f $(docker ps -aq -f "label=net.azure-devices.edge.owner=Microsoft.Azure.Devices.Edge.Agent") && sudo iotedge config apply

IoT Edge 代理无法访问某个模块的映像 (403)

症状

某个容器未能运行,edgeAgent 日志报告 403 错误。

原因

IoT Edge 代理模块无权访问某个模块的映像。

解决方案

确保设备部署清单中的容器注册表凭据正确。

IoT Edge 代理标识调用次数过多

现象

IoT Edge 代理对 Azure IoT 中心的标识调用次数过多。

原因

设备部署清单配置错误导致设备上的部署失败。 IoT Edge 代理重试逻辑继续重试部署。 每次重试都会进行标识调用,直到部署成功。 例如,如果部署清单指定了容器注册表中不存在或错误输入的模块 URI,则 IoT Edge 代理会重试部署,直到更正部署清单为止。

解决方案

在 Azure 门户中验证部署清单。 更正任何错误并将清单重新部署到设备。

IoT Edge 中心未能启动

症状

edgeHub 模块未能启动。 你可能会在日志中看到一条类似于以下错误的消息:

One or more errors occurred.
(Docker API responded with status code=InternalServerError, response=
{\"message\":\"driver failed programming external connectivity on endpoint edgeHub (6a82e5e994bab5187939049684fb64efe07606d2bb8a4cc5655b2a9bad5f8c80):
Error starting userland proxy: Bind for 0.0.0.0:443 failed: port is already allocated\"}\n)

info: edgelet_docker::runtime -- Starting module edgeHub...
warn: edgelet_utils::logging -- Could not start module edgeHub
warn: edgelet_utils::logging -- caused by: failed to create endpoint edgeHub on network nat: hnsCall failed in Win32:
        The process cannot access the file because it is being used by another process. (0x20)

原因

主机上的其他某个进程绑定了 edgeHub 模块尝试绑定的端口。 用于网关方案的 IoT Edge 中心映射端口 443、5671 和 8883。 如果另一个进程已绑定了其中某个端口,则无法启动该模块。

解决方案

可通过两种方式解决此问题:

如果 IoT Edge 设备充当网关设备,则你需要查找并停止正在使用端口 443、5671 或 8883 的进程。 端口 443 的错误通常表示另一个进程是 Web 服务器。

如果不需要将 IoT Edge 设备用作网关,则可以从 edgeHub 的模块创建选项中删除端口绑定。 可以在 Azure 门户中更改创建选项,也可直接在 deployment.json 文件中进行更改。

在 Azure 门户中:

  1. 导航到 IoT 中心,然后在“设备管理”菜单下选择“设备”。

  2. 选择要更新的 IoT Edge 设备。

  3. 选择“设置模块”。

  4. 选择“运行时设置”。

  5. 在“Edge Hub”模块设置中,从“容器创建选项”文本框中删除所有内容。

  6. 选择“应用”以保存更改并创建部署。

在 deployment.json 文件中:

  1. 打开应用到 IoT Edge 设备的 deployment.json 文件。

  2. 在 edgeAgent 所需属性部分找到 edgeHub 设置:

      "edgeHub": {
          "restartPolicy": "always",
          "settings": {
             "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
             "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
          },
          "status": "running",
          "type": "docker"
       }
    
  3. 删除 createOptions 行,并删除其前面的 image 行的尾随逗号:

      "edgeHub": {
          "restartPolicy": "always",
          "settings": {
          "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
          "status": "running",
          "type": "docker"
    }
    
  4. 选择“创建”以再次将其应用于 IoT Edge 设备。

IoT Edge 模块未能将消息发送到 edgeHub 并出现 404 错误

症状

自定义 IoT Edge 模块未能将消息发送到 IoT Edge 中心并出现 404 Module not found 错误。 IoT Edge 运行时在日志中输出以下消息:

Error: Time:Thu Jun  4 19:44:58 2018 File:/usr/sdk/src/c/provisioning_client/adapters/hsm_client_http_edge.c Func:on_edge_hsm_http_recv Line:364 executing HTTP request fails, status=404, response_buffer={"message":"Module not found"}u, 04 )

原因

出于安全考虑,IoT Edge 运行时会强制对连接到 edgeHub 的所有模块执行进程识别。 它会验证某个模块发送的所有消息是否来自该模块的主进程 ID。 如果发送消息的模块的进程 ID 不同于最初建立的进程 ID,则守护程序会拒绝该消息并返回 404 错误消息。

解决方案

从版本 1.0.7 开始,所有模块进程都有权进行连接。 有关详细信息,请参阅 1.0.7 版本更改日志

如果无法升级到 1.0.7,请完成以下步骤。 确保自定义 IoT Edge 模块始终使用相同的进程 ID 向 Edge 中心发送消息。 例如,请确保在 Docker 文件中使用 ENTRYPOINT,而不使用 CMD 命令。 CMD 命令会导致为模块生成一个进程 ID,并为运行主程序的 bash 命令生成另一个进程 ID,但是 ENTRYPOINT 只会生成单个进程 ID。

小型设备上的稳定性问题

症状

你可能会在 Raspberry Pi 等资源受限设备上遇到稳定性问题,尤其是在这些设备用作网关时。 症状包括 IoT Edge 中心模块出现“内存不足”异常、下游设备无法连接或者设备在几小时后无法发送遥测消息。

原因

IoT Edge 中心是 IoT Edge 运行时的一部分,默认情况下已针对性能进行了优化,并尝试分配大块内存。 这种优化对于受限边缘设备并不理想,可能会导致稳定性问题。

解决方案

对于 IoT Edge 中心,请将环境变量 OptimizeForPerformance 设置为 false。 可以通过两种方式来设置环境变量:

在 Azure 门户中:

  1. 在 IoT 中心,选择 IoT Edge 设备,然后从设备详细信息页中依次选择“设置模块”>“运行时设置” 。

  2. 为 IoT Edge 中心模块创建名为 OptimizeForPerformanceTrue/False 类型设置为 False 的环境变量。

  3. 选择“应用”以保存更改,然后选择“查看 + 创建”。

    该环境变量现在位于部署清单的 edgeHub 属性中:

       "edgeHub": {
          "env": {
                "OptimizeForPerformance": {
                   "value": false
                }
          },
          "restartPolicy": "always",
          "settings": {
                "image": "mcr.microsoft.com/azureiotedge-hub:1.5",
                "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"443/tcp\":[{\"HostPort\":\"443\"}],\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}]}}}"
          },
          "status": "running",
          "type": "docker"
       }
    
  4. 选择“创建”以保存更改并部署模块。

安全守护程序无法成功启动

症状

安全守护程序无法启动,并且模块容器未创建。 edgeAgentedgeHub 和其他自定义模块未通过 IoT Edge 服务启动。 在 aziot-edged 日志中,会看到此错误:

  • 守护程序无法成功启动:无法启动管理服务
  • 原因:路径 /var/run/iotedge/mgmt.sock 出错
  • 原因:权限被拒绝(操作系统错误 13)

原因

对于所有 Linux 发行版(CentOS 7 除外),IoT Edge 的默认配置是使用 systemd 套接字激活。 如果将配置文件更改为不使用套接字激活,而将 URL 保留为 /var/run/iotedge/*.sock,则会发生权限错误,因为 iotedge 用户无法写入 /var/run/iotedge,这也意味着它无法自己解锁和装载套接字。

解决方案

不需要在支持套接字激活的发行版上禁用套接字激活。 但是,如果不想使用套接字激活,请将套接字置于 /var/lib/iotedge/

  1. 运行 systemctl disable iotedge.socket iotedge.mgmt.socket 以禁用套接字单元,使 systemd 不会不必要地启动它们
  2. 将 iotedge 配置更改为在 connectlisten 部分中同时使用 /var/lib/iotedge/*.sock
  3. 如果已经有模块,则它们具有旧 /var/run/iotedge/*.sock 装载,因此 docker rm -f 它们。

消息队列清理速度缓慢

现象

处理消息后不会清理消息队列。 消息队列随着时间推移而增长,最终会导致 IoT Edge 运行时内存不足。

原因

消息清理间隔由客户端消息 TTL(生存时间)和 EdgeHub MessageCleanupIntervalSecs 环境变量控制。 默认消息 TTL 值为 2 小时,默认 MessageCleanupIntervalSecs 值为 30 分钟。 如果应用程序使用的 TTL 值短于默认值,并且不会调整 MessageCleanupIntervalSecs 值,则在下一个清理间隔之前不会清理过期的消息。

解决方案

如果更改短于默认值的应用程序的 TTL 值,则还要调整 MessageCleanupIntervalSecs 值。 MessageCleanupIntervalSecs 值应明显小于客户端使用的最小 TTL 值。 例如,如果客户端应用程序在消息标头中定义 TTL 为 5 分钟,请将 MessageCleanupIntervalSecs 值设置为 1 分钟。 这些设置可确保在 6 (5 + 1) 分钟内清理消息。

若要配置 MessageCleanupIntervalSecs 值,请在 IoT Edge 中心模块的部署清单中设置环境变量。 有关设置运行时环境变量的详细信息,请参阅 Edge 代理和 Edge 中心环境变量

网络

由于主机名无效,IoT Edge 安全守护程序失败

症状

尝试检查 IoT Edge 安全管理器日志失败,并输出以下消息:

Error parsing user input data: invalid hostname. Hostname cannot be empty or greater than 64 characters

原因

IoT Edge 运行时只支持短于 64 个字符的主机名。 物理计算机通常不具有长主机名,但此问题在虚拟机上更常见。 特别是为 Azure 中托管的 Windows 虚拟机自动生成的主机名,往往会很长。

解决方案

看到此错误时,可以配置虚拟机的 DNS 名称,然后在设置命令中将 DNS 名称设置为主机名。

  1. 在 Azure 门户中,导航到虚拟机的概述页面。

  2. 通过选择“未配置”链接(如果你的虚拟机是新的)打开配置面板,或在“概要”>“DNS 名称”下选择你现有的 DNS 名称。 如果你的虚拟机已配置 DNS 名称,则不需要再配置。

  3. 提供“DNS 名称标签”的值(如果尚未提供),然后选择“保存”。

  4. 复制新的 DNS 名称,其格式应为:
    <DNSnamelabel>.<vmlocation>.cloudapp.chinacloudapi.cn.

  5. 在 IoT Edge 设备上,打开配置文件。

    sudo nano /etc/aziot/config.toml
    
  6. hostname 的值替换为你的 DNS 名称。

  7. 保存并关闭该文件,然后将更改应用到 IoT Edge。

    sudo iotedge config apply
    

IoT Edge 模块报告连接错误

症状

直接连接云服务的 IoT Edge 模块(包括运行时模块)停止正常工作,并返回有关连接或网络故障的错误。

原因

容器依赖于 IP 数据包转发来连接到 Internet,以便可以与云服务通信。 默认情况下,在 Docker 中启用 IP 数据包转发,但如果禁用了它,则连接到云服务的任何模块都将无法按预期方式工作。 有关详细信息,请参阅 Docker 文档中的了解容器通信

解决方案

使用以下步骤启用 IP 数据包转发。

  1. 打开 sysctl.conf 文件。

    sudo nano /etc/sysctl.conf
    
  2. 将以下行添加到该文件。

    net.ipv4.ip_forward=1
    
  3. 保存并关闭该文件。

  4. 重启网络服务和 docker 服务以应用更改。

网关后面的 IoT Edge 无法执行 HTTP 请求和启动 edgeAgent 模块

症状

使用有效的配置文件时,IoT Edge 运行时处于活动状态,但它无法启动 edgeAgent 模块。 命令 iotedge list 返回一个空列表。 日志中的 IoT Edge 运行时报告“Could not perform HTTP request”。

原因

网关后面的 IoT Edge 设备将从父 IoT Edge 设备(在配置文件的 parent_hostname 字段中指定)获取其模块映像。 “Could not perform HTTP request”错误表示下游设备无法通过 HTTP 访问其父设备。

解决方案

请确保父 IoT Edge 设备可以接收来自下游 IoT Edge 设备的传入请求。 在端口 443 和 6617 上打开网络流量,以获取来自下游设备的请求。

网关后面的 IoT Edge 无法执行 HTTP 请求和启动 edgeAgent 模块

症状

使用有效的配置文件时,IoT Edge 守护程序处于活动状态,但它无法启动 edgeAgent 模块。 命令 iotedge list 返回一个空列表。 IoT Edge 守护程序日志报告 Could not perform HTTP request

原因

网关后面的 IoT Edge 设备将从父 IoT Edge 设备(在配置文件的 parent_hostname 字段中指定)获取其模块映像。 “Could not perform HTTP request”错误表示下游设备无法通过 HTTP 访问其父设备。

解决方案

请确保父 IoT Edge 设备可以接收来自下游 IoT Edge 设备的传入请求。 在端口 443 和 6617 上打开网络流量,以获取来自下游设备的请求。

从一个 IoT 中心迁移到另一个 IoT 中心时,网关后面的 IoT Edge 无法进行连接

症状

尝试将 IoT Edge 设备的层次结构从一个 IoT 中心迁移到另一个 IoT 中心时,顶级父 IoT Edge 设备可以连接到 IoT 中心,但下游 IoT Edge 设备不可以。 日志报告 Unable to authenticate client downstream-device/$edgeAgent with module credentials

原因

迁移到新的 IoT 中心时,下游设备的凭据未正确更新。 因此,edgeAgentedgeHub 模块被设置为具有身份验证类型 none(如果未明确设置,则为默认值)。 在连接过程中,下游设备上的模块使用旧凭据,导致身份验证失败。

解决方案

迁移到新的 IoT 中心时(假设不使用 DPS),请按顺序执行以下步骤:

  1. 按照本指南将设备标识从旧的 IoT 中心导出,然后导入到新的 IoT 中心
  2. 在新的 IoT 中心重新配置所有 IoT Edge 部署和配置
  3. 在新的 IoT 中心重新配置所有父子设备关系
  4. 更新每台设备以指向新的 IoT 中心主机名(config.toml[provisioning] 下的 iothub_hostname
  5. 如果选择了在设备导出期间排除身份验证密钥,请使用新 IoT 中心(config.toml[provisioning.authentication] 下的 device_id_pk)提供的新密钥重新配置每个设备
  6. 首先重启顶级父 Edge 设备,确保它已启动并在运行
  7. 从上到下逐级重启层次结构中的每个设备

在地理位置上远离 IoT 中心时,IoT Edge 消息吞吐量较低

症状

在地理位置上远离 Azure IoT 中心的 Azure IoT Edge 设备的消息吞吐量低于预期。

原因

设备和 IoT 中心之间的高延迟可能会导致消息吞吐量低于预期。 IoT Edge 使用的默认消息批大小为 10。 这会限制在单个批处理中发送的消息数,从而增加设备和 IoT 中心之间的往返次数。

解决方案

尝试增加 IoT Edge 中心 MaxUpstreamBatchSize 环境变量。 可通过该方法在单个批处理中发送更多消息,从而减少设备和 IoT 中心之间的往返次数。

若要在 Azure 门户中设置 Azure Edge 中心环境变量,请执行以下操作:

  1. 导航到 IoT 中心,然后在“设备管理”菜单下选择“设备”。
  2. 选择要更新的 IoT Edge 设备。
  3. 选择“设置模块”。
  4. 选择“运行时设置”。
  5. 在“Edge 中心”模块设置选项卡中,将 MaxUpstreamBatchSize 环境变量添加为“数字”类型,值为 20
  6. 选择“应用”。

后续步骤

认为在 IoT Edge 平台中发现了 bug? 提交问题,以便我们可以持续改进。

如果你还有其他问题,请创建支持请求以获取帮助。