使用 Dev Containers 进行本地开发
你可能经历过这样的场景:一位新开发者加入你的团队,两天后他们仍在与 Node 版本冲突、缺失的依赖项以及在所有人的机器上都能运行但唯独在他们机器上不行的环境变量作斗争。与此同时,你们的实际项目却原封不动。
Dev Containers 通过将你的整个开发环境——运行时、工具、扩展和配置——打包到一个在每台机器上都能完全相同运行的容器中来解决这个问题。本文将解释 Dev Containers 如何为前端团队创建可复现的开发环境,而无需深入的 Docker 专业知识。
核心要点
- Dev Containers 将你的整个开发环境——运行时、工具、扩展和设置——打包到一个可复现的、代码定义的容器中。
- 单个
devcontainer.json文件可以替代冗长的设置文档,并消除”在我的机器上可以运行”的问题。 - 预构建的镜像涵盖了大多数前端需求,而 Docker Compose 则处理多服务设置。
- 理解
containerEnv和remoteEnv(以及containerUser与remoteUser)之间的区别可以避免常见的权限和配置错误。 - Dev Containers 提供一致性而非不可变性——固定你的镜像版本并定期测试配置。
Dev Containers 实际做什么
Dev Containers 是专门为开发工作配置的 Docker 容器。与运行应用程序的生产容器不同,Dev Containers 运行你的整个开发环境。你的编辑器连接到容器,所有工具都在容器内执行。
其核心理念很简单:与其编写设置步骤文档并希望每个人都正确遵循,不如用代码定义你的环境。当开发者打开你的项目时,他们获得的 Node 版本、linting 工具和编辑器扩展与其他所有人完全相同。
这种容器化本地开发的方法完全消除了”在我的机器上可以运行”的问题。你的 devcontainer.json 文件成为如何在你的项目上进行开发的唯一真实来源。
你需要理解的核心概念
devcontainer.json 文件
每个 Dev Container 配置都从一个 devcontainer.json 文件开始,通常存储在项目根目录的 .devcontainer 文件夹中。这个文件告诉你的编辑器如何构建或拉取容器以及在其中配置什么。
前端项目的最小配置如下所示:
{
"name": "Frontend Dev Environment",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"forwardPorts": [3000],
"customizations": {
"vscode": {
"extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
}
}
此配置拉取一个支持 TypeScript 的预构建 Node 20 镜像,转发端口 3000 以便你可以从主机浏览器访问开发服务器,并在 VS Code 中自动安装 ESLint 和 Prettier 扩展。
镜像 vs. Dockerfiles
你有两个选项来定义容器的基础。使用预构建镜像(如上例)更简单且更快——容器启动迅速,因为无需构建任何内容。使用 Dockerfile 可以完全控制,但会增加构建时间。
对于大多数前端项目,来自微软 Dev Container 镜像仓库的预构建镜像效果很好。你可以使用 Features 扩展它们——这是安装特定工具的模块化添加项,无需自定义 Dockerfile。
用于复杂设置的 Docker Compose
当你的前端在开发期间需要后端服务——数据库、API 服务器或 Redis 缓存时——Docker Compose 集成允许你定义多容器环境。你的 devcontainer.json 引用 Compose 文件,所有服务一起启动。
{
"name": "Full Stack Dev Environment",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace"
}
在此设置中,service 属性指定 Compose 文件中你的编辑器应连接到哪个容器,而其余服务(数据库、缓存、API)则在其旁边运行。
Discover how at OpenReplay.com.
环境变量:containerEnv vs. remoteEnv
这个区别很重要且容易引起混淆。containerEnv 在容器启动时设置变量——它们对所有进程可用。remoteEnv 仅为编辑器生成的进程设置变量。对构建工具需要的变量使用 containerEnv,对编辑器特定的设置使用 remoteEnv。
{
"containerEnv": {
"NODE_ENV": "development",
"API_URL": "http://localhost:4000"
},
"remoteEnv": {
"EDITOR_THEME": "dark"
}
}
类似地,containerUser 决定谁拥有容器中的进程,而 remoteUser 控制编辑器以哪个用户身份连接。设置错误会导致让开发者沮丧的权限错误。在大多数情况下,将 remoteUser 设置为 "node"(对于基于 Node 的镜像)可以避免生成文件的 root 所有权问题。
Dev Containers 无法保证什么
扩展安装和工作区设置在重建过程中并非完全可复现。扩展会更新,某些设置依赖于本地状态。当你使用更新的基础镜像重建时,烘焙到镜像中的配置也可能发生变化。
接受 Dev Containers 提供的是一致性,而非不可变性。固定你的镜像版本(例如,使用特定的 SHA 摘要或带日期的标签而不是 latest)并定期测试你的配置。
值得考虑的权衡
Dev Containers 会增加启动时间——容器必须构建或拉取后你才能工作。它们会占用镜像的磁盘空间。而且你的团队需要对 Docker 概念有基本的熟悉,即使他们从不编写 Dockerfile。
对于入职需要数天且环境漂移经常导致问题的团队来说,这些成本微不足道。对于从事简单项目的独立开发者来说,可能不值得。
值得关注的新兴工作流
团队越来越多地通过 Dev Container 配置集成 AI 编码助手和代理式服务。容器不仅成为你的开发环境,还成为自动化工具操作代码的环境。这种模式正在快速发展,但基础——将环境定义为代码——保持稳定。
入门指南
VS Code 提供了最流畅的 Dev Container 体验。安装 Docker Desktop,添加 Dev Containers 扩展,并从命令面板运行 Dev Containers: Add Dev Container Configuration Files。选择与你的技术栈匹配的模板,几分钟内你就能在容器中运行。
其他编辑器也支持 Dev Containers。JetBrains IDE(如 IntelliJ 和 WebStorm)提供内置的 Dev Container 支持,开源的 Dev Container CLI 允许你从任何终端或 CI 流水线使用 Dev Containers。
结论
设置 Dev Container 的投资在新队友第一天而不是第三天开始贡献时就会得到回报。通过在单个 devcontainer.json 文件中将开发环境定义为代码,你用可复现、可共享的配置替代了脆弱的设置文档。权衡——启动时间、磁盘空间和对容器的基本理解——与调试环境漂移所浪费的时间相比微不足道。从预构建镜像开始,添加团队依赖的扩展,然后从那里迭代。
常见问题
不需要。对于大多数前端项目,你只需要安装并运行 Docker Desktop。devcontainer.json 文件处理配置,微软的预构建镜像消除了编写 Dockerfile 的需要。对容器是什么有基本认识有助于故障排除,但入门不需要深入的 Docker 专业知识。
可以。JetBrains IDE(如 IntelliJ 和 WebStorm)具有内置的 Dev Container 支持。还有一个开源的 Dev Container CLI,允许你从任何终端构建和运行 Dev Containers,使它们可在 CI 流水线或其他支持远程开发工作流的编辑器中使用。
你可能会注意到文件系统操作稍慢,特别是在 macOS 和 Windows 上,因为文件在主机和容器之间共享。使用命名卷或将项目存储在容器文件系统内可以减少这种开销。CPU 和内存性能通常与原生开发相当。
可以。Dev Containers 支持 Docker Compose,它允许你定义多容器环境。你的编辑器连接到一个容器,而数据库、API 服务器和缓存在其旁边的独立容器中运行。当你打开项目时,所有服务一起启动。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.