Dev Container — 统一 Mac / Windows / Linux 开发环境
使用 VS Code Dev Containers 消除操作系统差异。基于 Docker 的可复现开发环境,由全团队共享的单一 devcontainer.json 定义。
「在我机器上能跑」这句话,通常源于操作系统差异。Mac 有 brew 和 Apple Silicon,Windows 有 PowerShell 和 UTF-16,Linux 机器有 systemd。即使所有人安装了相同版本的 Node 和相同的包,细微差异仍然存在。
我认为 Dev Containers 解决的不只是环境一致性,而是入职成本。以前新团队成员需要花数天配置开发环境;如今通过 devcontainer.json 共享的容器化环境,克隆加一条命令就能获得完全相同的环境,因为环境定义本身已经成为代码库的一部分。
Dev Containers(VS Code Dev Containers + 标准 devcontainer.json)将操作系统差异封装在 Docker 容器内。整个团队在同一个 Linux 环境中工作,只有 IDE 运行在宿主机上。本指南介绍如何配置一个可在 Mac、Windows 和 Linux 宿主机上完全一致运行的开发容器。
TL;DR
- 安装 Docker 运行时(Mac:OrbStack/Docker Desktop,Win:Docker Desktop/WSL Docker,Linux:docker)
- VS Code + Dev Containers 扩展(
ms-vscode-remote.remote-containers) - 在项目根目录添加
.devcontainer/devcontainer.json Cmd/Ctrl+Shift+P→ Dev Containers: Reopen in Container — IDE 在容器内重新启动- 新团队成员:克隆 → 执行该命令一次 → 获得完全相同的环境
前置条件
- VS Code 1.95+
- Docker 运行时 — 各 OS 安装指南:mac/docker-setup · windows/docker-wsl2
- 项目已纳入 Git 管理(以便共享 devcontainer.json)
1. 为什么使用 Dev Containers
解决的问题
- 「在我机器上能跑」 — 容器内操作系统和工具链完全一致
- 加快上手速度 — 新员工无需阅读 30 行的 README,点击一次即可
- 版本冲突 — 项目 A 用 Node 18,项目 B 用 Node 22 — 无需宿主机的 mise/nvm,完全隔离
- OS 特有的构建问题 — 绕过 Apple Silicon ARM 问题、Windows 长路径问题等
- 与 CI 保持一致 — 使用与 GitHub Actions 工作流相同的基础镜像,消除差距
Dev Containers 的不足
- GUI 应用开发 — Mac 原生或 Windows 原生 UI 构建不适合放在容器中
- GPU 密集型工作负载 — 部分 GPU 直通可行,但在宿主机上运行更稳定
- 低配置机器 — Docker 本身额外占用 1–2GB 内存(16GB 配置下问题不大)
2. 最简 devcontainer.json
.devcontainer/devcontainer.json:
{
"name": "My Project Dev",
"image": "mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
},
"forwardPorts": [3000, 5173],
"remoteUser": "node"
}关键字段说明:
| 字段 | 作用 |
|---|---|
image | Docker 基础镜像(Node / Python / Go / Rust 等) |
features | 附加工具(git、gh、docker-in-docker、awscli — 从目录中按需选取) |
postCreateCommand | 容器创建后执行一次(安装依赖等) |
customizations.vscode.extensions | 在容器内自动安装的 VS Code 扩展 |
forwardPorts | 暴露给宿主机的端口 |
remoteUser | 容器内用户(出于安全考虑,建议使用非 root 用户) |
3. 首次运行
VS Code 命令面板(Cmd/Ctrl+Shift+P) → Dev Containers: Reopen in Container。
- 首次运行:约 1–3 分钟(拉取镜像 + 执行
postCreateCommand) - VS Code 左下角显示
Dev Container: My Project Dev
# 容器内终端(VS Code Terminal)
uname -a
# Linux 1234abcd 6.10.x #1 SMP Debian ...
which node
# /usr/local/share/nvm/versions/node/v22.x/bin/node无论宿主机操作系统如何,均使用相同的 Linux 环境。
4. 选择基础镜像
devcontainer.json 中的 image: 字段。官方目录:
| 语言 / 技术栈 | 镜像 |
|---|---|
| Node.js | mcr.microsoft.com/devcontainers/javascript-node:1-{18,20,22}-bookworm |
| Python | mcr.microsoft.com/devcontainers/python:1-{3.11,3.12,3.13}-bookworm |
| Go | mcr.microsoft.com/devcontainers/go:1-{1.22,1.23} |
| Rust | mcr.microsoft.com/devcontainers/rust:1-bookworm |
| Java | mcr.microsoft.com/devcontainers/java:1-{17,21}-bookworm |
| .NET | mcr.microsoft.com/devcontainers/dotnet:1-9.0-bookworm |
| Universal(多语言) | mcr.microsoft.com/devcontainers/universal:2-linux |
建议:单一语言项目 → 使用对应语言的镜像;多语言项目 → 基础镜像 + features 组合。
也可以编写自定义 Dockerfile:
{
"name": "My Custom Dev",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
}
}5. features — 一行添加工具
features 块使用官方目录(https://containers.dev/features)中的模块。一行即可安装工具。
常用选项:
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/docker-in-docker:2": {}, // 在容器内运行 docker
"ghcr.io/devcontainers/features/aws-cli:1": {},
"ghcr.io/devcontainers/features/terraform:1": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
}6. Docker-in-Docker — 容器内运行容器
当需要在开发容器内执行 docker run(测试 docker-compose、验证构建)时:
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"dockerDashComposeVersion": "v2"
}
}或共享宿主机的 Docker socket(更轻量,但安全性略低):
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
]7. 宿主机 ↔ 容器文件挂载
工作区文件夹自动挂载到 /workspaces/{project}。
追加挂载:
"mounts": [
"source=${localEnv:HOME}/.aws,target=/home/node/.aws,type=bind,readonly",
"source=${localEnv:HOME}/.gitconfig,target=/home/node/.gitconfig,type=bind"
]macOS 挂载性能优化请参见 docker-setup §5.2(推荐 VirtioFS)。
8. 环境变量与密钥
静态环境变量
"containerEnv": {
"NODE_ENV": "development",
"LOG_LEVEL": "debug"
}密钥(切勿提交)
挂载 .env 文件或通过 localEnv 传入:
"containerEnv": {
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
"OPENAI_API_KEY": "${localEnv:OPENAI_API_KEY}"
}宿主机 shell 的环境变量会注入容器。请将 .env 添加到 .gitignore。
9. 多容器(docker-compose 集成)
为 DB / Redis 等依赖服务使用多容器:
.devcontainer/docker-compose.yml:
services:
app:
image: mcr.microsoft.com/devcontainers/javascript-node:1-22-bookworm
volumes:
- ..:/workspaces/myapp
command: sleep infinity
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: dev
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:.devcontainer/devcontainer.json:
{
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/myapp"
}VS Code 附加到 app 容器,db 容器自动启动。
10. 与 CI 保持一致 — devcontainer-cli
在 CI 中复用 devcontainer.json:
npm install -g @devcontainers/cli
# 构建容器并运行命令
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . npm testGitHub Actions:
# .github/workflows/test.yml
- name: Test in dev container
uses: devcontainers/ci@v0.3
with:
runCmd: npm testCI 通过 = 本地相同结果。
11. 验证
# 宿主机
docker --version
# 容器内(VS Code Terminal)
uname -a # Linux ...
which node # /usr/local/share/...
echo $NODE_ENV # development(containerEnv 已生效)
node --version # 容器中的 Node 版本
git --version # 通过 features 安装五项均在容器内正常响应 = 配置完成。
12. 故障排查
「Failed to connect」/ 容器启动失败
- Docker 运行时是否正在运行?(Docker Desktop 菜单栏、
orb status、colima status) docker ps检查是否存在端口/名称冲突- VS Code → 命令面板 → 「Dev Containers: Rebuild Without Cache」
构建耗时极长
- 首次构建需要拉取基础镜像(多 GB)— 这是正常现象
- 后续构建使用缓存。
postCreateCommand不使用缓存(每次重建都会执行) - 区分
onCreateCommand(仅执行一次)和postCreateCommand(每次重建都执行)
文件权限拒绝
- 容器 UID 与宿主机 UID 不匹配(Linux 宿主机上尤为常见)
- 设置
remoteUser和updateRemoteUserUID:"remoteUser": "vscode", "updateRemoteUserUID": true
forwardPorts 不生效
- 容器内应用是否绑定到
0.0.0.0或::(而非127.0.0.1)? - 示例:Next.js 需要
next dev -H 0.0.0.0
容器内无法读取宿主机 Git 配置
.gitconfig自动挂载是可选的 — 请在mounts中显式添加- 或依赖 features 中的 git,它会复制
gitconfig
IDE 在大型 node_modules 下运行缓慢
- 将
node_modules从 VS Code 的文件监控中排除(files.watcherExclude) - 或将
node_modules放在仅限容器的卷中,而非宿主机挂载:"mounts": [ "source=${localWorkspaceFolderBasename}-node-modules,target=/workspaces/${localWorkspaceFolderBasename}/node_modules,type=volume" ]
13. 下一步
- Mac Docker — /mac/docker-setup(运行时对比)
- Windows Docker WSL2 — /windows/docker-wsl2
- 远程开发 — /multi-os/remote-development — 将远程机器作为开发环境
- Dotfiles 同步 — /mac/dotfiles — 通过 chezmoi 在开发容器中应用 dotfiles
参考资料
更新日志
- 2026-05-16:初稿。devcontainer.json 要点 · 基础镜像选择 · features · docker-compose 集成 · CI 集成 · 六个故障排查案例。