在Docker中运行的Python应用程序调试

5
我刚开始尝试理解Docker,并成功运行开发机器。现在,我想在我的Python应用程序(特别是Django)中使用Visual Studio Code中的调试器。
我尝试遵循VS Code的Python扩展的有限文档,其中解释了远程调试的参数。

Dockerfile

FROM python:3.5.2
RUN apt-get update \
--no-install-recommends && rm -rf /var/lib/apt/lists/* \
&& mkdir -p /code \
EXPOSE 8000
WORKDIR /code
COPY requirements.txt /code
RUN /bin/bash --login -c "pip install -r requirements.txt"
ADD . /code
CMD []

docker-compose.yml

version: '2'
services:
    db:
        image: postgres
    web:
        build: .
        volumes:
            - .:/code
        ports:
            - "8000:8000"
        command: bash -c "./wait-for-it.sh db:5432 && python manage.py migrate && python manage.py runserver 0.0.0.0:8000 --noreload"
        depends_on:
            - db

launch.json

{
    "name": "Attach (Remote Debug)",
    "type": "python",
    "request": "attach",
    "localRoot": "${workspaceRoot}",
    "remoteRoot": "/code",
    "port": 8000,
    "secret": "debug_secret",
    "host": "localhost"
}

我还在项目文件中添加了一行ptvsd.enable_attach("debug_secret", address = ('0.0.0.0', 8000))

问题

每当我启动调试器时,什么也不发生,看起来 VS Code 正在等待断点命中。但它从未发生过。

有任何想法吗?

编辑:小更新

我尝试使用不同的调试器端口以及在docker-compose.yml中公开新端口,但都没有成功。看起来附加成功了,因为调试器没有崩溃,但没有触发断点。我真的被卡住了。

解决方案

请参见 theBarkman 的答案。 我要补充说明的是,我无法使用密码来使其工作。我做了以下操作:

manage.py

import ptvsd
ptvsd.enable_attach(secret=None, address=('0.0.0.0', '3000'))

launch.json

{
        "name": "Attach Vagrant",
        "type": "python",
        "request": "attach",
        "localRoot": "${workspaceRoot}",
        "remoteRoot": "/code",
        "port": 3000,
        "secret": "",
        "host":"localhost"
    }
3个回答

4

我在远程调试Docker化的Django项目方面取得了最大成功,方法是将ptvsd代码插入到我的manage.py文件中,并关闭Django的实时代码重新加载。

Django在运行runserver命令时实际上会启动两个服务器(一个用于实现实时代码重新加载,另一个则为应用本身的服务器),这会导致ptvsd不知道该监视哪个服务器。我曾尝试等待附加、使用try/except语句调用enable_attach方法或进入调试器来解决问题,但断点永远不起作用,而且似乎每次只能调试一个文件。

如果在启动服务器时使用Django标志--noreload,你就可以将ptvsd嵌入到manage.py文件中,无需等待或进入调试器,从而获得更加强大和稳定的调试体验。

manage.py:

import ptvsd
ptvsd.enable_attach(secret='mah_secret', address=('0.0.0.0', 3000))

运行服务器:

python manage.py runserver 0.0.0.0:8000 --noreload

希望这有所帮助!

这对我帮助很大!我会将其标记为解决方案,但我应该补充说明,我无法使ptvsd.enable_attach与密钥一起工作。我通过在launch.json中设置secret=None和secret=""来解决了这个问题。 - Mattias
很奇怪,我从来没有遇到过附件中的秘密部分出现问题。不过很高兴你解决了!不用说,一定要确保不会意外地部署没有秘密的版本;) 哈哈 - theBarkman

3

我试图做与你非常相似的事情,并遇到了这个问题/评论:

https://github.com/DonJayamanne/pythonVSCode/issues/252#issuecomment-245566383

在这里描述了使用断点需要使用 ptvsd.break_into_debugger() 函数。

例如:

import ptvsd
ptvsd.enable_attach(secret='my_secret',address = ('0.0.0.0', 3000))
ptvsd.wait_for_attach()
ptvsd.break_into_debugger()

当我在我的Python脚本中添加这个内容后,我的断点开始工作了。希望它有所帮助。


编辑于2017年1月24日

在我的DockerFile中,我安装了ptvsd

FROM kaixhin/theano
RUN pip install ptvsd
WORKDIR /src
EXPOSE 3000
ENTRYPOINT ["python","src/app.py"]
COPY . /src

看起来您正在通过requirements.txt文件安装依赖项,ptvsd是否在其中?


谢谢!我回家后会尝试这个。 - Mattias
1
无法使其工作...也许我做错了什么。你把ptvsd函数调用放在哪个文件中了? - Mattias
@Mattias 我刚刚在我的 DockerFile 中添加了一个引用,你在你的 Docker 容器中安装了 ptvsd 吗? - Colter McQuay
我的意思是,我应该把ptvsd函数调用放在哪里?我需要将其放在每个文件中还是只放在一个文件中?你能否展示一下你使用ptvsd的整个代码?谢谢。 - Mattias
我觉得现在已经有一半的工作完成了...问题现在似乎是调试器在几秒钟后停止了。所以我无法验证调试器是否真正起作用。 - Mattias

0

以下是一些故障排除提示:

1)确保您的调试端口已打开。从您的主机上运行以下命令。

nc -zv test.example.com 30302

2)确保您的 Web 服务器不会自动重新加载您的应用程序。这将中断调试器连接。在启动时在您的代码中放置一个打印或日志语句,以确保您的应用程序没有被加载两次。这适用于在 Flask 上运行的 SocketIO,但 Django 和其他 Web 服务器也有类似的功能。

socketio.run(app, host="0.0.0.0", port=5000, debug=True, use_reloader=False)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接