你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

用于实现低带宽连接的高效 Docker 映像部署

Azure 容器注册表
Azure Functions
Azure IoT Edge
Azure IoT 中心
Azure Pipelines

本文介绍一种解决方案,用于跨间歇性或低带宽 Internet 连接部署容器化物联网 (IoT) 边缘模块。

边缘处理是一种关键的物联网 (IoT) 模式,可提供低延迟连接并节省带宽,例如在移动方案中。 IoT 系统通常通过部署软件容器映像来预配边缘设备。 通过间歇性低带宽 Internet 连接中断的容器部署可能会导致移动方案中出现故障。 具有有限、间歇性或低带宽的 IoT 方案需要可靠且可复原的部署功能。

在此示例中,一家大型物流公司希望改进其全球产品运输跟踪。 该公司通过各种陆运、空运和海运方式将货物运送到许多地区,包括具有间歇性、低带宽 Internet 连接的地区。 出于保险、安全或跟踪目的,产品货物中安装了各种具有不同功能的 IoT 设备,具体取决于货物类型。 设备包括 GPS 跟踪器、温度传感器和数据捕获工具。

该公司在其最近开发的 Azure IoT Edge 平台上更新设备时遇到问题。 主要难题包括:

  • 将更新的软件部署到设备时的带宽消耗较高。
  • 没有跨设备的标准化自动化部署。
  • 技术选择的灵活性有限。

为了解决这些问题,开发团队创建了以下解决方案:

  • 最小化每个设备的部署规模,减少带宽。
  • 实现从 IoT Edge 平台到异质远程 IoT 设备的标准化 Docker 容器部署。
  • 启用可靠的部署监视。
  • 利用各种 Azure DevOps 和云服务,并使用客户的首选旧版工具。

此解决方案显著提高了在有限连接环境中的设备预配过程的可靠性和复原能力。 本文介绍解决方案详细信息和解决方案选项评估过程。

客户要求

此客户具有以下要求:

  • 解决方案必须支持间歇性低带宽云连接。
  • 部署的应用程序必须继续在本地运行。
  • 本地员工需要脱机使用功能,或者无云往返延迟。
  • 连接后,解决方案必须有效使用云连接。
  • 解决方案必须根据产品中一致定义的业务规则确定发送数据的优先级。

还有以下详细要求:

  • 通过低带宽间歇性连接卫星连接传输映像文件。
  • 传输的数据量应最小化。
  • 将文件传输到设备时使用客户的首选第三方应用程序。
  • 设备工作负载使用 IoT Edge 中的 Docker 映像。
  • 映像大小范围为几十 MB 到几 GB。
  • 用 .NET Core 2.2 编写 IoT Edge 模块。

可能的用例

此解决方案适用于 IoT 方案,其中软件容器通过低带宽、间歇性连接提供解决方案。 示例包括:

  • 远程石油、天然气和采矿监测
  • 无线汽车更新
  • 无法保证强连接的任何位置

体系结构

在高带宽方案中,Azure IoT Edge 直接从可通过 Internet 访问的 Docker 注册表中提取映像,可以是 Docker 中心,也可以是私有中心,如 Azure 容器注册表 (ACR)。 此功能与运行 docker pull <image_name> 命令相同。

使用可能具有间歇性的网络访问(如卫星 Internet 连接)时,Docker 拉取方法会变得不可靠。 如果在 Docker 拉取映像时 Internet 连接断开,则不会缓存进度。 Internet 连接恢复后,Docker 必须再次从头开始拉取映像。

该解决方案使用替代部署机制(Docker 映像文件的二进制修补)来减少带宽并补偿间歇性连接。

显示 Azure DevOps 和 Azure 高级解决方案体系结构的示意图。

数据流

  1. 开发人员与源代码存储库中的边缘模块源代码进行交互。
  2. 容器注册表存储每个模块的 Docker 映像。
  3. 清单存储库包含所有工作流的部署清单。
  4. 每个模块都有一个 Azure Pipelines 生成管道,该管道使用通用 Docker 生成自动创建和注册模块。
  5. 映像到设备管道将 Docker 映像部署到目标设备,如清单文件定义。
  6. 清单到设备管道将部署清单推送到待更新设备的正确 Azure IoT 中心。
  7. 第三方快速文件传输解决方案将文件从 Azure 存储帐户传输到设备。
  8. 映像重建 IoT Edge 模块在设备上应用收到的修补程序。
  9. IoT 中心从映像重建模块接收状态消息,并设置设备的部署清单。 管道流的其余部分使用此部署清单。
  10. Azure Functions 监视 IoT 中心消息流、更新 SQL 数据库,并通知用户成功或失败。
  11. Azure SQL 数据库跟踪目标设备和基于 Azure 的服务在部署期间和之后发生的事件。

组件

  • Azure IoT Edge 在设备上运行容器化工作负载,提供低延迟连接并节省带宽。
  • Azure IoT 中心是一种托管在云中的托管服务,在 IoT 应用程序和其控制的设备之间充当中央消息中心。
  • Azure 容器注册表是一种基于云的专用注册表服务,用于存储和管理专用 Docker 容器映像和相关项目。
  • Azure Pipelines 将持续集成 (CI) 和持续交付 (CD) 组合在一起,可以自动测试并生成代码,并将代码发送给任何目标。
  • Azure Functions 是一种无服务器计算平台,可以运行事件触发的代码,而无需预配或管理基础结构。
  • Azure 存储为所有类型的业务数据、对象和文件提供高度可缩放、安全、高性能和经济高效的存储。
  • Azure SQL 数据库是面向云生成的完全托管的多模式关系数据库服务。
  • Docker 是一个用于开发、传送和运行容器化应用程序的开放平台。

备选方法

开发团队在决定完整的 Docker 映像增量传输解决方案之前评估了多个选项。 以下部分介绍评估替代项和结果。

团队考虑了每个选项的以下评估条件:

  • 解决方案是否满足要求。
  • 无论需要在设备上实现低、中还是高逻辑。
  • 无论需要在 Azure 上实现低、中还是高逻辑。
  • 传输容器映像的带宽效率或传输数据与映像总大小的比率。

带宽效率包括以下情况:

  • 设备上不存在任何映像。
  • 设备上存在具有相同基础映像的映像。
  • 设备上存在以前应用程序版本的映像。
  • 设备上存在基于以前基础映像生成的应用程序的映像。

团队使用以下方案评估带宽效率:

方案 说明
传输在设备上已具有基层的映像 当设备上已有另一个映像共享基础映像时传输新映像。 此方案表示,同一 OS 和框架中已存在另一个应用程序时,首次部署新应用程序。
更新应用程序层 仅更改现有应用程序映像的代码。 此方案表示用户提交新功能时的典型更改。
更新基础映像 更改生成应用程序的基本映像的版本。

“传输 Docker 层”选项

Docker 容器映像是只读文件系统差异的 UnionFS 装载,另一个可写层用于运行容器时所做的更改。 文件系统称为,基本上是文件夹和文件。 层堆叠形成容器根文件系统的基础。 由于层是只读的,因此不同的映像可以共享同一层(如果它们处于公用层)。

传输 Docker 层选项重复使用映像之间的层,并且仅将新层传输到设备。 此选项最适用于共享同一基层的的映像(通常是 OS)或现有映像的更新版本。

此方法的缺点包括:

  • 业务流程协调程序必须维护有关哪些设备上存在哪些层的信息。
  • 基本层更改会导致所有后续层的哈希发生更改。
  • 比较需要一致的层哈希。
  • Docker 保存和 Docker 负载可能存在依赖项。

“修改 Docker 客户端”选项

此选项侧重于修改或包装 Docker 客户端,以便在中断后恢复层下载。 默认情况下,如果 Internet 连接在中断约 30 分钟内恢复,Docker 拉取将恢复下载。 否则,客户端将退出,并且所有下载进度将丢失。

此方法可行,但会带来以下问题:

  • 设备上的所有映像都必须注册到拉取映像的 Docker 守护程序,以最大程度地提高带宽效率。
  • 必须修改开源 Docker 项目以支持此功能,会带来开放源代码维护人员拒绝该建议的风险。
  • 通过 HTTP 而不是客户喜欢的快速文件传输解决方案来传输数据,这需要开发自定义重试逻辑。
  • 当基础映像发生更改时,必须重新传输所有层。

“在边缘设备上生成”选项

此方法将映像生成环境移动到设备。 以下数据将发送到设备:

  • 正在生成的应用程序源代码
  • 代码所依赖的所有 NuGet 包的副本
  • .NET Core 生成环境和运行时的 Docker 基础映像
  • 有关结束映像的元数据

然后,设备上的生成代理会生成映像,然后将其注册到设备 Docker 管理器。

此解决方案被拒绝,因为:

  • 仍然需要一种方法将大型 Docker 映像移动到设备。 用于生成 .NET 应用程序的映像大于应用映像本身。
  • 此方法仅适用于团队具有源代码的应用程序,因此无法使用第三方映像。
  • 该选项需要打包 NuGet 包并跟踪其移动到设备。
  • 如果在设备上生成映像失败,团队必须远程调试生成环境和创建的映像。 远程调试需要大量使用可能受限的 Internet 连接。

“完整映像增量传输”选项

所选方法将 Docker 映像视为单个二进制文件。 Docker save 命令将映像导出为 .tar 文件。 该解决方案导出现有和新的 Docker 映像,并计算应用时将现有映像转换为新映像的二进制增量。

该解决方案跟踪设备上的现有 Docker 映像,并生成二进制增量修补程序,将现有映像转换为新映像。 系统仅跨低带宽 Internet 连接传输增量修补程序。 该解决方案需要一些自定义逻辑来生成二进制修补程序,但它向设备发送的数据量最少。

评估结果

下表显示了如何根据评估标准度量上述每个解决方案。

符合请求 设备逻辑 Azure 逻辑 传输 第一张图像 基于设备 更新应用层 更新基层
传输 Docker 层 中等 FileCatalyst 100% 10.5% 22.4% 100%
修改 Docker 客户端 中等 HTTP 100% 10.5% 22.4% 100%
在边缘设备上生成 中等 FileCatalyst 空值 不可用 不可用 空值
完整映像增量传输 FileCatalyst 100% 3.2% 0.01% 16.1%

注意事项

这些注意事项实施 Azure 架构良好的框架的支柱原则,即一套可用于改进工作负载质量的指导原则。 有关详细信息,请参阅 Microsoft Azure 架构良好的框架

性能效率

此解决方案大大降低了 IoT 设备更新所消耗的带宽。 下表显示了传输效率差异的明细。

图像重建器作为源:

映像名称 映像大小 修补程序大小 数据缩减
数据可视化 228 MB 79.6 MB 65.1%
模拟 WCD 188 MB 1.5 MB 99.2%
代理 258 MB 29.9 MB 88.4%

早期版本作为源:

映像名称 映像大小 修补程序大小 数据缩减
数据可视化 228 MB 0.01 MB 99.9%
模拟 WCD 188 MB 0.5 MB 99.7%
代理 258 MB 0.04 MB 99.9%

卓越运营

以下部分详细介绍了该解决方案。

源代码存储库

开发人员与源代码存储库中的边缘模块源代码进行交互。 存储库由包含每个模块代码的文件夹组成,如下所示:


\- repository root
    - modulea
    - modulea.csproj
    - module.json
    - Program.cs
    - Dockerfile

\- moduleb
    - moduleb.csproj
    - module.json
    - Program.cs
    - Dockerfile

建议的源代码存储库数为:

  • 所有工作流中的所有模块共用一个存储库。
  • 每个工作流都有一个源代码存储库。

容器注册表实例

容器注册表存储每个模块的 Docker 映像。 容器注册表有两种可能的配置:

  • 存储所有映像的单个容器注册表实例。
  • 两个容器注册表实例,一个用于存储开发、测试和调试映像,另一个实例仅包含标记为生产就绪的映像。

清单存储库

清单存储库包含所有工作流的部署清单。 模板位于基于其工作流的文件夹中。 在此示例中,两个工作流是共享基础结构和容器化应用程序。


\- repository root
     - Workstream1
         - deployment.template.json
     - Workstream2
         - deployment.template.json

Docker 映像生成管道

每个模块都有一个 Azure Pipelines 生成管道。 管道使用通用 Docker 生成来创建和注册模块。 管道负责:

  • 源代码的安全扫描。
  • 对用于生成 Docker 映像的基础映像进行安全扫描。
  • 为模块运行单元测试。
  • 将源生成到 Docker 映像中。 映像标记包含 BUILD_BUILDID,以便始终可以将映像链接回生成它的源代码。
  • 将映像推送到容器注册表实例。
  • 创建增量文件。
  • 创建映像的签名文件,并将该文件保存至 Azure 存储帐户。

所有管道实例都基于单个 YAML 管道定义。 管道可以使用环境变量对模块执行操作。 筛选器仅在特定文件夹中提交更改时触发每个管道。 该筛选器可以避免在仅更新一个模块时生成所有模块。

映像到设备管道

映像到设备管道将 Docker 映像部署到目标设备,如清单文件定义。 触发管道手动启动部署。

管道定义指定在容器中运行这些部署。 管道支持映像基于容器的变量输入。 单个变量可以控制所有管道的部署。

此映像包含确定要生成的修补程序、生成这些修补程序并将其分发到文件传输工具的 Azure 端所需的代码。

映像分发工具需要以下信息:

  • 要部署的映像(由存储库清单提供)。
  • 要部署到的设备(由触发管道的用户提供)。
  • 目标设备上已有的映像(由 Azure SQL 数据库提供)

管道输出为:

  • 发送到文件传输工具的 Azure 端的修补程序捆绑将分发到设备。
  • SQL 数据库条目,用于标记哪些映像已开始传输到每个设备。
  • SQL 新部署集的数据库条目。 这些条目包括订购部署的用户的姓名和电子邮件地址。

此管道执行以下步骤:

  1. 根据部署清单确定所需的映像。
  2. 查询 SQL 以查看设备上已有哪些映像。 如果所有映像都已存在,管道将成功终止。
  3. 确定要创建的修补程序捆绑。 算法将确定生成最小修补程序捆绑的起始映像。
    • 输入:.tar 文件,其中包含要部署的新映像和设备上现有映像的签名文件。
    • 输出:现有映像的排名,以确定要创建的最小修补程序。
  4. 为每个设备创建所需的修补程序捆绑包。 一次生成类似的修补程序,并将其复制到所需的所有设备。
  5. 将修补程序分发到文件传输工具存储帐户以进行部署。
  6. 更新 SQL,以将新映像标记为 in transit 到每个目标设备。
  7. 将部署集信息与部署映像的人员的姓名和联系电子邮件一起添加到 SQL。

显示从原始文件到已更改的文件再到生成的数据的工作流示意图。

清单到设备管道

清单到设备管道将部署清单推送到待更新设备的正确 IoT 中心连接。 用户手动触发管道,并为 IoT 中心实例指定目标环境变量。

管道:

  • 确定部署所需的映像。
  • 查询 SQL 以确保所需映像全部位于目标设备上。 如果不是,则管道以 failed 状态终止。
  • 将新的部署清单推送到正确的 IoT 中心。

快速文件传输解决方案

客户希望继续使用其第三方快速文件传输解决方案(称为 FileCatalyst)来提供 Azure 与其 IoT 设备之间的连接。 此解决方案是最终一致的文件传输工具,这意味着传输可能需要很长时间,但最终将完成且不会丢失任何文件信息。

该解决方案在连接的 Azure 端使用了 Azure 存储帐户,并为每个接收映像的设备使用了客户的现有文件传输主机 VM。 修补程序捆绑包传输到运行 IoT 中心的 Linux VM。

映像重建模块

映像重建 IoT Edge 模块在设备上应用收到的修补程序。 每个设备都使用 Docker 开源注册表托管自己的本地容器注册表。 映像重建过程在主机 VM 上运行,与文件传输 VM 相同。

该模块:

  1. 在装载到容器的文件夹中接收修补程序捆绑包。
  2. 解压缩修补程序内容以读取配置文件。
  3. 按哈希值从本地容器注册表中提取基础映像。
  4. 将基础映像保存为 .tar 文件。
  5. 将修补程序应用于基础映像。
  6. 将包含新映像的 .tar 文件加载到 Docker。
  7. 将新映像推送到本地容器注册表,配置文件包含友好名称和标记。
  8. 向 IoT 中心发送成功消息。

如果该过程在任何时候失败,此模块会向 IoT 中心发送失败消息,以便可以通知触发部署的用户。

IoT 中心

多个部署过程使用 IoT 中心。 IoT 中心除了从映像重建模块接收状态消息以外,还设置设备的部署清单。 管道流的其余部分使用此清单。

显示操作中心和 IoT 设备修补到映像重建器的工作流示意图。

Azure Functions

Azure Functions 监视来自 IoT 中心的消息流,并在云中采取措施。

对于成功消息:

  • 函数将设备上映像 SQL 输入的状态从 in transit 更新为 succeeded
  • 如果这是到达部署集的最后一个映像:
    • 该函数通知用户部署成功。
    • 函数还会更新清单到设备管道,以开始使用新映像。

对于失败消息:

  • 函数将设备上映像 SQL 输入的状态从 in transit 更新为 failed
  • 该函数通知用户映像传输失败。

操作中心和 IoT 设备映像重建器消息工作流

SQL 数据库

SQL 数据库跟踪目标设备和基于 Azure 的部署服务在部署期间和之后发生的事件。 Azure Functions 和 Azure Pipelines 都使用为与数据库交互而创建的专用 NuGet 包。

SQL 数据库存储以下数据:

  • 每个设备上有哪些映像。
  • 每个设备上有哪些正在前往的映像。
  • 哪些部署的映像属于一个集。
  • 订购部署的用户。

此示例的目标是确保系统为将来的数据仪表板生成了所需的数据。 查询 IoT 中心可以提供以下有关清单到设备管道的数据:

  • 部署的状态。
  • 给定设备上的映像。
  • 具有映像的设备。
  • 有关成功和失败传输的时序数据。
  • 基于用户的部署查询。

作者

本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。

首席作者:

后续步骤