Vagrant + VirtualBox实践:从开发环境一致性问题到自动化管理 先聊一个几乎每个开发团队都会碰到的经典场景某同事在本地把功能跑得好好的一提交代码其他人拉到自己的电脑上直接跑不起来——不是缺依赖就是系统版本对不上号好不容易装好了发现线上服务器是 Linux自己本地是 Windows又是另一套配置。这种问题我调试过太多次了根子不在代码在环境。Vagrant VirtualBox 解决的就是这个痛点。它不是那种“教你装个虚拟机”的入门教程而是把整个开发环境用一种文本的方式固化下来——用什么操作系统、开哪些端口、要不要独立 IP、预装哪些软件全部写在一个叫 Vagrantfile 的配置文件里。任何人拿到这份文件只需要一条 vagrant up就能在本地拉起一个完全一致的环境。这篇文章会从原理讲起再带你把一个真实可用的开发环境从零搭起来最后把我踩过的坑和排查思路一并整理出来。适合两类人看一类是刚刚开始接触环境自动化、不想手动装虚拟机的开发者另一类是已经用过一阵 Vagrant、想搞明白配置项背后逻辑的人。1. 为什么要用 Vagrant VirtualBox开发环境三大痛点的解法1.1 痛点一环境不一致导致的“灵异现象”“在我机器上是好的”这句话几乎是所有开发团队内部流传最广的冷笑话。同一个项目你本地是 Node 18同事是 Node 16服务器上是 Node 20三个版本下某些依赖包的行为就是不一样有些 bug 只在特定版本上能复现。更别提操作系统层面的差异了——Windows 上的路径分隔符、文件权限模型、shell 行为和 Linux 完全是两回事。Vagrant 的做法很直接把整个开发环境的“期望状态”写进一个文本文件底层用 VirtualBox 创建一台完整独立的虚拟机。这台虚拟机跑的是什么系统、装了什么环境完全由配置文件决定跟你宿主机是什么系统没有任何关系。也就是说你在 Windows 上开发但项目运行在虚拟机里的 Ubuntu 上———这样就和服务器环境保持了一致。1.2 痛点二环境搭建过程的一次性浪费手动搭建环境的流程大家应该都经历过下载系统镜像、创建虚拟机、设置网络、替换软件源、装一堆依赖包、配环境变量……这套流程走一遍新鲜走两遍凑合走三遍就只想骂人。我见过有同事在本地手动搭环境花了整整一天最后卡在一个诡异的 libssl 版本冲突上一怒之下重装了系统。Vagrant 把整个过程分成两个阶段第一阶段有人或者某个基础镜像的维护者把环境的“初始状态”打包成一个 box 文件第二阶段其他人只需要基于这个 box 启动虚拟机再用 provision 脚本把后续要装的软件自动装好。第一次搭建可能要花点时间研究配置但这个配置文件是固定的以后每一次搭建都是完全自动化的不会再出现“这次多装了一个包、那次漏了一步”这种随机差异。1.3 痛点三多项目环境的互相干扰同时维护两三个项目的时候环境冲突几乎是不可避免的。项目 A 需要 PHP 7.4项目 B 需要 PHP 8.2项目 C 要用 MySQL 5.7项目 D 要用 MySQL 8.0。如果你把所有东西都装在宿主机上这些版本冲突会让你头大到怀疑人生。用 Vagrant 可以把每个项目封装在独立的虚拟机里项目 A 一个环境项目 B 一个环境互不干扰。用的时候 vagrant up 把对应项目的环境拉起来不用了 vagrant halt 直接关机。宿主机上只保留 Vagrant、VirtualBox 和一个文本配置文件干净得不能再干净。1.4 Vagrant 的设计哲学把基础设施当作文本来管理理解 Vagrant 的核心要抓住一个关键词可复现性。它的思路和“基础设施即代码”一脉相承——环境的定义、配置、变更都通过代码配置文件来管理而不是靠某个人脑子里的记忆或者一堆散乱的文档。你可以把 Vagrantfile 理解成一张“环境的配方单”它描述了需要什么样的系统、什么网络配置、什么软件。这份配方单可以提交到 Git 仓库里做版本管理可以走代码评审可以随时回滚。团队里任何一个人拿到这份配方都能生成一个一模一样的环境。这种思路看起来简单但真正用起来会让你从“人肉配置环境”变成“用代码管理环境”节省的精力远超想象。2. 核心概念与关键配置项解析2.1 Vagrant 和 VirtualBox 各自扮演什么角色这两个工具的分工经常被搞混。VirtualBox 是虚拟机软件它负责真正的虚拟化层——创建虚拟机、分配 CPU 内存、管理磁盘镜像。Vagrant 则是站在 VirtualBox 以及其他虚拟化平台之上的管理工具它通过和 VirtualBox 的 API 通信帮你完成“创建虚拟机—启动系统—执行配置脚本—建立 SSH 连接—同步文件夹”等一系列操作。说白了VirtualBox 是引擎Vagrant 是自动驾驶。你可以手动用 VirtualBox 完成全部操作但那样很累也可以只用 Vagrant 而完全不关心底层虚拟机的细节这样更省心。理论上 Vagrant 还支持 VMware、Hyper-V 等后端但 VirtualBox 是最常用、最不需要额外付费的选择也是绝大多数教程和实践的默认搭配。2.2 box 是什么环境模板的核心理解 box 是理解 Vagrant 的关键。box 本质上是一个预打包的虚拟机镜像文件它不只是一个裸的操作系统里面通常还预装了一些基础软件和 Vagrant 运行所需的组件。你可以把它理解成“手机出厂时的初始系统预装应用”的镜像而不是一台全新空白的机器。Vagrant 的 box 类别很多选择时需要留个心眼。官方仓库HashiCorp 维护的 Vagrant Cloud里有大量公开 box常见的有 generic/ubuntu2204、generic/debian12、bento/ubuntu-22.04 等。generic/ 系列由第三方维护质量比较稳定更新也算及时bento/ 系列由运维自动化公司维护也很可靠。选 box 的时候要注意确认它是否包含 VirtualBox 的 Guest Additions这直接影响同步文件夹的性能。2.3 Vagrantfile 的加载机制与配置分层Vagrantfile 的配置并不只有一个文件。实际加载的配置是从多个来源合并的优先级从低到高依次是Vagrant 自带的默认配置、box 内置的 Vagrantfile、项目根目录下的 Vagrantfile、用户主目录下的 ~/.vagrant.d/Vagrantfile。后面加载的配置会覆盖前面同名的配置。这个机制带来的实际价值是box 作者可以预设一些默认值比如端口转发规则、默认的用户名等项目维护者可以在项目 Vagrantfile 里覆盖这些默认值而每个开发者则可以在自己的用户级配置里加上一些个性化设置比如统一给所有虚拟机分配更多内存。这种分层设计避免了“为了改一个小配置就要 fork 整个项目”的尴尬。2.4 三种网络模式怎么选别一上来就照抄Vagrant 提供三种主要的网络模式很多人抄配置的时候根本没搞清楚它们之间的区别。第一种是 forwarded_port也就是端口转发。它把虚拟机里的某个端口映射到宿主机上的某个端口比如把虚拟机里的 8080 映射到宿主机的 8080你访问本机的 8080 就等于访问虚拟机的 8080。这种模式最安全、也最简单适合只在本地开发调试的场景。缺点是每次新增端口都要改配置并 reload而且映射的端口号不能冲突。第二种是 private_network私有网络。它会为虚拟机分配一个固定的私网 IP比如 192.168.56.10这个 IP 只有宿主机能直接访问在同一块 VirtualBox 创建的虚拟网卡上。适合需要模拟多台服务器互相通信的场景比如 Web 服务器访问数据库服务器。这种模式不需要关心端口映射App 里配置的端口就是真实端口更接近生产环境的网络拓扑。第三种是 public_network公有网络。虚拟机会通过宿主机所在的局域网 DHCP 获取一个独立的 IP局域网里的其他机器也能直接访问它。适合需要让手机、其他电脑联调测试的场景但要注意安全问题——虚拟机里的服务会直接暴露在局域网中如果没有做好访问控制风险比较大。我个人常用的组合是本地单机开发用 forwarded_port模拟集群用 private_network。如果你不确定选什么从 forwarded_port 开始后面随着需求变化再调。3. 完整实操从零搭建一个可复用的开发环境3.1 环境准备装好两个基础工具在写任何配置之前先把 VirtualBox 和 Vagrant 装好。VirtualBox 的安装比较简单去官网下载对应操作系统的安装包一路下一步就行。安装完成后会多出一个 VirtualBox 管理界面但大多数情况下你不需要打开它——Vagrant 会用命令行方式跟它交互。Vagrant 的安装同样直接。Windows 和 macOS 都有安装包Linux 可以用包管理器安装也可以通过二进制包安装。装完后在终端里执行 vagrant --version能输出版本号就说明成功了。安装时有两件事值得提前提醒。第一安装完 VirtualBox 后建议重启一下电脑尤其是 Windows 平台这是为了让虚拟化相关的驱动和内核模块正确加载否则后续创建虚拟机经常会报 VT-x 不可用的错误。第二Vagrant 的插件和管理操作非常依赖 SSH 和 rsyncWindows 用户建议提前装好 Git Bash 或者直接使用 Windows Terminal PowerShell在某些老版本的 Windows 上自带的 cmd 会对输出格式识别产生一些小问题。3.2 初始化项目生成第一个 Vagrantfile在你打算放置项目的目录里执行vagrant init generic/ubuntu2204这条命令会生成一个最基础的 Vagrantfile。打开看一下里面有很多注释掉的配置项都是从官方模板带出来的。这个文件用的是 Ruby 语法但你对 Ruby 一窍不通也没关系——绝大多数时候你只需要改几个 config.vm.xxx 的赋值。我建议把里面的注释全部删掉只留你真正用到的配置这样文件更清爽也减少被误导的机会。一个最小可用的配置是这样的Vagrant.configure(2) do |config| config.vm.box generic/ubuntu2204 config.vm.hostname dev-box config.vm.network forwarded_port, guest: 8080, host: 8080 config.vm.provider virtualbox do |vb| vb.name my-dev-env vb.memory 2048 vb.cpus 2 end end解释一下几个关键配置项config.vm.box 指定基础镜像config.vm.hostname 设置虚拟机的主机名config.vm.network 配置网络转发provider 段里是 VirtualBox 特有的设置vb.name 是显示在 VirtualBox 列表里的虚拟机名称vb.memory 和 vb.cpus 控制虚拟机的资源配额。3.3 启动虚拟机vagrant up 和它的完整流程配置文件写好后执行vagrant up第一次运行和后续运行会有截然不同的体验。第一次运行时Vagrant 会去下载对应的 box 文件如果本地没有缓存然后创建虚拟机、启动系统、执行配置脚本整个过程可能持续几分钟到十几分钟取决于你的网络速度和机器性能。后续再执行 vagrant up因为 box 已在本地缓存、虚拟机已创建基本上几十秒内就能完成启动。启动完成的标志是命令行输出 Machine booted and ready! 之类的提示。此时你可以通过vagrant ssh直接登录到虚拟机内部。这个命令会自动帮你建立 SSH 连接用的密钥信息是 Vagrant 自动生成的不需要手动输入密码。日常使用中最常用的几个命令值得单独列一下vagrant up # 启动虚拟机 vagrant halt # 关闭虚拟机相当于正常关机 vagrant suspend # 挂起虚拟机占内存但恢复快 vagrant reload # 重启虚拟机并重新加载配置 vagrant destroy # 彻底删除虚拟机不影响 box 缓存 vagrant status # 查看当前虚拟机状态destroy 这个命令要特别提醒它会删除虚拟机的磁盘文件但不会动你的项目源代码因为源代码是通过同步文件夹映射进去的宿主机上的文件不会被删除。不过虚拟机里如果安装了什么额外软件、改了什么系统配置这些会全部丢失。所以不要乱执行 destroy除非你确认环境可以通过 provision 完整重建。3.4 provision把软件安装过程固化下来第一次手动安装软件可以但从第二台机器开始手动安装就是浪费时间。Vagrant 的 provision 机制就是为了解决这个问题。provision 支持很多种方式最简单的就是 shell 脚本。你可以把环境初始化命令直接写在一段 shell 里比如config.vm.provision shell, inline: -SHELL apt-get update apt-get install -y nginx systemctl enable nginx SHELL也可以把脚本放在项目目录下用脚本路径引用config.vm.provision shell, path: bootstrap.sh这里有个很重要的细节provision 默认只在虚拟机的首次创建时执行如果虚拟机已经存在再修改 provision 配置后执行 vagrant reload 并不会自动重新执行脚本。你需要手动执行vagrant provision或者用 vagrant up --provision 强制重新执行。另一个使用 provision 的核心技巧是保证脚本的幂等性——也就是说脚本无论执行一次还是执行十次效果都应该是相同的。很简单的一个例子如果你用 apt-get install没问题它本身就是幂等的但如果你用 echo 追加内容到某个文件那你第二次执行脚本时就会出现重复追加的问题。一个简单的习惯是在追加内容前先用 grep 判断是否存在或者直接采用更规范的工具比如 Ansible来做配置管理。3.5 同步文件夹宿主机和虚拟机之间的文件交换你肯定不希望每次改代码都要手动复制到虚拟机里。Vagrant 默认把项目根目录即 Vagrantfile 所在目录同步到虚拟机里的 /vagrant 目录。你在宿主机上编辑代码虚拟机里立即可见在虚拟机里跑测试生成的文件宿主机上也能直接看到。默认的同步方式叫做 VirtualBox Shared Folders通过 VirtualBox 的 Guest Additions 机制实现通用但是性能一般尤其在文件数量多、小文件频繁读写的场景下速度确实比较慢。如果你对同步性能敏感可以考虑改用 NFSmacOS/Linux 宿主机或 rsync任何平台。例如config.vm.synced_folder ./www, /var/www/html, type: rsync这里要特别注意 rsync 是单向同步它只会把宿主机上的文件推送到虚拟机虚拟机里对同步目录的修改不会自动传回宿主机。如果你在用 IDE 远程编辑虚拟机内文件的工具这会带来非常难以排查的奇怪问题。所以在选择同步方式之前先确认自己的工作流是否需要双向同步。3.6 完整的配置示例一条命令拉起一个 LNMP 环境把上面所有的点串起来我给一个可以直接参考的配置。假设项目需要一个 Ubuntu 22.04 环境带 Nginx、PHP 8.1 和 MySQL并且需要在当前目录下直接编辑代码。Vagrant.configure(2) do |config| config.vm.box generic/ubuntu2204 config.vm.hostname dev-lnmp config.vm.network forwarded_port, guest: 80, host: 8080 config.vm.network forwarded_port, guest: 3306, host: 33066 config.vm.network private_network, ip: 192.168.56.10 config.vm.synced_folder ./code, /var/www/html config.vm.provider virtualbox do |vb| vb.name dev-lnmp-box vb.memory 2048 vb.cpus 2 end config.vm.provision shell, inline: -SHELL apt-get update apt-get install -y nginx php8.1-fpm mysql-server systemctl enable nginx systemctl enable mysql SHELL end启动后访问 http://localhost:8080 就能看到 Nginx 的欢迎页通过 192.168.56.10 也可以直接访问。MySQL 的 3306 我特意映射到了宿主机上的 33066避免冲突。这个配置不算复杂但它定义了一个完整、独立、可复现的开发环境——你把它提交到 Git 仓库任何人 clone 下来执行 vagrant up得到的都是一模一样的系统。4. 踩坑记录我遇到过的典型问题与排查方法4.1 端口冲突导致启动失败这是最常见的错误之一。当你启动多个不同的 Vagrant 项目或者宿主机上已经有程序占用同一端口时Vagrant 会直接报错常见提示类似 A port forwarding rule already exists for this VM 或者 Address already in use。排查方法比较简单先确认宿主机上的端口占用情况。macOS/Linux 用 lsof -i :端口号Windows 用 netstat -ano | findstr 端口号。找到占用端口的进程然后决定是杀掉它还是改掉配置里的 host 端口。这里有个容易忽略的坑Vagrant 默认会自动处理一部分“冲突”情况——如果 host 端口被占用Vagrant 可能会随机分配一个新的可用端口但这样会导致你原有的访问链接失效。为了避免这种隐式变更建议在配置里显式写清楚 port collision detection 相关的设置或者直接用 private_network 模式绕开端口映射。4.2 VirtualBox 版本与 Vagrant 插件不兼容自从 VirtualBox 7.0 发布之后早期版本 Vagrant 的某些插件出现兼容性问题的情况比以前更频繁。如果你遇到类似 Unknown configuration section vbguest 或者加载插件报错大概率是版本不匹配。解决思路是保持 Vagrant 和 VirtualBox 都比较新优先使用官方最新稳定版。原则上不要为了“稳定”特意去用老版本的 Vagrant因为 VirtualBox 每次大版本升级都可能改动底层接口老版本的 Vagrant 往往无法正确解析新版本的虚拟机元数据。另外很多教程会推荐安装 vagrant-vbguest 插件来自动更新 Guest Additions。这个插件确实能解决“VirtualBox 升级后同步文件夹失效”的问题但它也可能引入新的兼容问题。在团队里统一版本是更好的做法大家在同一个 Vagrant 版本、同一个 VirtualBox 版本上协作环境才真正一致。4.3 同步文件夹速度慢到怀疑人生前面提到过默认的 vboxsf 模式在大量小文件读写的场景下性能不佳。如果你跑的是 Node.js 项目node_modules 里动辄几万个小文件用 vboxsf 同步会慢到你怀疑电脑是不是卡死了。解决思路有两个一是为这类目录单独设置同步类型直接使用 rsync把资源消耗大的文件单向传给虚拟机二是更简单粗暴的做法——在虚拟机里安装依赖而不是在宿主机上安装。比如 Node 项目在代码目录下忽略 node_modules然后在虚拟机里执行 npm install。这样同步的只有源代码运行依赖直接跑在虚拟机内部速度和稳定性都远高于跨虚拟机的文件共享。如果你一定要用 vboxsf 同步确保虚拟机内已经安装并且加载了正确版本的 Guest Additions很多看似玄学的卡顿问题最后都指向 Guest Additions 版本不匹配。4.4 SSH 连接缓慢或者频繁超时vagrant ssh 登录后敲命令总是卡一两秒才响应这在某些 Windows 宿主机上特别明显。Vagrant 的 SSH 配置默认会尝试 UseDNS 反向解析导致登录时等待一段时间。一个有效但不太优雅的解决方法是在 Vagrantfile 里加一段配置让 SSH 连接保持活跃config.ssh.forward_agent true另一个老手才知道的做法是在 vagrant ssh 之前先手动修改虚拟机内的 /etc/ssh/sshd_config把 UseDNS 改成 no同时关闭 GSSAPIAuthentication。修改后重启 sshd 服务。这样登录速度会快非常明显。如果你用 rsync 同步它也是通过 SSH 执行的这个优化同样有效。4.5 磁盘空间被虚拟机镜像撑爆box 文件本身占用几个 GB虚拟机的虚拟磁盘又占几个 GB如果你同时维护好几个环境宿主机的磁盘空间会迅速告急。常用的整理命令是vagrant box list # 查看本机缓存了哪些 box vagrant box remove name # 删除不用的 box注意删除 box 之前要确认没有任何虚拟机还在使用它否则已经创建的虚拟机也无法正常启动。另外Vagrant 创建的虚拟机磁盘文件默认放在 VirtualBox 的默认虚拟机目录通常和 box 缓存目录不在同一个位置遇到磁盘告急时要检查这两处。长时间使用之后虚拟机内部的磁盘也会膨胀即使你在里面删除了大量文件虚拟磁盘文件也不一定会自动收缩。如果需要清理可以进入虚拟机执行 fstrim针对 SSD 宿主机和虚拟磁盘类型或者用 zerofree 把空闲空间置零然后再执行 Vagrant 配置里的压缩步骤。这个过程比较费时间不建议频繁操作但对磁盘紧张的机器意义很大。5. 进阶玩法多机编排与团队协作5.1 多机编排用一份配置拉起整套环境有些项目的开发环境不是单台机器而是由 Web 服务器、数据库服务器、缓存服务器组成的基本架构。Vagrant 支持在一个 Vagrantfile 里定义多台虚拟机这个特性叫 multi-machine。Vagrant.configure(2) do |config| config.vm.box generic/ubuntu2204 config.vm.define web do |web| web.vm.hostname web-server web.vm.network private_network, ip: 192.168.56.11 web.vm.provision shell, inline: apt-get install -y nginx end config.vm.define db do |db| db.vm.hostname db-server db.vm.network private_network, ip: 192.168.56.12 db.vm.provision shell, inline: apt-get install -y mysql-server end end执行 vagrant up 时Vagrant 会按顺序启动这两台虚拟机vagrant ssh web 和 vagrant ssh db 分别登录到对应机器。web 机器可以通过 192.168.56.12 访问数据库机器这就模拟出了一个最基本的集群拓扑而不用在一台机器上同时跑两个互相依赖的服务。多机配置里有一个注意事项每台机器的 provision 默认也是只在首次创建时执行。如果你修改了其中一台的配置想要重新执行需要指定机器名vagrant provision web5.2 把 Vagrantfile 纳入版本库的团队规范当你把 Vagrantfile 提交到 Git 仓库团队协作就进入了新阶段。新成员加入项目时不再需要看几十页的环境搭建文档只需要git clone 项目仓库 cd 项目目录 vagrant up这是整个 Vagrant 工作流里最让人舒畅的部分。但要把这套流程跑顺有几个规范需要提前约定。一是 box 版本要锁定。在 Vagrantfile 里尽量指定具体的 box 版本比如 config.vm.box_version 1.2.3避免不同成员因为拉取到不同版本的 box 而出现环境漂移。二是不要提交 .vagrant 目录。这个目录是 Vagrant 运行时的状态目录里面记录了虚拟机的 ID、SSH 配置等本机相关信息。它本来就有一个默认的 .gitignore 规则但你应该在 .gitignore 里主动加上 .vagrant防止有人在没有全局 ignore 规则的环境下把它提交上去。三是 provision 脚本要尽量讲清依赖。如果底层 box 更新了原来能跑通的 provision 脚本可能在新系统上失败。bash 脚本本身不负责解释“为什么这么装”所以在脚本开头写清楚依赖理由对后来维护的人极其重要。5.3 在宿主机上用 IDE 打开虚拟机里的代码很多开发者习惯了在宿主机上用 IDE 编辑代码但代码的实际运行环境在虚拟机里。前面提到的同步文件夹让这两者可以共存——你在宿主机编辑代码实时同步到虚拟机虚拟机的运行结果直接可见。如果你的项目对同步性能不敏感比如 PHP、Python 这类脚本语言项目vboxsf 完全够用。遇到性能问题再考虑调优不要一开始就在同步方案上过度设计。如果同步确实无法满足性能要求还可以考虑另一种流程直接在虚拟机里装 IDE 或者用 VS Code 的 Remote-SSH 插件连接虚拟机。这种方式彻底绕开了文件同步的问题代码和运行环境在同一台机器上性能完全没问题。缺点是需要习惯远程开发的工作模式对网络和本机内存的要求也更高。5.4 给初学者的几条项目实践建议根据我的实际经验刚开始用 Vagrant 的时候容易踩进几个思维误区。第一不要把 Vagrant 当成生产工具。Vagrant 的目标是让开发环境保持一致它默认的虚拟机资源配额不高网络配置也不适合生产环境。生产环境请交给容器编排平台或者云服务不要试图在生产服务器上执行 vagrant up。第二不要在环境内做临时性的手工修改。今天你为了调试某个问题手动在虚拟机里改了配置这个修改不会出现在 Vagrantfile 里也不会被记录下来。下次有人重新创建环境这个修复就无声消失了。正确做法是把每一次手工修改反推到 provision 脚本里让环境的所有变更都有据可查。第三定期清理不用的环境。开发一段时间后宿主机上可能残留着四五台关机状态的虚拟机。定期执行 vagrant global-status 查看所有设备的状态对确定不再使用的执行 vagrant destroy能释放大量磁盘空间也能避免 VirtualBox 列表里堆满了僵尸机器。6. 个人体会与后续扩展方向在我负责的多个模拟项目里Vagrant VirtualBox 组合带来的实际收益是肉眼可见的。最明显的一个变化是新成员从“照文档装环境”变成了“跑一条命令”出错率大幅下降另一个变化是模拟环境可以被反复摧毁和重建我可以大胆在虚拟机里做破坏性实验不用担心把宿主机搞乱。这种“随便造、随时复原”的安全感是手动维护环境完全给不了的。如果你想继续深入有几个方向值得投入时间。一是用 Ansible 替代简单的 shell provision把配置管理做得更规范和可复用二是尝试用 Vagrant 管理 Kubernetes 本地集群很多实验性质的多节点集群方案就是建立在 Vagrant 之上的三是了解容器和虚拟机的边界随着 Docker 的普及有些场景用容器确实更轻量但如果你想完整模拟一台服务器的全部细节虚拟机依然不可替代。最后分享一个小技巧给一个开发环境配置好之后记得做一次快照。Vagrant 支持快照功能命令是 vagrant snapshot save 环境名。快照的存在意味着你可以在实验前备份一个干净状态实验失败后执行 vagrant snapshot restore 一键恢复。我现在的标准工作流就是第一次 vagrant up 完成并验证环境可用后立刻保存一个快照之后所有的环境折腾都在快照之上进行。这个习惯帮我省下过无数次“环境搞坏了只能销毁重来”的时间。