当前位置: 首页 > news >正文

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

前言

文章摘要

本文是一篇全面的 Vagrant 入门与实践指南,通过一个真实的 Web 应用Terramino演示了 Vagrant 的核心功能。主要内容包括:

  1. Vagrant 解决的问题:解决传统开发环境中的“在我电脑上能跑”问题,通过“环境即代码”实现环境一致性、可移植性和隔离性。

  2. 安装与基础使用:详细介绍了 Vagrant 和 VirtualBox 的安装步骤,以及如何通过vagrant initvagrant upvagrant ssh等命令创建和管理第一个虚拟机环境。

  3. 自动化配置(Provisioning):使用 Shell 脚本在虚拟机启动时自动安装 Docker、克隆代码库并启动应用,实现环境的一键部署。

  4. 宿主机与虚拟机互联:通过端口转发和同步文件夹功能,实现宿主机直接访问虚拟机服务,并支持宿主机编码、虚拟机运行的开发模式。

  5. 多机环境模拟微服务架构:在一个 Vagrantfile 中定义多台虚拟机(redis、backend、frontend),模拟生产环境的微服务架构,并演示了服务故障模拟与恢复。

  6. 核心价值:Vagrant 通过 Vagrantfile、Box、Provisioning、端口转发、同步文件夹和多机环境等功能,为团队提供了可重复、可共享、可销毁的开发环境解决方案。

核心工作流vagrant init→ 编写 Vagrantfile →vagrant upvagrant 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 安装 VirtualBox

Vagrant 默认使用 VirtualBox 作为虚拟化提供商。前往 VirtualBox 官网 下载并安装7.1.4 或更新版本

macOS Apple Silicon 用户注意:如果遇到虚拟机启动问题,可能需要执行以下命令取消一个 VirtualBox 全局设置:

$ VBoxManage setextradata global"VBoxInternal/Devices/pcbios/0/Config/DebugLevel"

2.2 安装 Vagrant

HashiCorp 将 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 A`Vagrantfile`has been placedinthis directory. You are now ready to`vagrant up`your first virtual environment!

这里我们指定了一个名为hashicorp-education/ubuntu-24-04box(即虚拟机基础镜像)。Vagrant 会从 HCP Vagrant Registry 获取这个镜像。

执行完后,目录下会生成一个Vagrantfile

Vagrant.configure("2")do|config|config.vm.box="hashicorp-education/ubuntu-24-04"config.vm.box_version="0.1.0"end

这个文件就是整个环境的核心配置文件。一定要把它提交到 Git,这样团队成员都能复用同样的环境。

什么是 Box?Box 是 Vagrant 的基础镜像,相当于虚拟机的“初始状态”。Vagrant 从 Box 克隆出虚拟机,而不会修改 Box 本身,所以多个项目可以共用同一个 Box。

3.2 启动虚拟机

执行vagrant up启动环境:

$ vagrant up==>default: Box'hashicorp-education/ubuntu-24-04'could 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

退出虚拟机:

$logout

3.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 Docker's official GPG keyinstall-m0755-d/etc/apt/keyringscurl-fsSLhttps://download.docker.com/linux/ubuntu/gpg|gpg--dearmor-o/etc/apt/keyrings/docker.gpgchmoda+r /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-release&&echo"$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-terramino<<'EOF' #!/bin/bash cd /home/vagrant/terramino-go docker compose down docker compose build --no-cache docker compose up -d EOFchmod+x /usr/local/bin/reload-terramino# Add aliasesecho'alias play="docker compose -f /home/vagrant/terramino-go/docker-compose.yml exec -it backend ./terramino-cli"'>>/home/vagrant/.bashrcecho'alias reload="sudo /usr/local/bin/reload-terramino"'>>/home/vagrant/.bashrcecho"source /home/vagrant/.bashrc">>/home/vagrant/.bash_profile

然后让脚本可执行:

$chmod+x install-dependencies.sh

4.2 更新 Vagrantfile

在 Vagrantfile 中添加 provisioning 配置:

Vagrant.configure("2")do|config|config.vm.box="hashicorp-education/ubuntu-24-04"config.vm.box_version="0.1.0"# Install Docker and dependenciesconfig.vm.provision"shell",name:"install-dependencies",path:"install-dependencies.sh"# Start Terraminoconfig.vm.provision"shell",name:"start-terramino",inline:<<-SHELLcd /home/vagrant/terramino-go docker compose up -dSHELL# Reload Terramino (only when explicitly invoked)config.vm.provision"shell",name:"reload-terramino",run:"never",inline:<<-SHELL/usr/local/bin/reload-terraminoSHELLend

这里定义了三个 provisioner:

  • install-dependencies:安装 Docker 和依赖
  • start-terramino:启动 Terramino 应用
  • reload-terramino:设置run: "never",只有手动指定时才会执行

4.3 执行 Provisioning

重新创建虚拟机并执行所有 Provisioning 脚本:

$ vagrant up--provision

如果虚拟机已在运行,可以用vagrant provision重新执行:

$ vagrant provision

4.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.network"forwarded_port",guest:8080,host:8080config.vm.network"forwarded_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--provision

5.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 拆分为三个服务,分别运行在三台独立的虚拟机上:

服务作用端口IP
redis存储游戏高分6379192.168.56.10
backend游戏逻辑和 API8080192.168.56.11
frontendWeb 界面8081192.168.56.12

6.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.gpgchmoda+r /etc/apt/keyrings/docker.gpgecho"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu$(./etc/os-release&&echo"$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
$chmod+x common-dependencies.sh

6.3 编写多机 Vagrantfile

# Service configuration referenceSERVICES={'redis'=>{ip:'192.168.56.10',ports:{6379=>6379}},'backend'=>{ip:'192.168.56.11',ports:{8080=>8080}},'frontend'=>{ip:'192.168.56.12',ports:{8081=>8081}}}Vagrant.configure("2")do|config|# Common configurationconfig.vm.box="hashicorp-education/ubuntu-24-04"config.vm.box_version="0.1.0"# Common provisioning script for all VMsconfig.vm.provision"shell",name:"common",path:"common-dependencies.sh"# Redis Serverconfig.vm.define"redis"do|redis|redis.vm.hostname="redis"redis.vm.network"private_network",ip:SERVICES['redis'][:ip]redis.vm.network"forwarded_port",guest:6379,host:6379redis.vm.synced_folder"./redis/terramino-go","/home/vagrant/terramino-go",create:trueredis.vm.provision"shell",name:"start-redis",inline:<<-SHELLcd /home/vagrant/terramino-go docker compose up -d redisSHELLend# Backend Serverconfig.vm.define"backend"do|backend|backend.vm.hostname="backend"backend.vm.network"private_network",ip:SERVICES['backend'][:ip]backend.vm.network"forwarded_port",guest:8080,host:8080backend.vm.synced_folder"./backend/terramino-go","/home/vagrant/terramino-go",create:truebackend.vm.provision"shell",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_HOST=redis.local \ -e REDIS_PORT=6379 \ -e TERRAMINO_PORT=8080 \ --add-host redis.local:${REDIS_IP} \ backendSHELLend# Frontend Serverconfig.vm.define"frontend"do|frontend|frontend.vm.hostname="frontend"frontend.vm.network"private_network",ip:SERVICES['frontend'][:ip]frontend.vm.network"forwarded_port",guest:8081,host:8081frontend.vm.synced_folder"./frontend/terramino-go","/home/vagrant/terramino-go",create:truefrontend.vm.provision"shell",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} \ frontendSHELLendend

6.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用代码定义环境,可提交 Git
Box基础镜像复用,加速环境创建
Provisioning自动化安装软件和配置
端口转发从宿主机访问虚拟机服务
同步文件夹宿主机编码,虚拟机运行
多机环境模拟微服务架构,测试容错

核心工作流

vagrant init → 编写 Vagrantfile → vagrant up → vagrant ssh → 开发 → vagrant destroy

下一步

  • 在 HCP Vagrant Registry 发现更多 box
  • 探索 Vagrant 插件生态
  • 学习与 Ansible、Chef、Puppet 等配置管理工具集成

记住:Vagrantfile 一定要提交到 Git。从此以后,新成员加入项目只需要两步:git clonevagrant up

http://www.jsqmd.com/news/1067132/

相关文章:

  • 终极指南:如何用OpenCore Legacy Patcher让老旧Mac重获新生,安装最新macOS系统
  • 【仅剩最后200份】SITS 2026官方Pipeline Design Kit(含DSL编译器+可观测性探针+合规性校验器)深度解读
  • 3000米浮空智联·200平方公里演训全域虚实透明监测与自愈通信一体化系统
  • 半导体投资的“隐形命门”:深挖六大核心黑马赛道
  • 医疗机构废水需要上在线监测吗?
  • 架构鸟瞰不是PPT,而是可执行的系统解剖术
  • 工程项目管理系统有哪些,知名全国工程项目管理系统推荐!
  • 卫星通信导论学习
  • NET 8 Web开发入门(七):安全门禁——JWT 身份验证与授权实战
  • 显存不够用,vLLM 在 AMD 卡上的 PagedAttention 调优实战
  • AI写作辅助平台的使用规范:从文献整理到成稿的合规流程解析?
  • 抄写员的消亡与转录的贬值
  • 【无人机通信】无人机卫星链路混合波束成形的 K 因子自适应 AN 功率分配matlab实现
  • 2026地图服务商AI时空大数据能力榜:商业选址视角
  • 3分钟掌握KH Coder:免费专业的文本挖掘工具终极指南
  • 告别网盘限速:ctfileGet让你的下载速度飞起来
  • 一个实验搞懂 Docker 和 K8s 怎么配合
  • Chroma GUI - Chroma 向量数据库可视化管理工具
  • AMD 显卡驱动更新指南,确保 Strix Halo 大模型部署不掉链子
  • 混合检索深度解析:大模型应用中的召回革命与精度突围
  • 基于JAX的函数式时序预测:Chronax库的核心原理与实践指南
  • 今天很开心
  • 传统电话报备 vs 智能手环监管,电力安全差距一目了然
  • 独立站品牌出海,做出高级的品牌
  • 电力系统的“安全卫士”是怎样炼成的?答案藏在这个实验台里
  • 深度技术揭秘:OpenCore Legacy Patcher如何让老Mac突破硬件限制运行最新macOS
  • 3步完成专业Windows部署:MediaCreationTool.bat批处理工具深度解析与实战指南
  • 静态库和动态库的开发使用
  • AI项目经理/产品经理薪资狂飙50%?掌握这技术,2026年职场无人能敌!
  • 为什么顶尖实验室已弃用手工特征?2026奇点大会公布的“特征熵阈值”动态判据,让AutoFE真正落地产线