UPDATE:PyCharm 2017.1 针对这个问题有解决方案,看这个博客条目 http://blog.jetbrains.com/pycharm/2017/03/docker-compose-getting-flask-up-and-running/
这是我解决问题的方法。我的情况是,我被分配对一个 Web 应用程序的特定区域进行干预,该应用程序使用 docker-compose 创建一组四个容器。 Docker-compose 是一种元 docker,可以通过一个命令管理多个 docker 容器。我不想破坏他们现有的设置,因为很多事情都依赖于它。但由于我正在处理其中一张图像中的一个特定部分,因此我决定使用 ssh 扩展其中一个容器,以便可以从 PyCharm 进行调试。此外,我希望应用程序在启动时正常运行,只有强制它退出然后从 PyCharm 连接到它,我才会有一个可调试组件。这是我在 Mac 上所做的,使用 boot2docker(在 VirtualBox 上)正确设置 docker。
首先,我需要扩展目标容器,称为jqworker
。我要使用"supervisior"
承担管理事务的繁重工作。
FROM jqworker
# Get supervisor to control multiple processes, sshd to allow connections.
# And supervisor-stdout allows us to send the output to the main docker output.
RUN apt-get update && apt-get install -y supervisor openssh-server python-pip \
&& pip install supervisor-stdout \
&& mkdir -p /var/run/sshd \
&& mkdir -p /var/log/supervisor \
&& mkdir -p /etc/supervisor/conf.d
COPY ./supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# Fix up SSH, probably should rip this out in real deploy situations.
RUN echo 'root:soup4nuts' | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
# Expose SSH on 22, but this gets mapped to some other address.
EXPOSE 22
# Replace old entrypoint with supervisiord, starts both sshd and worker.py
ENTRYPOINT ["/usr/bin/supervisord"]
Supervisor 允许我通过一个命令运行多个任务,在本例中是原始命令和 SSHD。是的,每个人都说 docker 中的 SSHD 是邪恶的,容器应该这样那样等等,但是编程是为了解决问题,而不是遵守忽略上下文的任意指令。我们需要 SSH 来调试代码,并且不会将其部署到现场,这是我们扩展现有容器而不是将其添加到部署结构中的原因之一。我在本地运行它,以便可以在上下文中调试代码。
这里是supervisord.conf
文件,请注意我正在使用supervisor-stdout
包将输出直接输出到主管,而不是记录数据,因为我更喜欢在一个地方看到所有数据:
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
[program:worker]
command=python /opt/applications/myproject/worker.py -A args
directory=/opt/applications/myproject
stdout_events_enabled=true
stderr_events_enabled=true
[eventlistener:stdout]
command = supervisor_stdout
buffer_size = 100
events = PROCESS_LOG
result_handler = supervisor_stdout:event_handler
我有一个包含上述两个文件的构建目录,我从那里的终端构建了Dockerfile
with:
docker build -t fgkrqworker .
这添加了它,以便我可以从docker
or docker-compose
。不要跳过尾随点!
由于该应用程序使用docker-compose
要运行一组容器,现有的WORKER
容器将被替换为能解决我的问题的容器。但首先我想表明,在我的另一部分docker-compose.yml
我定义了从容器到本地硬盘驱动器的映射,这是被映射的多个卷之一:
volumes: &VOLUMES
? /Users/me/source/myproject:/opt/applications/myproject
然后是我的容器的实际定义,它引用了上面的内容VOLUMES
:
jqworker: &WORKER
image: fgkrqworker
privileged: true
stdin_open: true
detach: true
tty: true
volumes:
<<: *VOLUMES
ports:
- "7722:22"
这会将 SSH 端口映射到虚拟机中可用的已知端口,记得我正在使用boot2docker
它依赖于 VirtualBox,但需要映射到 PyCharm 可以访问它的位置。在 VirtualBox 中,打开boot2docker
虚拟机并选择Adapter 1
。有时,“附加到:”组合会自行取消选择,因此请注意这一点。就我而言,它应该有NAT
已选择。
单击“端口转发”并将内部端口映射到本地主机上的端口,我选择使用相同的端口号。它应该是这样的:
- Name:
ssh_mapped
;
- 协议:
TCP
;
- Host IP:
127.0.0.1
;
- 主机端口:
7722
;
- 访客 IP:;
- 访客端口:
7722
Note:注意不要更改 boot2dockerssh
设置,否则您最终将无法正确启动虚拟机。
所以,此时我们有了一个扩展我的目标容器的容器。它在端口上运行 ssh22
并将其映射到7722
因为其他容器可能想要使用22
,并且在 VirtualBox 环境中可见。 VirtualBox 地图7722
to 7722
到本地主机,你可以通过 ssh 进入容器:
ssh root@localhost -p 7722
然后将提示输入密码“soup4nuts”,您应该能够找到特定于您的容器的内容,以验证它是否正确并且一切正常。如果我将其部署在本地计算机以外的任何地方,我不会弄乱 root,所以请注意。这仅适用于本地调试,您应该三思而行在实时站点上执行此操作.
如果您使用过 PyCharm 的远程调试,此时您可能可以弄清楚其余部分。但我是这样设置的:
首先,请记住我有docker-compose.yml
映射项目目录:
? /Users/me/source/myproject:/opt/applications/myproject
在我的容器里/opt/applications/myproject
实际上是/Users/me/source/myproject
在我的本地硬盘上。所以,这是我的项目的根源。我的 PyCharm 将此目录视为项目根目录,我希望 PyCharm 编写.pycharm_helpers
在这里,以便它在会话之间持续存在。我正在管理 mac 端的源代码,但 PyCharm 认为它是其他地方的 unixy 盒子。是的,在 JetBrains 整合 Docker 解决方案之前,这有点混乱。
首先,转到 Project X/Project Structure 并创建本地映射的内容根,在我的例子中这意味着/Users/me/source/myproject
稍后再回来补充.pycharm_helpers
对于排除的集合,我们不希望它最终进入源代码管理或混淆 PyCharm。
转到“构建”、“执行”、“部署”选项卡,选择“部署”并创建一个 SFTP 类型的新部署。主机是localhost,端口是7722
,根路径是/opt/applications/myproject
用户名是root
密码是soup4nuts
我选中了保存密码的选项。我将我的部署命名为“dockercompose”,以便稍后能够将其挑选出来。
在“部署映射”选项卡上,我将本地路径设置为/Users/me/source/myproject
以及部署和 Web 路径到单个“/”,但由于我的代码不对应于 URL 并且我不使用它来调试,因此它是 Web 路径设置中的占位符。我不知道你如何设置你的。
在 Project X/Project Interpreter 选项卡上,创建一个新的远程 Python 解释器。您可以选择部署配置并选择dockercompose
我们上面创建的配置。主机 URL 应填写为ssh://root@localhost:7722
Python 解释器路径可能是/usr/bin/python
。我们需要设置 PyCharm Helpers Path,因为默认值将无法在重做的容器中保留下来。我实际上转到了我的项目本地目录并创建了一个.pycharm_helpers
根目录下,然后将此处的路径设置为/opt/applications/myproject/.pycharm_helpers
当我点击“确定”按钮时,它将文件“向上”复制到目录中。我不知道它是否会自动创建它。
不要忘记.pycharm_helpers
目录可能应该被排除在项目根选项卡上。
此时,您可以转到“构建”、“执行”、“部署”选项卡,然后在“控制台/Python控制台”下,选择我们上面创建的远程解释器并将工作目录设置为/opt/applications/myproject
如果您愿意,您可以在容器中运行 Python 控制台。
现在您需要创建一个运行配置,以便您可以远程调试您的 python 代码。进行新的 Python 配置并将脚本设置为用于在容器中启动 python 代码的脚本。我的,从主管设置来看,上面是:
/opt/applications/myproject/worker.py -A args
所以我将脚本设置为/opt/applications/myproject/worker.py
和参数-A args
.
选择我们上面创建的远程解释器,以及需要的工作目录,对我来说是/opt/applications/myproject
对我来说就可以了。
现在我想进入我的容器并停止worker.py
脚本,以便我可以启动调试版本。当然,如果您愿意,可以忽略默认运行脚本,仅使用容器进行调试。
我可以打开 ssh 会话来停止脚本,但 docker 提供了一个有用的命令,可以通过将脚本传递到环境中来为我完成工作。
$> docker exec -i -t supervisorctl stop worker
因为我的进程被命名为“worker”。请注意,您可以通过替换来重新启动stop
命令与start
.
现在,在 PyCharm 中使用上面创建的运行配置启动调试会话。它应该连接并启动并在窗口中为您提供控制台输出。自从我们杀死了监督最初启动的那一个以来,它就不再连接了。
这是凭感觉进行的操作,因此可能存在我没有注意到的错误和不正确的假设。特别是,PyCharm 设置需要几次迭代,因此顺序可能不正确,如果失败,请尝试重试。这是很多东西并且很容易跳过一些关键的东西。