VS Code 连接 Docker 容器并同步主机工作区

这次要解决什么问题

当时的工作流是:代码写在主机上,程序跑在 TensorFlow 容器里。每改一次 tf.py,都要手动执行:

docker exec tf python ./tf.py

能运行,但调试体验很差:编辑器不在真正的运行环境里,断点、解释器和依赖也容易对不上。于是这次尝试的目标很具体:

  1. 代码仍然放在主机工作区;
  2. Python 依赖和运行环境放在容器里;
  3. VS Code 能直接打开容器里的项目;
  4. 修改主机文件后,容器可以立即看到变化。

先理解文件是怎么同步的

这里并没有把文件“复制”两份,而是通过 Docker 的 bind mount 把主机目录挂载到容器目录:

主机 ~/Project  ── bind mount ──>  容器 /root/Project
       │                              │
       └── VS Code 编辑               └── Python 运行 / 调试

因此,代码修改会直接反映在两边。但依赖安装、容器内生成的缓存和编译产物不一定应该放在主机目录里。尤其是主机和容器的操作系统、文件权限或二进制格式不一致时,盲目共享整个目录会带来新的问题。

准备一个带挂载目录的容器

当时使用的是 TensorFlow GPU 镜像:

docker run --gpus all -itd \\
  --name tf \\
  --rm \\
  -v ~/Project:/root/Project \\
  tensorflow/tensorflow:latest-gpu-py3

参数的作用:

  • --gpus all:把可用 GPU 暴露给容器;没有 GPU 或未配置运行时的机器不应照搬;
  • --name tf:给容器一个稳定名字,方便 docker exec 和 VS Code 查找;
  • --rm:容器停止后自动删除容器本身,但挂载在主机上的代码不会因此删除;
  • -v ~/Project:/root/Project:把主机目录挂载到容器目录。

启动后先不要急着连 VS Code,先确认挂载和 Python 环境:

docker ps
docker exec tf pwd
docker exec tf ls -la /root/Project
docker exec tf python --version

如果主机目录在容器里看不到,先解决挂载问题,不要把代码再复制一份到容器里继续排查。

用 VS Code 连接正在运行的容器

当时安装了两个扩展:

  • Docker;
  • Remote Development。

VS Code 的 Docker 插件

Docker 扩展可以确认 tf 容器是否正在运行,Remote Development 提供连接容器的入口。

Remote Development

选择正在运行的容器后,打开容器中的 /root/Project 目录:

VS Code in Container

连接成功后,VS Code 的终端、Python 解释器和调试进程都会运行在容器环境里。第一次进入时,编辑器可能会在容器中安装 VS Code Server 或相关组件,这部分属于远程编辑器运行环境,不等同于把项目依赖安装进镜像。

运行和调试一个最小文件

在主机的 ~/Project 下创建 tf.py:

import tensorflow as tf

print("hello tensorflow")
print(tf.__version__)

然后从容器内执行:

python /root/Project/tf.py

也可以在 VS Code 中选择容器内的 Python 解释器,再点击运行或调试按钮。

run tensorflow

此时修改主机上的 tf.py,容器内的文件应立即变化:

printf '\nprint("changed")\n' >> ~/Project/tf.py
docker exec tf tail -n 3 /root/Project/tf.py

Docker 主机文件同步

这就是“同步”真正发生的地方:两边访问的是同一份挂载内容,而不是 VS Code 替你做了一次隐式上传。

常见问题和边界

主机文件变成 root 所有

如果容器内用 root 用户创建文件,主机上可能看到 root 所有的文件。开发容器最好配置与主机用户对应的非 root 用户,或者在创建文件前明确检查 UID/GID。

依赖装了但重启后消失

如果只是把依赖安装在临时容器里,删除容器后自然会消失。应该把依赖写入 Dockerfile,或者使用新版 VS Code Dev Containers 的 devcontainer.json 配合 Dockerfile 管理开发环境。

挂载目录遮住镜像里的目录

如果镜像中 /root/Project 原本有文件,挂载主机目录后,主机目录会遮住容器里的原内容。需要区分“镜像内文件”和“挂载内容”,不要看到文件消失就直接重建镜像。

latest 不是稳定版本

原文使用了 latest-gpu-py3,这是当时为了快速验证的选择。长期项目应固定经过验证的镜像标签,并把 CUDA、Python、框架和驱动的兼容关系记录下来。否则镜像更新后,同一条命令可能得到不同环境。

现在更推荐的维护方式

手工启动容器适合快速验证;长期使用时,可以把这些信息写进项目文件:

  • Dockerfile:记录基础镜像和依赖;
  • devcontainer.json:记录 VS Code 如何创建或连接开发容器;
  • Compose 文件:记录多个服务、挂载和端口;
  • README:记录启动、调试和清理命令。

这样换机器时,开发环境可以重新创建,主机工作区仍然通过挂载进入容器,不需要依赖某个已经被手动改过的容器。

这次实践最终解决的是“主机编辑、容器运行、VS Code 调试”之间的摩擦。文件挂载很方便,但它只解决文件在哪里,不会自动解决依赖版本、权限和镜像可复现性。

参考资料

可用性说明:本文发布于 2020 年 1 月,距今已超过五年。文中涉及的软件版本、接口、下载地址、命令参数和操作界面可能已经发生变化,部分方案在当前环境下可能失效。请结合官方最新文档核对后再操作,生产环境使用前务必先行验证。

版权声明: 本文首发于 指尖魔法屋-VS Code 连接 Docker 容器并同步主机工作区(https://blog.thinkmoon.cn/post/692-guide-vscode-docker/) 转载或引用必须申明原指尖魔法屋来源及源地址!