告别“在我电脑上能跑”——用 Vagrant 一键搭建可复现的开发环境

发布时间:2026/6/23 11:14:39

告别“在我电脑上能跑”——用 Vagrant 一键搭建可复现的开发环境 前言文章摘要本文是一篇全面的 Vagrant 入门与实践指南通过一个真实的 Web 应用Terramino演示了 Vagrant 的核心功能。主要内容包括Vagrant 解决的问题解决传统开发环境中的“在我电脑上能跑”问题通过“环境即代码”实现环境一致性、可移植性和隔离性。安装与基础使用详细介绍了 Vagrant 和 VirtualBox 的安装步骤以及如何通过vagrant init、vagrant up、vagrant ssh等命令创建和管理第一个虚拟机环境。自动化配置Provisioning使用 Shell 脚本在虚拟机启动时自动安装 Docker、克隆代码库并启动应用实现环境的一键部署。宿主机与虚拟机互联通过端口转发和同步文件夹功能实现宿主机直接访问虚拟机服务并支持宿主机编码、虚拟机运行的开发模式。多机环境模拟微服务架构在一个 Vagrantfile 中定义多台虚拟机redis、backend、frontend模拟生产环境的微服务架构并演示了服务故障模拟与恢复。核心价值Vagrant 通过 Vagrantfile、Box、Provisioning、端口转发、同步文件夹和多机环境等功能为团队提供了可重复、可共享、可销毁的开发环境解决方案。核心工作流vagrant init→ 编写 Vagrantfile →vagrant up→vagrant ssh→ 开发 →vagrant destroy你有没有遇到过这样的场景项目在你自己电脑上跑得好好的一提交代码同事那边就各种报错或者新同事入职光是搭建开发环境就折腾了两三天这就是经典的“在我电脑上能跑”问题。而 Vagrant 的出现正是为了终结这个噩梦。Vagrant 是一个用于在单一工作流中构建和管理虚拟机环境的工具。它通过简单易用的工作流和自动化能力大幅缩短开发环境搭建时间提高环境一致性。简单来说Vagrant 就是用代码来定义、管理和销毁开发环境。你把环境配置写在一个文件里团队成员只需要执行一条命令就能得到一模一样的开发环境。本文将以一个真实的 Web 应用Terramino为例带你从零开始一步步掌握 Vagrant 的核心用法。所有代码均可直接运行建议你跟着操作一遍。一、Vagrant 解决了什么问题1.1 传统开发环境的痛点在传统的开发流程中每个开发者需要手动在自己的机器上安装各种软件数据库、缓存、编程语言运行时、Web 服务器……这个过程不仅耗时而且极易出错配置漂移开发 A 用的是 MySQL 5.7开发 B 用的是 MySQL 8.0同样的代码可能表现不同。依赖冲突项目 A 需要 Python 3.8项目 B 需要 Python 3.11手动切换版本非常麻烦。环境不可复现新成员入职、旧项目维护环境搭建成本极高。1.2 Vagrant 的解决方案Vagrant 通过“环境即代码”的方式解决上述问题一致性所有团队成员使用相同的 Vagrantfile得到完全一致的环境。可移植性Vagrantfile 可以提交到 Git任何人都可以一键复现。隔离性每个项目的环境相互隔离互不干扰。可销毁性环境用完即焚不留任何残留文件。Vagrant 支持多种虚拟化提供商Provider包括 VirtualBox、VMware、Docker 等你可以根据需求灵活选择。二、安装 Vagrant在开始之前你需要先安装 Vagrant 和虚拟化软件。2.1 安装 VirtualBoxVagrant 默认使用 VirtualBox 作为虚拟化提供商。前往 VirtualBox 官网 下载并安装7.1.4 或更新版本。macOS Apple Silicon 用户注意如果遇到虚拟机启动问题可能需要执行以下命令取消一个 VirtualBox 全局设置$ VBoxManage setextradata globalVBoxInternal/Devices/pcbios/0/Config/DebugLevel2.2 安装 VagrantHashiCorp 将 Vagrant 作为一个二进制包分发。根据你的操作系统选择对应的安装方式macOS / Linux下载对应平台的压缩包解压后将vagrant二进制文件移动到 PATH 中的某个目录例如/usr/local/bin$mv~/Downloads/vagrant /usr/local/bin/Windows下载安装包后按向导安装即可安装程序会自动配置 PATH。2.3 验证安装打开终端执行以下命令确认安装成功$ vagrant--helpUsage: vagrant[options]command[args]...如果看到命令列表说明安装成功了。三、第一个 Vagrant 环境3.1 初始化项目创建一个目录并初始化 Vagrant 环境$mkdirlearn-vagrant-get-started $cdlearn-vagrant-get-started $ vagrant init hashicorp-education/ubuntu-24-04 --box-version0.1.0 AVagrantfilehas been placedinthis directory. You are now ready tovagrant upyour first virtual environment!这里我们指定了一个名为hashicorp-education/ubuntu-24-04的box即虚拟机基础镜像。Vagrant 会从 HCP Vagrant Registry 获取这个镜像。执行完后目录下会生成一个VagrantfileVagrant.configure(2)do|config|config.vm.boxhashicorp-education/ubuntu-24-04config.vm.box_version0.1.0end这个文件就是整个环境的核心配置文件。一定要把它提交到 Git这样团队成员都能复用同样的环境。什么是 BoxBox 是 Vagrant 的基础镜像相当于虚拟机的“初始状态”。Vagrant 从 Box 克隆出虚拟机而不会修改 Box 本身所以多个项目可以共用同一个 Box。3.2 启动虚拟机执行vagrant up启动环境$ vagrant updefault: Boxhashicorp-education/ubuntu-24-04could not be found. Attempting tofindand install... default: Box Provider: virtualbox...default: Machine booted and ready!Vagrant 会自动下载 Box、创建虚拟机并完成初始化。第一次启动可能需要几分钟之后就会快很多。3.3 连接虚拟机使用 SSH 连接到虚拟机内部$ vagrantsshWelcome to Ubuntu24.04.1 LTS(GNU/Linux6.8.0-51-generic aarch64)进去后可以执行任何 Linux 命令$ lsb_release-aDistributor ID: Ubuntu Description: Ubuntu24.04.1 LTS Release:24.04退出虚拟机$logout3.4 生命周期管理Vagrant 提供了一套完整的生命周期管理命令命令作用vagrant up启动虚拟机首次会创建vagrant sshSSH 连接到虚拟机vagrant suspend挂起虚拟机保存内存状态vagrant resume恢复被挂起的虚拟机vagrant halt优雅关机vagrant destroy销毁虚拟机删除所有数据vagrant box remove删除已下载的 Box 镜像注意vagrant destroy会删除虚拟机但不会删除 Box 文件。Box 可以被其他项目复用。四、Provisioning自动化配置环境手动在虚拟机里安装软件太麻烦了。Vagrant 的Provisioning预配置功能可以在虚拟机启动时自动执行脚本完成环境初始化。4.1 创建安装脚本我们来为 Terramino 应用安装 Docker 和依赖。创建一个install-dependencies.sh文件#!/bin/bash# Install dependencies for Terramino demo app# Update package listapt-getupdate# Install required packagesapt-getinstall-yca-certificatescurlgnupggit# Add Dockers official GPG keyinstall-m0755-d/etc/apt/keyringscurl-fsSLhttps://download.docker.com/linux/ubuntu/gpg|gpg--dearmor-o/etc/apt/keyrings/docker.gpgchmodar /etc/apt/keyrings/docker.gpg# Add Docker repositoryecho\deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(./etc/os-releaseecho$VERSION_CODENAME) stable|\tee/etc/apt/sources.list.d/docker.list/dev/null# Install Docker packagesapt-getupdateapt-getinstall-ydocker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# Add vagrant user to docker groupusermod-aGdockervagrant# Clone Terramino repositoryif[!-d/home/vagrant/terramino-go/.git];thencd/home/vagrantrm-rfterramino-gogitclone https://github.com/hashicorp-education/terramino-go.gitcdterramino-gogitcheckout containerizedfi# Create reload scriptcat/usr/local/bin/reload-terraminoEOF #!/bin/bash cd /home/vagrant/terramino-go docker compose down docker compose build --no-cache docker compose up -d EOFchmodx /usr/local/bin/reload-terramino# Add aliasesechoalias playdocker compose -f /home/vagrant/terramino-go/docker-compose.yml exec -it backend ./terramino-cli/home/vagrant/.bashrcechoalias reloadsudo /usr/local/bin/reload-terramino/home/vagrant/.bashrcechosource /home/vagrant/.bashrc/home/vagrant/.bash_profile然后让脚本可执行$chmodx install-dependencies.sh4.2 更新 Vagrantfile在 Vagrantfile 中添加 provisioning 配置Vagrant.configure(2)do|config|config.vm.boxhashicorp-education/ubuntu-24-04config.vm.box_version0.1.0# Install Docker and dependenciesconfig.vm.provisionshell,name:install-dependencies,path:install-dependencies.sh# Start Terraminoconfig.vm.provisionshell,name:start-terramino,inline:-SHELLcd /home/vagrant/terramino-go docker compose up -dSHELL# Reload Terramino (only when explicitly invoked)config.vm.provisionshell,name:reload-terramino,run:never,inline:-SHELL/usr/local/bin/reload-terraminoSHELLend这里定义了三个 provisionerinstall-dependencies安装 Docker 和依赖start-terramino启动 Terramino 应用reload-terramino设置run: never只有手动指定时才会执行4.3 执行 Provisioning重新创建虚拟机并执行所有 Provisioning 脚本$ vagrant up--provision如果虚拟机已在运行可以用vagrant provision重新执行$ vagrant provision4.4 测试应用SSH 进入虚拟机测试 Terramino 是否正常运行$ vagrantssh$curllocalhost:8080 Terramino – HashiCorp Demo App https://developer.hashicorp.com/运行游戏$ play Terramino CLI Controls: ← →:Move left/right ↑:Rotate ↓:Soft drop Space:Hard drop q:Quit Press Enter to start...五、共享资源宿主机与虚拟机互联5.1 端口转发虚拟机内部的服务默认只能在虚拟机内部访问。通过端口转发我们可以从宿主机直接访问虚拟机里的服务。在 Vagrantfile 中添加端口映射# Forward ports for Terramino (8081 for frontend, 8080 for backend)config.vm.networkforwarded_port,guest:8080,host:8080config.vm.networkforwarded_port,guest:8081,host:8081重新加载虚拟机使配置生效$ vagrant reload--provision现在在宿主机浏览器中访问http://localhost:8081就能直接玩 Terramino 了。5.2 同步文件夹更强大的功能是同步文件夹synced folders——宿主机和虚拟机之间的目录双向同步。你在宿主机用 IDE 写代码虚拟机里自动同步更新。在 Vagrantfile 中添加# Sync the terramino-go directoryconfig.vm.synced_folder./terramino-go,/home/vagrant/terramino-go,create:true重新加载$ vagrant reload--provision5.3 验证同步现在在宿主机上修改terramino-go/main.go添加一个健康检查接口http.HandleFunc(/health,func(w http.ResponseWriter,r*http.Request){w.Write([]byte(OK))})然后在宿主机上验证$curllocalhost:8080/health OK修改实时生效这就是同步文件夹的威力——宿主机编码虚拟机运行。如果销毁虚拟机vagrant destroy本地目录不会被删除它是数据的“源”。六、多机环境模拟微服务架构真实的生产环境往往由多个服务组成。Vagrant 的多机Multi-Machine功能允许你在一个 Vagrantfile 中定义多台虚拟机模拟微服务架构。6.1 架构设计我们将 Terramino 拆分为三个服务分别运行在三台独立的虚拟机上服务作用端口IPredis存储游戏高分6379192.168.56.10backend游戏逻辑和 API8080192.168.56.11frontendWeb 界面8081192.168.56.126.2 创建公共依赖脚本先创建一个common-dependencies.sh在所有虚拟机上安装 Docker#!/bin/bash# Install Docker and clone repo (common dependencies for multi-machine tutorial)apt-getupdateapt-getinstall-yca-certificatescurlgnupggitavahi-daemon libnss-mdnsinstall-m0755-d/etc/apt/keyringscurl-fsSLhttps://download.docker.com/linux/ubuntu/gpg|gpg--dearmor-o/etc/apt/keyrings/docker.gpgchmodar /etc/apt/keyrings/docker.gpgechodeb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu$(./etc/os-releaseecho$VERSION_CODENAME)stable|tee/etc/apt/sources.list.d/docker.list/dev/nullapt-getupdateapt-getinstall-ydocker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginusermod-aGdockervagrant# Clone repoif[!-d/home/vagrant/terramino-go/.git];thengitclone https://github.com/hashicorp-education/terramino-go.git /home/vagrant/terramino-gocd/home/vagrant/terramino-gogitcheckout containerizedfi$chmodx common-dependencies.sh6.3 编写多机 Vagrantfile# Service configuration referenceSERVICES{redis{ip:192.168.56.10,ports:{63796379}},backend{ip:192.168.56.11,ports:{80808080}},frontend{ip:192.168.56.12,ports:{80818081}}}Vagrant.configure(2)do|config|# Common configurationconfig.vm.boxhashicorp-education/ubuntu-24-04config.vm.box_version0.1.0# Common provisioning script for all VMsconfig.vm.provisionshell,name:common,path:common-dependencies.sh# Redis Serverconfig.vm.defineredisdo|redis|redis.vm.hostnameredisredis.vm.networkprivate_network,ip:SERVICES[redis][:ip]redis.vm.networkforwarded_port,guest:6379,host:6379redis.vm.synced_folder./redis/terramino-go,/home/vagrant/terramino-go,create:trueredis.vm.provisionshell,name:start-redis,inline:-SHELLcd /home/vagrant/terramino-go docker compose up -d redisSHELLend# Backend Serverconfig.vm.definebackenddo|backend|backend.vm.hostnamebackendbackend.vm.networkprivate_network,ip:SERVICES[backend][:ip]backend.vm.networkforwarded_port,guest:8080,host:8080backend.vm.synced_folder./backend/terramino-go,/home/vagrant/terramino-go,create:truebackend.vm.provisionshell,name:start-backend,inline:-SHELLcd /home/vagrant/terramino-go # Get Redis IP dynamically for i in {1..30}; do if REDIS_IP$(getent hosts redis.local | awk {print $1}); then break fi echo Waiting for redis.local to be resolvable... sleep 2 done docker build -f Dockerfile.backend -t backend . docker run -d -p 8080:8080 \ -e REDIS_HOSTredis.local \ -e REDIS_PORT6379 \ -e TERRAMINO_PORT8080 \ --add-host redis.local:${REDIS_IP} \ backendSHELLend# Frontend Serverconfig.vm.definefrontenddo|frontend|frontend.vm.hostnamefrontendfrontend.vm.networkprivate_network,ip:SERVICES[frontend][:ip]frontend.vm.networkforwarded_port,guest:8081,host:8081frontend.vm.synced_folder./frontend/terramino-go,/home/vagrant/terramino-go,create:truefrontend.vm.provisionshell,name:start-frontend,inline:-SHELLcd /home/vagrant/terramino-go # Update nginx.conf to use backend hostname sed -i s#proxy_pass http://backend:8080#proxy_pass http://backend.local:8080# nginx.conf # Get backend IP dynamically for i in {1..30}; do if BACKEND_IP$(getent hosts backend.local | awk {print $1}); then break fi echo Waiting for backend.local to be resolvable... sleep 2 done docker build -f Dockerfile.frontend -t frontend . docker run -d -p 8081:8081 \ --add-host backend.local:${BACKEND_IP} \ frontendSHELLendend6.4 启动多机环境启动所有虚拟机$ vagrant up也可以单独启动某台$ vagrant up redis $ vagrant up backend $ vagrant up frontend查看状态$ vagrant status Current machine states: redis running(virtualbox)backend running(virtualbox)frontend running(virtualbox)6.5 模拟服务故障多机环境的另一个价值是模拟生产故障。挂起 backend 服务$ vagrantsuspendbackend刷新浏览器http://localhost:8081高分区域会显示SVC_DOWN说明前端检测到了后端不可用。恢复 backend$ vagrant resume backend刷新页面功能恢复正常。这种能力对于测试系统的容错性非常有价值。七、总结通过本文的实践你应该已经掌握了 Vagrant 的核心能力功能解决的问题Vagrantfile用代码定义环境可提交 GitBox基础镜像复用加速环境创建Provisioning自动化安装软件和配置端口转发从宿主机访问虚拟机服务同步文件夹宿主机编码虚拟机运行多机环境模拟微服务架构测试容错核心工作流vagrant init → 编写 Vagrantfile → vagrant up → vagrant ssh → 开发 → vagrant destroy下一步在 HCP Vagrant Registry 发现更多 box探索 Vagrant 插件生态学习与 Ansible、Chef、Puppet 等配置管理工具集成记住Vagrantfile 一定要提交到 Git。从此以后新成员加入项目只需要两步git clone和vagrant up。

相关新闻