在 Visual Studio 中远程调试 Linux 上的 Python 代码

本文介绍如何配置 Visual Studio 安装以支持在远程 Linux 计算机上调试 Python 代码。 本演练基于 Visual Studio 2019 版本 16.6。

Visual Studio 可在 Windows 计算机上以本地和远程方式来启动和调试 Python 应用程序。 Visual Studio 还支持使用 debugpy 库在除 CPython 之外的其他操作系统、设备或 Python 实现中进行远程调试。

Visual Studio 2019 16.4 及更低版本使用 ptvsd 库。 在 Visual Studio 2019 16.5 及更高版本中,debugpy 库将取代 ptvsd。 使用 debugpy 时,正被调试的 Python 代码会托管 Visual Studio 可附加到的调试服务器。 此托管要求对代码进行少量修改才能导入和启用此服务器。 此外,可能还需调整远程计算机上的网络或防火墙配置,从而允许 TCP 连接。

先决条件

  • 安装了 Python 工作负载支持的 Visual Studio。 有关详细信息,请参阅在 Visual Studio 中安装 Python 支持

  • 在操作系统(如 Mac OSX 或 Linux)上运行 Python 的远程计算机。

  • 远程计算机的防火墙上已打开的 5678 端口(入站),它是用于远程调试的默认端口。

设置 Linux 计算机

可轻松在 Azure 中创建 Linux 虚拟机,并使用 Windows 远程桌面来访问该虚拟机。 适用于虚拟机的 Ubuntu 十分方便,因为默认会安装 Python。 如有其他配置,则请参阅安装 Python 解释器以了解其他 Python 下载位置。

配置防火墙

必须在远程计算机的防火墙上打开入站端口 5678,从而支持远程调试。

有关如何为 Azure 虚拟机创建防火墙规则的详细信息,请参阅以下文章:

准备调试脚本

按照以下步骤准备在 Linux 上用于调试 Python 代码的脚本。

  1. 在远程计算机上,使用以下代码创建名为 guessing-game.py Python 文件:

    import random
    
    guesses_made = 0
    name = input('Hello! What is your name?\n')
    number = random.randint(1, 20)
    print('Well, {0}, I am thinking of a number between 1 and 20.'.format(name))
    
    while guesses_made < 6:
        guess = int(input('Take a guess: '))
        guesses_made += 1
        if guess < number:
            print('Your guess is too low.')
        if guess > number:
            print('Your guess is too high.')
        if guess == number:
            break
    if guess == number:
        print('Good job, {0}! You guessed my number in {1} guesses!'.format(name, guesses_made))
    else:
        print('Nope. The number I was thinking of was {0}'.format(number))
    
  2. 使用 pip3 install debugpy 命令将 debugpy 包安装到环境中。

    注意

    最好记录已安装的 debugpy 版本,以备故障排除时所需。 debugpy 列表还会显示可用版本。

  3. 通过在 guessing-game.py 文件顶部(即,在其他代码之前)添加以下代码,从而启用远程调试。 (虽然不是严格要求,但不能调试调用 listen 函数前生成的任何后台线程。)

    import debugpy
    debugpy.listen(('0.0.0.0', 5678))
    
  4. 保存此文件,然后运行程序:

    python3 guessing-game.py
    

    与程序进行交互时,对 listen 函数的调用会在后台运行并等待传入连接。 如果需要,可在调用 listen函数后调用 wait_for_client 函数从而阻止该程序,直到调试器完成附加。

提示

listenwait_for_client 函数外,debugpy 还提供辅助函数 breakpoint。 如果附加了调试器,则此函数将充当编程断点。 如果附加了调试器,则另一函数 is_client_connected1 会返回 True。 调用任何其他 debugpy 函数之前,无需检查此结果。

从 Python 工具远程附加

以下步骤演示如何设置断点,从而停止远程进程。

  1. 在本地计算机上创建远程文件的副本,然后在 Visual Studio 中打开它。 文件位置并不重要,但其名称应与远程计算机上的脚本名称匹配。

  2. (可选)若要在本地计算机上安装适用于 debugpy 的 IntelliSense,请将 debugpy 包安装到 Python 环境中。

  3. 选择调试>附加到进程

  4. 附加到进程对话框中,将连接类型设为 Python 远程(debugpy)

  5. 连接目标字段中,输入命令 tcp://<ip_address>:5678

    • tcp:// 会将连接类型指定为传输控制协议 (TCP)。
    • <ip_address> 为远程计算机的 IP 地址,它可为显式地址或名称,如 myvm.cloudapp.net
    • :5678 为远程调试端口号。
  6. 选择 Enter 以填充此计算机上可用 debugpy 进程的列表:

    Screenshot that shows how to enter the connection target to see a list of available debugpy processes.

    如果在填写此列表后碰巧在远程机器上启动了另一个程序,请选择刷新按钮。

  7. 选择要调试的进程,然后选择附加或双击该进程。

  8. Visual Studio 将切换为调试模式,而脚本则会继续在远程计算机上运行,并提供所有常用调试功能。

    可在 if guess < number: 行上设置断点,然后切换到远程计算机并输入其他猜测。 本地计算机上的 Visual Studio 将在该断点处停止、显示局部变量等:

    Screenshot that shows how Visual Studio pauses debugging when a breakpoint is hit.

  9. 停止调试时,Visual Studio 将从程序分离。 程序会继续在远程计算机上运行。 debugpy 还继续侦听调试程序附加,因此你可以随时重新附加到进程。

排查连接问题

查看以下几点,从而帮助排查连接问题。

  • 请确保已为连接类型选择 Python 远程(debugpy)

  • 确认连接目标中的密钥与远程代码中的密钥完全匹配。

  • 确认连接目标中的 IP 地址与远程计算机中的 IP 地址一致。

  • 验证远程计算机上的远程调试端口是否已打开,以及连接目标是否包含端口后缀,例如 :5678

    若要使用其他端口,请在针对 listen 函数的调用中指定端口号,如 debugpy.listen((host, port)) 中所示。 在此情况下,请务必在防火墙中打开此特定端口。

  • 确认远程计算机上安装的 debugpy 版本(由 pip3 list 命令返回)与 Visual Studio Python 工具 (PTVS) 版本匹配。

    下表列出了有效版本对。 如有必要,请更新远程计算机上的 debugpy 版本。

    Visual Studio Python 工具 debugpy
    2019 16.6 1.0.0b5 1.0.0b5
    2019 16.5 1.0.0b1 1.0.0b1

注意

Visual Studio 2019 版本 16.0-16.4 利用的是 ptvsd,而不是 debugpy。 对于这些版本,本演练中的进程类似,但函数名称不同。 Visual Studio 2019 版本 16.5 使用 debugpy,但函数名称与 ptvsd 中的函数名称相同。 使用 enable_attach,而不是 listen。 使用 wait_for_attach,而不是 wait_for_client。 使用 break_into_debugger,而不是 breakpoint

将 ptvsd 3.x 用于旧版调试

ptvsd 3.x 旧版调试器是 Visual Studio 2017 15.7 及更低版本中的默认调试器。

根据 Visual Studio 配置,可能需使用 ptvsd 3.x 进行远程调试:

  • Visual Studio 2017 15.7 及更低版本(附带 Python 2.6、3.1 到 3.4 或 IronPython)
  • Visual Studio 2019 16.5 及更高版本(附带 Python 2.6、3.1 到 3.4 或 IronPython)
  • 早期 4.x 版本

如果配置实现了旧版场景,Visual Studio 则会显示错误:调试器不支持此 Python 环境

设置远程调试

若要为使用 ptvsd 3.x 进行远程调试进行准备,请完成以下步骤:

  1. 设置密钥,它可用于限制对正在运行的脚本的访问。

    在 ptvsd 3.x 中,enable_attach 函数要求传递一个“密钥”以作为第一个参数。

    • 附加远程调试器时,使用 enable_attach(secret="<secret>") 命令输入此密钥。

    虽然可使用 enable_attach(secret=None) 命令从而允许任何人进行连接,但不建议使用此选项。

  2. 在窗体 tcp://<secret>@<ip_address>:5678 中创建连接目标 URL。

    • tcp:// 会将连接类型指定为 TCP。
    • <secret> 为随 Python 代码中 enable_attach 的函数一起传递的字符串。
    • <ip_address> 为远程计算机的 IP 地址,它可为显式地址或名称,如 myvm.cloudapp.net
    • :5678 为远程调试端口号。

使用 TCPS 协议进行安全连接

默认情况下,与 ptvsd 3.x 远程调试服务器的连接仅由密钥进行保护,且所有数据均会以纯文本形式传递。 为实现更安全的连接,ptvsd 3.x 使用 TCP 协议的安全形式(或 TCPS)来支持 SSL。

使用以下步骤将 ptvsd 3.x 配置为使用 TCPS 协议:

  1. 在远程计算机上,使用 openssl 命令为密钥和自签名证书生成单独的文件:

    openssl req -new -x509 -days 365 -nodes -out cert.cer -keyout cert.key
    
    • openssl 提示符下,为公用名输入用于连接的主机名或 IP 地址。

    有关详细信息,请参阅 Python ssl 模块文档中的自签名证书。 请注意,Python 文档中介绍的命令仅会生成单个组合文件。

  2. 在此代码中,通过将文件名用作值来修改对 enable_attach 函数的调用,从而包含 certfilekeyfile 参数。 这些参数的含义与针对标准 ssl.wrap_socket Python 函数的含义相同。

    ptvsd.enable_attach(secret='my_secret', certfile='cert.cer', keyfile='cert.key')
    

    此外,还可在本地计算机上的代码文件中进行相同更改。 由于此代码实际并未运行,因此并非必须执行该操作。

  3. 在远程计算机上重启 Python 程序,以便其做好调试准备。

  4. 使用 Visual Studio 将证书添加到 Windows 计算机上受信任的根 CA,从而保护此通道:

    1. 将证书文件从远程计算机复制到本地计算机。

    2. 打开控制面板,然后转到 Windows 工具>管理计算机证书

    3. certlm [证书 - 本地计算机] 对话框中,展开受信任的根证书颁发机构节点,右键单击证书,然后选择所有任务>导入

    4. 找到并选择从远程计算机复制的 .cer 文件。

    5. 继续按对话框提示进行操作,从而完成导入流程。

  5. 在 Visual Studio 中重复此附加流程,如前面在 Python 工具中远程附加中所述。

    对于此实例,请将 tcps:// 定义为连接目标(或限定符))的协议。

    Screenshot that shows how to specify TCPS as the remote debugging transport with SSL.

解决连接问题

连接尝试期间,Visual Studio 可能会出现问题。 请查看以下场景,并按需采取相应措施。

  • 通过 SSL 进行连接时,Visual Studio 会警告你注意潜在的证书问题。

    操作:可忽略此消息并继续操作。

    注意

    请记住,虽然此通道仍会进行加密以防窃听,但它可能会受到中间人攻击。

  • Visual Studio 显示远程证书不受信任警告。

    问题:未将证书正确添加到受信任的根 CA。

    操作:重新检查将证书添加到 Windows 计算机上的受信任根 CA 的步骤,然后重试此连接。

    Screenshot of the warning that says the remote SSL certificate isn't trusted.

  • Visual Studio 显示远程证书名称与主机名不匹配警告。

    问题:没有为证书的公用名指定正确的主机名或 IP 地址。

    操作:重新检查使用 TCPS 保护连接中的步骤。 创建证书时,请务必使用正确的公用名,然后重试此连接。

    Screenshot of the warning that says the remote SSL certificate doesn't match the hostname.