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

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

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

在本教程中,你将了解:

  • 将身份验证凭据另存为存储库机密。
  • 创建工作流来预配 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 - 创建工作流

A 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 参数,为工作流命名。

    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 参数添加到工作流文件。

    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 教程”,这是我们在工作流文件中定义的名称,然后选择“运行工作流”下拉框。

    Screenshot of the action tab where you can select a workflow and run it.

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

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

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

  6. 当所有作业都成功完成后,你应该在每个作业旁边看到绿色复选标记。

    Screenshot of a successfully completed workflow.

清理资源

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

使用 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 实例。