使用 Visual Studio Code 调试 Azure IoT Edge 模块

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

本文介绍如何使用 Visual Studio Code 来调试以多种语言编写的 IoT Edge 模块。 在开发计算机上,可以使用 Visual Studio Code 在本地或远程模块容器中附加和调试模块。

本文包含适用于两种 IoT Edge 开发工具的步骤。

  • Azure IoT Edge Dev Tool 命令行工具 (CLI)。 此工具是开发的首选工具。
  • 适用于 Visual Studio Code 的 Azure IoT Edge 工具扩展。 该扩展处于维护模式

使用本文开头的工具选择器按钮选择工具版本。

Visual Studio Code 支持使用以下编程语言编写 IoT Edge 模块:

  • C# 和 C# Azure Functions
  • C
  • Python
  • Node.js
  • Java

Azure IoT Edge 支持以下设备体系结构:

  • AMD64
  • ARM32v7
  • ARM64

有关支持的操作系统、语言和体系结构的详细信息,请参阅语言和体系结构支持

使用 Visual Studio Code IoT Edge 扩展时,还可以在 IoT Edge 模拟器中启动和调试模块代码。

还可以使用 Windows 开发计算机并使用 IoT Edge for Linux on Windows (EFLOW) 在 Linux 容器中调试模块。 有关使用 EFLOW 开发模块的详细信息,请参阅教程:使用 IoT Edge for Linux on Windows 通过 Linux 容器开发 IoT Edge 模块

如果你不熟悉 Visual Studio Code 的调试功能,请参阅 Visual Studio Code 调试

先决条件

可以使用运行 Windows、macOS 或 Linux 的计算机或虚拟机作为开发计算机。 在 Windows 计算机上,可以开发 Windows 或 Linux 模块。 若要开发 Linux 模块,请使用符合 Docker Desktop 要求的 Windows 计算机。

若要安装所需的开发和调试工具,请完成使用 Visual Studio Code 开发 Azure IoT Edge 模块教程。

安装 Visual Studio Code

添加以下扩展:

若要在设备上调试模块,需要:

  • 具有至少一个 IoT Edge 设备的有效 IoT 中心。
  • 物理 IoT Edge 设备或虚拟设备。 若要在 Azure 中创建虚拟设备,请按照适用于 Linux 的快速入门中的步骤操作。
  • 一个自定义 IoT Edge 模块。 若要创建自定义模块,请按照使用 Visual Studio Code 开发 Azure IoT Edge 模块教程中的步骤操作。

使用 IoT Edge 模拟器在没有容器的情况下进行调试

IoT Edge 模拟器是在开发计算机上运行的工具,用于模拟单个 IoT Edge 设备的行为。 你可以使用 IoT Edge 模拟器来开发和测试 IoT Edge 模块,而无需物理设备或完整的 IoT Edge 设备运行时。

以下调试步骤假设你已创建自定义模块。 如果未创建自定义模块,请按照使用 Visual Studio Code 开发 Azure IoT Edge 模块教程中的步骤操作。

使用 C 或 Python 时,无法在没有容器的情况下调试模块。

使用 IoT Edge 模拟器在附加模式下进行调试

C 或 Python 不支持在附加模式下进行调试。

使用 IoT Edge 运行时调试模块

每个模块文件夹中都有多个适用于不同容器类型的 Docker 文件。 使用以扩展名“.debug”结尾的任何文件来生成用于测试的模块 。

使用此方法调试模块时,模块在 IoT Edge 运行时之上运行。 IoT Edge 设备和 Visual Studio Code 可位于同一台计算机上;更常见的情况是,Visual Studio Code 位于开发计算机上,IoT Edge 运行时和模块在另一台物理计算机上运行。 若要在 Visual Studio Code 中进行调试,必须:

  • 设置 IoT Edge 设备,使用 .debug Dockerfile 生成 IoT Edge 模块,然后将其部署到 IoT Edge 设备。
  • 更新 launch.json,使 Visual Studio Code 能够附加到远程计算机上的容器中的进程。 可以在工作区中的 .vscode 文件夹内找到此文件。每当添加用于支持调试的新模块时,此文件都会更新。
  • 使用远程 SSH 调试附加到远程计算机上的容器。

生成模块并将其部署到 IoT Edge 设备

在 Visual Studio Code 中,打开 deployment.debug.template.json 部署清单文件。 部署清单描述要在目标 IoT Edge 设备上配置的模块。 在部署之前,需要使用正确的 createOptions 值更新 Azure 容器注册表凭据和模块映像。 若要了解 createOption 值的详细信息,请参阅如何配置 IoT Edge 模块的容器创建选项

  1. 如果使用 Azure 容器注册表来存储模块映像,请将凭据添加到 deployment.debug.template.json 中的 edgeAgent>settings>registryCredentials 部分。 将这两个位置的 myacr 替换为你自己的注册表名称,并提供密码和登录服务器地址。 例如:

    "modulesContent": {
    "$edgeAgent": {
      "properties.desired": {
        "schemaVersion": "1.1",
        "runtime": {
          "type": "docker",
          "settings": {
            "minDockerVersion": "v1.25",
            "loggingOptions": "",
            "registryCredentials": {
              "myacr": {
                "username": "myacr",
                "password": "<your_azure_container_registry_password>",
                "address": "myacr.azurecr.cn"
              }
            }
          }
        },
    ...
    
  2. 将以下字符串化内容添加到列出的每个系统(edgeHub 和 edgeAgent)和自定义模块(例如 filtermodule)的 createOptions 值或替换此值。 请根据需要更改这些值。

    "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    

    例如,filtermodule 配置应类似于:

    "filtermodule": {
    "version": "1.0",
    "type": "docker",
    "status": "running",
    "restartPolicy": "always",
    "settings": {
        "image": "myacr.azurecr.cn/filtermodule:0.0.1-amd64",
        "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
    }
    
  1. 在 Visual Studio Code 命令面板中,运行“Azure IoT Edge: Build and Push IoT Edge solution”命令。
  2. 选择解决方案的 deployment.debug.template.json 文件。
  3. 在 Visual Studio Code 资源管理器视图的“Azure IoT 中心”>“设备”部分,右键单击 IoT Edge 设备名称进行部署,然后选择“为单个设备创建部署”。

    提示

    若要确认已选择的设备为 IoT Edge 设备,请选择它以展开模块列表并验证是否存在“$ edgeHub”和“$ edgeAgent” 。 每个 IoT Edge 设备都包含这两个模块。

  4. 导航到解决方案的“config”文件夹,选择 deployment.debug.amd64.json 文件,然后选择“选择 Edge 部署清单” 。

可以通过在终端中运行 docker ps 命令从设备或虚拟机检查容器状态。 运行该命令后,应会看到你的容器已列出。 如果 Visual Studio Code 和 IoT Edge 运行时在同一台计算机上运行,则还可以在 Visual Studio Code Docker 视图中检查状态。

重要

如果对映像使用专用注册表(如 Azure 容器注册表),可能需要完成身份验证才能推送映像。 使用 docker login <Azure Container Registry login server>az acr login --name <Azure Container Registry name> 进行身份验证。

登录 Docker

向 Docker 提供容器注册表凭据,以便它可以推送要存储在注册表中的容器映像。

  1. 使用创建注册表后保存的 Azure 容器注册表凭据登录到 Docker。

    docker login -u <Azure Container Registry username> -p <Azure Container Registry password> <Azure Container Registry login server>
    

    可能会收到一条安全警告,推荐使用 --password-stdin。 虽然它是为生产方案推荐的最佳做法,但它超出了本教程的范畴。 有关详细信息,请参阅 docker login 参考。

  2. 登录到 Azure 容器注册表。 可能需要安装 Azure CLI 才能使用 az 命令。 此命令要求提供在“设置”>“访问密钥”中的容器注册表中的用户名和密码。

    az acr login -n <Azure Container Registry name>
    

提示

如果你在学习本教程过程中的任何时候退出登录,请重复 Docker 和 Azure 容器注册表登录步骤以继续。

生成模块 Docker 映像

使用模块的 Dockerfile 生成模块 Docker 映像。

docker build --rm -f "<DockerFilePath>" -t <ImageNameAndTag> "<ContextPath>" 

例如,若要为本地注册表或 Azure 容器注册表生成映像,请使用以下命令:

# Build the image for the local registry

docker build --rm -f "./modules/filtermodule/Dockerfile.amd64.debug" -t localhost:5000/filtermodule:0.0.1-amd64 "./modules/filtermodule"

# Or build the image for an Azure Container Registry

docker build --rm -f "./modules/filtermodule/Dockerfile.amd64.debug" -t myacr.azurecr.cn/filtermodule:0.0.1-amd64 "./modules/filtermodule"

推送模块 Docker 映像

将模块映像推送到本地注册表或容器注册表。

docker push <ImageName>

例如:

# Push the Docker image to the local registry

docker push localhost:5000/filtermodule:0.0.1-amd64

# Or push the Docker image to an Azure Container Registry
az acr login --name myacr
docker push myacr.azurecr.cn/filtermodule:0.0.1-amd64

将模块部署到 IoT Edge 设备

使用 IoT Edge Azure CLI set-modules 命令将模块部署到 Azure IoT 中心。 例如,若要将 deployment.debug.template.json 文件中定义的模块部署到 IoT Edge 设备 my-device 的 IoT 中心 my-iot-hub,请使用以下命令:

az iot edge set-modules --hub-name my-iot-hub --device-id my-device --content ./deployment.debug.template.json --login "HostName=my-iot-hub.azure-devices.cn;SharedAccessKeyName=iothubowner;SharedAccessKey=<SharedAccessKey>"

提示

可以在 Azure 门户中的 IoT 中心>“安全设置”>“共享访问策略”>“iothubowner”下找到你的 IoT 中心连接字符串。

调试模块

若要调试远程设备上的模块,可以在 Visual Studio Code 中使用远程 SSH 调试。

若要启用 Visual Studio Code 远程调试,请安装远程开发扩展。 有关 Visual Studio Code 远程调试的详细信息,请参阅 Visual Studio Code 远程开发

有关如何在 Visual Studio Code 中使用远程 SSH 调试的详细信息,请参阅使用 SSH 进行远程开发

在 Visual Studio Code 调试视图中,选择模块的调试配置文件。 默认情况下,.debug Dockerfile、模块的容器 createOptions 设置和 launch.json 文件使用 localhost。

选择“开始调试”或选择 F5 。 选择要附加到的进程。 在 Visual Studio Code 调试视图中,可以在左侧面板中看到变量。

使用 Docker 远程 SSH 进行调试

Docker 和 Moby 引擎支持与容器的 SSH 连接,允许在连接到远程设备的 Visual Studio Code 中进行调试。 需要满足以下先决条件才能使用此功能。

远程 SSH 调试先决条件可能有所不同,具体取决于所使用的语言。 以下部分介绍了 .NET 的设置。 有关其他语言的信息,请参阅使用 SSH 进行远程开发以了解概述。 有关如何配置远程调试的详细信息包含在 Visual Studio Code 文档每种语言的调试部分中。

配置 Docker SSH 隧道

  1. 按照 Docker SSH 隧道中的步骤在开发计算机上配置 SSH 隧道。 SSH 隧道需要公钥/私钥对身份验证和定义远程设备终结点的 Docker 上下文。

  2. 连接到 Docker 需要根级别权限。 按照以非根用户身份管理 docker 中的步骤操作,以允许连接到远程设备上的 Docker 守护程序。 完成调试后,可能需要从 Docker 组中删除用户。

  3. 在 Visual Studio Code 中,使用命令面板 (Ctrl+Shift+P) 发出 Docker Context: Use 命令,以激活指向远程计算机的 Docker 上下文。 此命令使 Visual Studio Code 和 Docker CLI 都使用远程计算机上下文。

    提示

    所有 Docker 命令都使用当前上下文。 请记住在完成调试后将上下文更改回默认值。

  4. 若要验证远程 Docker 上下文是否处于活动状态,请列出远程设备上正在运行的容器:

    docker ps
    

    输出应列出远程设备上运行的容器,如下所示:

    PS C:\> docker ps        
    CONTAINER ID   IMAGE                                                             COMMAND                   CREATED        STATUS         PORTS                                                                                                                                   NAMES
    a317b8058786   myacr.azurecr.cn/filtermodule:0.0.1-amd64                         "dotnet filtermodule…"    24 hours ago   Up 6 minutes                                                                                                                                           filtermodule
    d4d949f8dfb9   mcr.microsoft.com/azureiotedge-hub:1.4                            "/bin/sh -c 'echo \"$…"   24 hours ago   Up 6 minutes   0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:5671->5671/tcp, :::5671->5671/tcp, 0.0.0.0:8883->8883/tcp, :::8883->8883/tcp, 1883/tcp   edgeHub
    1f0da9cfe8e8   mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0   "/bin/sh -c 'echo \"$…"   24 hours ago   Up 6 minutes                                                                                                    
                                           tempSensor
    66078969d843   mcr.microsoft.com/azureiotedge-agent:1.4                          "/bin/sh -c 'exec /a…"    24 hours ago   Up 6 minutes                                                                                                    
                                           edgeAgent
    
  5. 在 .vscode 目录中,通过在 Visual Studio Code 中打开文件,将新配置添加到 launch.json。 选择“添加配置”,然后选择模块的匹配远程附加模板。 例如,以下配置适用于 .NET Core。 将 PipeArgs 中 -H 参数的值更改为设备 DNS 名称或 IP 地址。

    "configurations": [
    {
      "name": "Remote Debug IoT Edge Module (.NET Core)",
      "type": "coreclr",
      "request": "attach",
      "processId": "${command:pickRemoteProcess}",
      "pipeTransport": {
        "pipeProgram": "docker",
        "pipeArgs": [
          "-H",
          "ssh://user@my-device-vm.chinaeast.cloudapp.chinacloudapi.cn:22",
          "exec",
          "-i",
          "filtermodule",
          "sh",
          "-c"
        ],
        "debuggerPath": "~/vsdbg/vsdbg",
        "pipeCwd": "${workspaceFolder}",
        "quoteArgs": true
      },
      "sourceFileMap": {
        "/app": "${workspaceFolder}/modules/filtermodule"
      },
      "justMyCode": true
    },
    

远程调试模块

  1. 在 Visual Studio Code 调试视图中,选择调试配置“远程调试 IoT Edge 模块(.NET Core)”。

  2. 选择“开始调试”或选择 F5 。 选择要附加到的进程。

  3. 在 Visual Studio Code 调试视图中,可以在左侧面板中看到变量。

  4. 在 Visual Studio Code 中设置自定义模块中的断点。

  5. 命中断点时,可以检查变量、逐步执行代码以及调试模块。

    在远程设备上附加到 Docker 容器的 Visual Studio Code(在断点处暂停)的屏幕截图。

注意

上面的示例展示了如何调试远程容器上的 IoT Edge 模块。 该示例添加远程 Docker 上下文,并更改远程设备上的 Docker 特权。 完成模块调试后,将 Docker 上下文设置为默认,并从用户帐户中删除权限。

有关使用 Raspberry Pi 设备的示例,请参阅此 IoT 开发人员博客文章

后续步骤

生成模块后,了解如何从 Visual Studio Code 部署 Azure IoT Edge 模块

若要开发用于 IoT Edge 设备的模块,请参阅了解并使用 Azure IoT 中心 SDK