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

教程:使用 GitHub Actions 自动执行 Azure 设备预配服务

使用 GitHub Actions 等自动化工具管理 IoT 设备生命周期。 本教程演示了使用 Azure 设备预配服务(DPS)将设备连接到 IoT 中心的 GitHub Actions 工作流。

本教程中,您将学习如何:

  • 将身份验证凭据保存为存储库机密。
  • 创建用于预配 IoT 中心和设备预配服务资源的工作流。
  • 运行工作流并监视连接到 IoT 中心的模拟设备。

先决条件

  • Azure 订阅服务

    如果没有 Azure 订阅,请在开始之前创建一个免费帐户

  • Azure CLI (命令行界面)

  • 一个 GitHub 帐户,其中包含你拥有的存储库或拥有管理员访问权限的存储库。 有关详细信息,请参阅 GitHub 入门

1 - 创建存储库机密

在下一部分中定义的工作流需要访问 Azure 订阅来创建和管理资源。 你不想将该信息放在可以发现它的未受保护的文件中,因此我们将使用存储库机密来存储此信息,但仍可在工作流中将其作为环境变量进行访问。 有关详细信息,请参阅 加密机密

只有存储库所有者和管理员可以管理存储库机密。

创建服务主体

我们不会提供个人访问凭据,而是创建服务主体,然后将这些凭据添加为存储库机密。 使用 Azure CLI 创建新的服务主体。 有关详细信息,请参阅创建 Azure 服务主体

  1. 使用 az ad sp create-for-rbac 命令创建具有特定资源组 参与者 访问权限的服务主体。 请将 <SUBSCRIPTION_ID><RESOURCE_GROUP_NAME> 替换为自己的信息。

    此命令需要订阅中“所有者”或“用户访问管理员”角色。

    az ad sp create-for-rbac --name github-actions-sp --role contributor --scopes /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP_NAME>
    
  2. 从服务主体创建命令的输出中复制以下项,以在下一部分中使用:

    • clientId
    • 客户端密钥 clientSecret。 这是服务主体生成的密码,你将无法再次访问。
    • tenantId
  3. 使用 az role assignment create 命令向服务主体分配另外两个访问角色: 设备预配服务数据参与者IoT 中心数据参与者。 将 <SP_CLIENT_ID> 替换为从上一命令的输出中复制的 clientId 值。

    az role assignment create --assignee "<SP_CLIENT_ID>" --role "Device Provisioning Service Data Contributor" --resource-group "<RESOURCE_GROUP_NAME>"
    
    az role assignment create --assignee "<SP_CLIENT_ID>" --role "IoT Hub Data Contributor" --resource-group "<RESOURCE_GROUP_NAME>"
    

将服务主体凭据另存为机密

  1. 在 GitHub.com 上,导航到存储库的设置

  2. 从导航菜单中选择 “秘密”,然后选择“ 操作”。

  3. 选择“新建存储库机密”。

  4. 为服务主密钥 ID 创建机密。

    • 名称APP_ID
    • 机密:粘贴你从服务主体创建命令的输出中复制的clientId
  5. 选择 “添加机密”,然后选择“ 新建存储库机密 ”以添加第二个机密。

  6. 为服务主体密码创建一个机密。

    • 名称SECRET
    • 密钥:将从服务主体创建命令输出中复制的 clientSecret 粘贴到。
  7. 选择 “添加机密”,然后选择“ 新建存储库机密 ”以添加最终机密。

  8. 为 Azure 租户创建机密。

    • 名称TENANT
    • 机密:粘贴您从创建服务主体命令的输出中复制的 tenantId
  9. 选择“添加机密”。

2 - 创建工作流

GitHub Actions 工作流 定义在 事件触发后将运行的任务。 工作流包含一个或多个作业,这些 作业 可以并行运行或按顺序运行。 有关详细信息,请参阅 了解 GitHub Actions

在本教程中,我们将创建一个工作流,其中包含以下每个任务的作业:

  • 预配 IoT 中心实例和 DPS 实例。
  • 将 IoT 中心和 DPS 实例相互链接。
  • 在 DPS 实例上创建单个注册,并通过 DPS 注册使用对称密钥身份验证将设备注册到 IoT 中心。
  • 模拟设备五分钟并监视 IoT 中心事件。

工作流是位于 .github/workflows/ 存储库目录中的 YAML 文件。

  1. 在 GitHub 存储库中,导航到 “操作” 选项卡。

  2. “作 ”窗格中,选择“ 新建工作流”。

  3. “选择工作流”页上,可以选择要使用的预生成模板。 我们将为本教程创建自己的工作流,因此请 自行选择“设置工作流”。

  4. GitHub 会为你创建新的工作流文件。 请注意,它位于 .github/workflows/ 目录中。 为新文件指定有意义的名称,例如 dps-tutorial.yml

  5. 添加 名称 参数以为工作流指定名称。

    name: DPS Tutorial
    
  6. 添加 on.workflow_dispatch 参数。 该 on 参数定义工作流何时运行。 该 workflow_dispatch 参数指示我们要手动触发工作流。 使用此参数,我们可以定义 inputs 将在每次运行时传递到工作流,但我们不会对本教程使用这些参数。

    on: workflow_dispatch
    
  7. 定义在工作流中创建的资源的 环境变量 。 这些变量将可用于工作流中的所有作业。 还可以为单个作业或作业中的单个步骤定义环境变量。

    将占位符中的值替换为您自己的值。 请确保指定服务主体有权访问的同一资源组。

    env:
      HUB_NAME: <Globally unique IoT hub name>
      DPS_NAME: <Desired Device Provisioning Service name>
      DEVICE_NAME: <Desired device name>
      RESOURCE_GROUP: <Solution resource group where resources will be created>
    
  8. 为在上一部分创建的机密定义环境变量。

      SP_USER: ${{ secrets.APP_ID }}
      SP_SECRET: ${{ secrets.SECRET }}
      SP_TENANT: ${{ secrets.TENANT }}
    
  9. 作业 参数添加到工作流文件。

    jobs:
    
  10. 定义工作流的第一个作业,并命名为 provision 作业。 此作业配置 IoT 中心和 DPS 实例:

      provision:
        runs-on: ubuntu-latest
        steps:
          - name: Provision Infra
            run: |
              az --version
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az iot hub create -n "$HUB_NAME" -g "$RESOURCE_GROUP"
              az iot dps create -n "$DPS_NAME" -g "$RESOURCE_GROUP"
    

    有关此作业中运行的命令的详细信息,请参阅:

  11. 定义一个作业以配置 (configure) DPS 和 IoT 中心实例。 请注意,此作业使用 needs 参数,这意味着在列出的作业成功完成自己的运行之前,configure 作业不会运行。

      configure:
        runs-on: ubuntu-latest
        needs: provision
        steps:
          - name: Configure Infra
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az iot dps linked-hub create --dps-name "$DPS_NAME" --hub-name "$HUB_NAME"   
    

    有关此作业中运行的命令的详细信息,请参阅:

  12. 定义一个名为register的作业,该作业将创建一个单独的注册,然后使用该注册将设备注册到 IoT 中心。

      register:
        runs-on: ubuntu-latest
        needs: configure
        steps:
          - name: Create enrollment
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot dps enrollment create -n "$DPS_NAME" --eid "$DEVICE_NAME" --attestation-type symmetrickey --auth-type login
          - name: Register device
            run: |
              az iot device registration create -n "$DPS_NAME" --rid "$DEVICE_NAME" --auth-type login   
    

    注释

    此作业及其他作业使用某些命令中的参数 --auth-type login 来指示该操作应使用当前 Microsoft Entra 会话中的服务主体。 替代 --auth-type key 方法不需要服务主体配置,但安全性较低。

    有关此作业中运行的命令的详细信息,请参阅:

  13. 定义一个作业,以模拟 (simulate) 连接到 IoT 中心并发送示例遥测数据消息的 IoT 设备的作业。

      simulate:
        runs-on: ubuntu-latest
        needs: register
        steps:
          - name: Simulate device
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot device simulate -n "$HUB_NAME" -d "$DEVICE_NAME"
    

    有关此作业中运行的命令的详细信息,请参阅:

  14. 定义一个作业来监视 (monitor) IoT 中心终结点的事件,并监视来自模拟设备的消息。 请注意,模拟监视作业都在其参数中定义needs作业。 此配置意味着 注册 作业成功完成后,这两个作业将并行运行。

      monitor:
        runs-on: ubuntu-latest
        needs: register
        steps:
          - name: Monitor d2c telemetry
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot hub monitor-events -n "$HUB_NAME" -y   
    

    有关此作业中运行的命令的详细信息,请参阅:

  15. 完整的工作流文件应如以下示例所示,信息将替换环境变量中的占位符值:

    name: DPS Tutorial
    
    on: workflow_dispatch
    
    env:
      HUB_NAME: <Globally unique IoT hub name>
      DPS_NAME: <Desired Device Provisioning Service name>
      DEVICE_NAME: <Desired device name>
      RESOURCE_GROUP: <Solution resource group where resources will be created>
      SP_USER: ${{ secrets.APP_ID }}
      SP_SECRET: ${{ secrets.SECRET }}
      SP_TENANT: ${{ secrets.TENANT }}
    
    jobs:
      provision:
        runs-on: ubuntu-latest
        steps:
          - name: Provision Infra
            run: |
              az --version
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az iot hub create -n "$HUB_NAME" -g "$RESOURCE_GROUP"
              az iot dps create -n "$DPS_NAME" -g "$RESOURCE_GROUP"
      configure:
        runs-on: ubuntu-latest
        needs: provision
        steps:
          - name: Configure Infra
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az iot dps linked-hub create --dps-name "$DPS_NAME" --hub-name "$HUB_NAME"
      register:
        runs-on: ubuntu-latest
        needs: configure
        steps:
          - name: Create enrollment
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot dps enrollment create -n "$DPS_NAME" --eid "$DEVICE_NAME" --attestation-type symmetrickey --auth-type login
          - name: Register device
            run: |
              az iot device registration create -n "$DPS_NAME" --rid "$DEVICE_NAME" --auth-type login
      simulate:
        runs-on: ubuntu-latest
        needs: register
        steps:
          - name: Simulate device
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot device simulate -n "$HUB_NAME" -d "$DEVICE_NAME"
      monitor:
        runs-on: ubuntu-latest
        needs: register
        steps:
          - name: Monitor d2c telemetry
            run: |
              az login --service-principal -u "$SP_USER" -p "$SP_SECRET" --tenant "$SP_TENANT"
              az extension add --name azure-iot
              az iot hub monitor-events -n "$HUB_NAME" -y
    
  16. 保存、提交此新文件并将其推送到 GitHub 存储库。

3 - 运行工作流

  1. 导航到 GitHub 存储库的「操作」选项卡。

  2. “作 ”窗格中,选择 DPS 教程,这是我们在工作流文件中定义的名称,然后选择“ 运行工作流 ”下拉列表框。

    动作选项卡的屏幕截图,可在其中选择工作流并运行它。

  3. 如果在除 main 以外的分支中创建工作流,则更改分支,然后选择“ 运行工作流”。

  4. 此时将显示新的工作流运行。 选择名称以查看运行的详细信息。

  5. 在工作流摘要中,可以监视每个作业的开始和完成情况。 选择任何作业名称以查看其详细信息。 模拟设备作业运行 5 分钟,并将遥测数据发送到 IoT 中心。 在此期间,选择 模拟 作业来监视从设备发送的消息,以及 监视 作业以监视 IoT 中心接收的消息。

  6. 所有作业成功完成后,您应该会看到每个作业旁边有绿色对勾。

    成功完成的工作流的屏幕截图。

清理资源

如果不打算继续使用本教程中创建的这些资源,请按照以下步骤将其删除。

使用 Azure CLI:

  1. 列出资源组中的资源。

    az resource list --resource-group <RESOURCE_GROUP_NAME>
    
  2. 若要删除单个资源,请使用资源 ID。

    az resource delete --resource-group <RESOURCE_GROUP_NAME> --ids <RESOURCE_ID>
    
  3. 如果要删除整个资源组及其中的所有资源,请运行以下命令:

    az group delete --resource-group <RESOURCE_GROUP_NAME>
    

使用 Azure 门户:

  1. Azure 门户中,导航到在其中创建新资源的资源组。
  2. 可以删除整个资源组,也可以选择要删除的单个资源,然后选择“ 删除”。

后续步骤

了解如何使用其他自动化工具预配 DPS 实例。