本篇是关于如何在 Pycharm 和 VSCode 中使用 Docker Compose 的. 开篇比较啰嗦, 大抵是踩过的一些坑和问题的解决过程, 实际的配置内容自 转 这一节开始.
起
公司的项目是通过 docker compose
进行管理, 包含 nginx \ sql \ backend 等几个部分, 后端开发的时候, 主要关注的是 backend 服务.
backend 具有如下的一个目录结构, 在开发时, 通用的一个方法是使用 docker compose up -d
开启集群服务, 然后使用 vscode
的 docker 相关的插件, attach
到对应的服务中, 进行开发. 由于使用了 -v 挂载目录, 所以不需要担心修改内容丢失的问题.
├── django_www
├── ...
├── manage.py
├── poetry.lock
├── poetry.toml
├── pyproject.toml
└── pytest.ini
├── docker-compose.yml
├── frontend
├── Dockerfile
└── ...
笔者算是第一次用 vscode 进行项目级别的后端开发, 在配置玩 python 的各种插件之后, 终于是完成了 文本编辑器 到 ___IDE__ 的蜕变.
不过作为一个3年 pycharm 用户, 闲暇之余, 自然是比较好奇项目在TL口中”比较麻烦”的 pycharm 是个什么样子.
承
VSCode 中的开发模式
想要在 PyCharm 中实现 docker compose dev , 最好是能够先了解这样的开发模式在 vscode 运作的核心流程 \ 原理.
在 VSCode 中选择 attach to a running container 之后, 首先会看到编辑器提示 start dev container…, 随后, 容器中会安装(如果是第一次 attach )并启动一系列的 vscode-server
进程. 这实际上与之前使用 ssh
连接远程服务器 (remote-server) 进行开发的过程是差不多的. (当然, 从命令的角度来看, attach 与 ssh 存在本质上的区别, exec 更加接进 ssh)
于是, 可以总结出基于 vscode 的开发流程如下:
- attach 到运行中的项目容器
- 安装 vscode-server && 安装 vscode-extensions
- 完成开发的前置工作.
在 PyCharm 中复刻?
pycharm 在官方文档中有 docker-compose 这样一篇配置教程. 按照这个流程走完之后, 就可以在pycharm中运行一个 demo 级的 docker-compose 结构的项目.
但是项目的运行却出现了问题. 项目的依赖使用 poetry 进行管理, Dockerfile 中只存在 poetry install --no-dev
这样的依赖安装流程, 这是因为这样的安装不会牵扯进 开发级别 的依赖, 如 pytest
\ mypy
等ci相关的依赖. 所以在开发的时候, 还需要在容器中执行 poetry install
或者 poetry update
来将缺失的开发依赖加进来.
这样就引出了我们遇到的问题, container 一旦重启, 那就 需要重新执行一遍安装命令 , 当开发依赖很多时, 这个过程就很痛苦了. 使用 vscode -> attach docker container
的方法, 我们可以保证在不重启容器的情况下完成开发. 但是对于 pycharm 来说, 每一次启动, 都会对容器进行重建, 那我们之前安装的东西就全清空了.
自然地, 笔者开始寻找 pycharm 中有没有不重建容器的办法, 因为在 django 的运行配置中, 有 docker compose
一栏, 能够配置相关的命令和参数, 但是这里只能配置pycharm支持的命令和参数, docker compose up --no-recreate
之类的命令恰好是不被支持的.
inspect
到 pycharm 创建的容器中, 可以发现, 它并没有按照 docker-compose.yaml
文件中的 command
执行, 而是启动了如下的命令.
"Args": [
"-u",
"/opt/.pycharm_helpers/pydev/pydevd.py",
"--multiprocess",
"--qt-support=auto",
"--port",
"56286",
"--file",
"/var/www/src/django_www/manage.py",
"runserver",
"0.0.0.0:3001"
]
看来是 pycharm 用自带的命令组替换了我们之前用来锚定容器的 tail
命令. 再更深一步地看一下, PyCharm是怎样实现这种 cmd
替换的?
监控 PyCharm 的运行过程, 捕获到如下的指令:
/usr/local/bin/docker-compose -f /Users/xinjian.zhang/Projects/Garena/WebSZ/kop-event/shipdoom.kop.kingdomofpirate.com/src/docker-compose.dev.yml -f /Users/xinjian.zhang/Library/Caches/JetBrains/PyCharm2022.1/tmp/docker-compose.override.890.yml up --exit-code-from web --abort-on-container-exit web
结合 官方文档中关于 multi file 的说明, 得到 PyCharm 在 compose 中的 Debug 运行过程.
- 使用自带的 override.yml 来追加 \ 覆盖原有的构建文件.
- 在 container 中开启一个调试器 (pydev debugger)
- attach 到 container 中, 并连接 (connect) 上调试器
到此, 基本上可以确定, 无法在 PyCharm 中复刻 vscode 的 attach
开发模式. 不过正如前文所说, vscode 的 attach
实际上是 ssh
的变种, 对于 PyCharm 来说, 实现 ssh remote 开发是完全没有问题的. 不过笔者并没有在 ssh
的路上继续走下去.
转
总结一下目前的困境的成因, 主要还是每次启动程序都会 recreate 容器, 而更上一层的原因则是, 开发环境与生产环境的割裂 , 导致我们需要在生产环境的docker中, 将环境更新为开发环境. 那何不一开始就搭建一个开发环境呢? 这样任他重建多少次, 我都不需要在对容器环境上下其手, 开箱即用便是.
于是笔者对项目的目录结构稍作修改.
├── django_www
├── ...
├── manage.py
├── poetry.lock
├── poetry.toml
├── pyproject.toml
└── pytest.ini
├── docker-compose.yml
├── docker-compose.dev.yml
├── frontend
├── Dockerfile
├── dev.Dockerfile
└── ...
然后在安装的时候再加入了一些小trick.
生产环境使用的是私有源, 开发环境下这个源下载速度较慢.
包含两种源, 分别是python和linux的源.
解决python的源需要修改 poetry 的配置文件, 也就是 pyproject.toml 和 poetry.lock, 但是这两个文件是无法通过上述的方法去copy一个替代品的, 所以在安装的时候, 使用sed
命令将其中的私有源替换为加速源.
解决linux源的问题与python的方法无二, 修改 source.list 文件.对于 pure(slim\apline) 镜像, 先将常用的软件安装齐备.
生产环境的镜像为了瘦身, 往往会将很多软件剪除, 但是开发环境需要这些常用的工具用来调试与监测, 如ping
\top
\vim
等.使用 override config 来升格 docker-compose.dev.yml.
Docker Compose 是支持在构建时使用两份 yml 文件的, 详见 Share Compose configurations between files and projects, 所以我们可以将 dev 环境的 compose 作为一个 override 配置来使用, 从而避免污染项目目录.
20220604内容增补
上述目录结构中的 dev.Dockerfile
文件其实也并非必要, 在 docker compose 3.4 的版本更新中加入了 target 参数, 用来指定构建 Dockerfile 中的哪一个区块, 至此, prod 和 dev 的构建指令就可以合并到一份文件中了.
合
至此, 对 pycharm 运行 docker-compose 下的 django 的探索告一段落. 不过过程中产生的一些疑惑与问题还需要更多的深入研究来解开.
基于 docker compose 的开发策略
看起来, 如果纠结于使用 pycharm 的话, 在项目的结构上就有了比较严格的约束. 那么这到底是是 docker 的开发模式的问题, 还是 pycharm 的设计问题呢?
在详细地查阅了相关的文档之后发现, vscode 的其实提供了 两种基于 contaniner 的开发方案. 其中, 使用 docker-compose 的开发方案中提供了详尽的外装开发模式的配置策略. 基于这个文档策略, 甚至可以对 PyCharm 文档中给出的 compose 开发方案进行进一步的优化… (不愧是宇宙第一开发工具😰)
vscode 所提供的两种配置, 目前看来都是基于 attach 的, 所以在性能上应该差距不大, 只不过配置 devcontainer 可以避免直接 attach 造成的 重建 相关的问题.
Docker 在开发中的使用
基于 docker compose 的开发方案究竟是掣肘还是利器?
摆脱docker进行开发? — 我在doccano的二次开发中进行了这样的尝试.
性能比较
以下的负载统计均为程序运行一段时间后趋于稳定的负载信息. 即使如此, 以下的统计依然过于粗略, 看个乐呵就行.
总的来说, pycharm 看上去容器的负载会比 vscode 低一些, 不过推测是 IDE 将一部分插件的功能转嫁到程序本身, 而编辑器则是将这部份损耗通过 vscode-server 一并附加到了容器中.
vscode
图片解释: 由于预先安装了 vscode-server, 所以会存在部分 vscode 相关的程序.
server 端的 vscode 中安装的插件如下:
- batisteo.vscode-django-1.10.0
- ms-python.python-2022.6.2
- ms-python.vscode-pylance-2022.5.3
- ms-toolsai.jupyter-2022.4.1021342353
- ms-toolsai.jupyter-keymap-1.0.0
- ms-toolsai.jupyter-renderers-1.0.7
- ms-vscode.makefile-tools-0.5.0
- njpwerner.autodocstring-0.6.1
下图则是运行 django 之后的负载情况.