看到标题里那个&&了吗?我第一次建项目目录,老老实实起名CentOS8&&Ubuntu22&&Ubuntu24,然后在 bash 里执行vagrant up,整个终端直接把我干沉默了——&&在 shell 里是连接符,目录名里有这玩意儿,等于把命令拆成三截,没报错纯属当时运气好。所以先给你们一个忠告:项目目录能多简单就多简单,别带&,别带空格,最好全小写。
这次折腾的目标很明确:一台工作站上,用一份 Vagrantfile 同时拉起 CentOS 8、Ubuntu 22.04 和 Ubuntu 24.04 三个虚拟机,用于本机跑联调测试和三套系统环境验证。整个过程不算顺利,box 下载、SSH 超时、CentOS 8 停服之后仓库失效、Ubuntu 24 和 VirtualBox 版本兼容性……全部踩了一遍。这篇文章就是把这些坑按时间线记下来,附带排查思路和最终能跑通的配置,适合准备用 Vagrant 管理多台虚拟机、或者只是想给本机装几套 Linux 做实验的人参考。
1. 项目概述:为什么用 Vagrant 管多虚拟机
1.1 我的使用场景
我在本地工作站上要维护三套环境:CentOS 8 是模拟老项目的生产服务器,Ubuntu 22.04 是常用开发环境,Ubuntu 24.04 则是为了验证新特性顺手加的。如果每套都用 VirtualBox 手动新建、手动装系统、手动配网络,三台下来至少折腾半天,而且每次重建都得重复劳动。Vagrant 的价值就在这里:把系统镜像、硬件配置、网络设置、初始化脚本全部写进 Vagrantfile,一条vagrant up全部搞定,重建环境也只是一条命令的事。
很多朋友对 Vagrant 的理解停留在"它能启动一个虚拟机",但真正的核心其实是"多机编排"。它的config.vm.define语法支持在一个文件里定义多个 VM,分别指定不同的 box、内存、网络、启动顺序和初始化脚本。这意味着你本地可以维护一个接近生产结构的多机环境,而不用买服务器。
1.2 为什么是这三个系统
选这三个发行版不是拍脑袋。CentOS 8 代表了 RHEL 系的老传统,虽然官方已经停服,但存量机器和旧项目基本都是它的影子;Ubuntu 22.04 和 24.04 分别对应两代 LTS,软件源、内核、网络管理方式都有明显差异。把这三个放在同一台机器上,等于同时覆盖了两种包管理生态和三代系统特性,对搞运维和开发异构环境测试的人来说挺典型。
p.s. 如果你家里电脑总共就 8GB 内存,三台全跑起来会非常紧张,我的建议是拿一台内存 16GB 以上的机器专门做虚拟化实验,否则光内存交换就能让你怀疑人生。具体内存怎么分,我在第 3 节详细说。
2. 前置准备:版本匹配和 box 选型
2.1 Vagrant 与 VirtualBox 版本匹配是第一道坎
很多人一上来直接vagrant up,卡住了就怪运气。实际上 Vagrant、VirtualBox、box 之间是强耦合的,尤其 VirtualBox 升级后,老的 Vagrant 插件经常崩。我这次用的组合是 VirtualBox 7.0.12 + Vagrant 2.4.1,整体比较稳。如果你还在用 VirtualBox 6.x 配新版 Vagrant,大概率会遇到宿主机虚拟网络适配器初始化失败、虚拟机启动后没有 IP 这类问题。
这里给一个保守建议:Vagrant 不要追求最新,VirtualBox 也不要追求最新,两者都选当前时间点附近已经发布半年以上的稳定版本,遇到奇葩问题的概率会低很多。安装顺序也有讲究,先装 VirtualBox,再装 Vagrant,装完打开 VirtualBox 确认 Host-Only 网络适配器已经创建成功。
2.2 box 选哪个:generic 系更省心
Vagrant 世界里没有"官方全包"的说法,box 基本靠社区维护。CentOS 8 官方已经停止维护,直接用centos/8这个老 box 很可能拉取失败或者里面的仓库配置失效。我更推荐generic/centos8,这是 Roboxes 维护的通用 box,支持 VirtualBox 和 VMware 后端,generic/ubuntu2204、generic/ubuntu2404同理。
选择 box 之前,建议先跑一下vagrant box list看看本地有没有旧缓存,再用vagrant box add generic/centos8 --provider virtualbox拉镜像。如果这一步就卡在下载上,不要硬刚,看下面这个坑。
| 目标系统 | 推荐 box | 说明 |
|---|---|---|
| CentOS 8 | generic/centos8 | 基于 CentOS 8.5,能提供最小化环境,仓库需要用 vault 源 |
| Ubuntu 22.04 | generic/ubuntu2204 | 稳定经典,box 体积适中 |
| Ubuntu 24.04 | generic/ubuntu2404 | 内核版本高,要求 VirtualBox 和 Guest Additions 版本同步更新 |
注意:box 名称里的
generic/前缀代表了维护方,不是系统版本号。拉之前最好去 Vagrant Cloud 看一眼这个 box 是否还存活,有些老 box 会因为维护者删除而直接 404。
2.3 拉取 box 太慢或失败时的应急方案
我这边网络环境访问 Vagrant Cloud 的速度堪比老牛拉破车,vagrant box add要么卡在等待响应,要么直接超时。这时候不要反复重试,我的方案是:先拿到 box 的直链下载地址(比如从 Vagrant Cloud 盒子的页面里复制.box文件的 URL),用浏览器或者下载工具直接拉下来,再执行本地导入:
vagrant box add /path/to/generic-ubuntu2404.box --name generic/ubuntu2404本地导入之后,Vagrantfile 里正常写config.vm.box = "generic/ubuntu2404"即可,Vagrant 不会再去远程检索。这个方法也适合公司内网部署,你可以把 box 文件放到内网共享目录,所有人统一导入,减少重复下载。
3. 核心配置:一份 Vagrantfile 拉起三个系统
3.1 多机定义的典型结构
Vagrantfile 本质上是 Ruby 脚本,但就算你没写过 Ruby 也能直接照抄。我这里把三台机器写在一个文件里,每台用config.vm.define单独声明。下面这个配置是最终能跑通的版本,我逐行注释了:
# -*- mode: ruby -*- Vagrant.configure("2") do |config| # 基础镜像设置,三个虚拟机默认用这个 config.vm.box = "generic/centos8" config.vm.box_check_update = false # 共享一个 SSH 配置,避免每台重复写 config.ssh.insert_key = false # ---------- CentOS 8 ---------- config.vm.define "centos8" do |centos| centos.vm.box = "generic/centos8" centos.vm.hostname = "centos8-node" centos.vm.network "private_network", type: "dhcp" centos.vm.provider "virtualbox" do |vb| vb.name = "vagrant-centos8" vb.memory = 1024 vb.cpus = 1 end end # ---------- Ubuntu 22.04 ---------- config.vm.define "ubuntu22" do |u22| u22.vm.box = "generic/ubuntu2204" u22.vm.hostname = "ubuntu22-node" u22.vm.network "private_network", type: "dhcp" u22.vm.provider "virtualbox" do |vb| vb.name = "vagrant-ubuntu22" vb.memory = 1536 vb.cpus = 2 end end # ---------- Ubuntu 24.04 ---------- config.vm.define "ubuntu24" do |u24| u24.vm.box = "generic/ubuntu2404" u24.vm.hostname = "ubuntu24-node" u24.vm.network "private_network", ip: "192.168.56.24" u24.vm.provider "virtualbox" do |vb| vb.name = "vagrant-ubuntu24" vb.memory = 1536 vb.cpus = 2 end end end这个文件有几个细节值得说。第一,type: "dhcp"和直接指定ip我混用了,目的是让你看到两种方式都可行。DHCP 方式简单省心,但每次启动后 IP 可能要重新vagrant ssh进去查;指定 IP 适合需要固定访问地址的机器,比如你要给 Ubuntu 24 配 nginx 端口转发或多站点域名,固定 IP 最方便。
第二,config.ssh.insert_key = false是我测试后加上的。默认情况下 Vagrant 会为每台机器生成新的 SSH key,但在国内网络环境下,有些 proxy 或安全软件会干扰 SSH 握手,关掉密钥插入能少一些离奇报错。生产环境不建议这样做,本地实验倒无所谓。
3.2 内存和 CPU 的分配逻辑
三台机器都开图形界面显然不现实,我全部用最小化环境,CentOS 8 分 1GB 内存 1 核,Ubuntu 两台各分 1.5GB 内存 2 核,总计 4GB 内存和 5 核。这个配置在 16GB 内存、8 核 16 线程的机器上跑,同时开三个实例依然有点喘,但能保证基本操作不卡死。
如果你的宿主机内存只有 8GB,建议砍掉一台,或者把 Ubuntu 24 降到 1GB。实际操作中,VM 里跑编译任务时内存会瞬间飙高,多留 500MB 余量也能避免虚拟机被 OOM killer 误杀。另外,VirtualBox 默认会为每台虚拟机分配一部分显存,如果你根本不打算进图形界面,可以在 provider 配置里加一行vb.gui = false,显存也能省下来。
3.3 初始化脚本写进 provision
Vagrant 的shellprovisioner 可以在虚拟机开机时自动执行命令,我习惯把装机后的基础操作全部放进去,省得手动打命令。来看一个最小的初始化脚本:
#!/bin/bash set -e # 更新系统时间,避免证书和时间不同步问题 timedatectl set-ntp true # 安装常用工具 if command -v yum &>/dev/null; then yum install -y vim curl net-tools htop elif command -v apt &>/dev/null; then export DEBIAN_FRONTEND=noninteractive apt update && apt install -y vim curl net-tools htop fi # 关闭防火墙,方便局域网内测试端口连通性 systemctl stop firewalld || true systemctl disable firewalld || true systemctl stop ufw || true systemctl disable ufw || true这段脚本同时兼容了 yum 和 apt 两个体系,对应 CentOS 和 Ubuntu。注意我用了|| true,原因是 CentOS 8 根本没有 ufw,Ubuntu 则不一定装了 firewalld,如果不用|| true兜底,脚本会判断失败并中断 provisioning。
在 Vagrantfile 里对应位置加上:
centos.vm.provision "shell", path: "init.sh" u22.vm.provision "shell", path: "init.sh" u24.vm.provision "shell", path: "init.sh"这里有个小坑:path是相对于宿主机上 Vagrantfile 所在目录的,所以三个 VM 可以共用同一个init.sh,省事。
4. 启动阶段的经典坑:box 下载、SSH 超时、Guest Additions
4.1 卡在Waiting for machine to boot怎么办
vagrant up最让人血压升高的时刻就是最后那行:
default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key Timed out while waiting for the machine to boot.这个报错出现的原因五花八门,但最常见的就是 VirtualBox 的 NAT 端口转发没有生效,或者虚拟机确实没起来。我的排查顺序是固定的:
- 打开 VirtualBox GUI,看那台虚拟机的运行状态,如果虚拟机窗口停在小黑屏或者启动 logo,说明系统还没起来,加长
config.vm.boot_timeout = 600试试; - 如果虚拟机已经起来但没有 IP,多半是网卡配置问题,检查 VirtualBox 全局网络设置里的 Host-Only Network 是否存在;
- 如果 SSH 一直拒绝连接,先手动
vagrant ssh看报错,再检查宿主机防火墙是否拦截了 2222 等端口转发。
在这个环节我实际遇到的是第二个原因:某次升级 VirtualBox 之后,原有的 Host-Only 网卡消失了,导致 private_network 无法创建。解决办法很简单,VirtualBox 全局设置里删除旧的 Host-Only Network,重新添加一个,然后重启 VirtualBox 服务。折腾完再vagrant up --provision,通常就能过。
4.2 box 下载失败的两种处理姿势
如果你第一次拉 box 时走到一半断了,Vagrant 会留下残缺文件在~/.vagrant.d/boxes,下次vagrant add可能直接报"file already exists"之类的错。这时候千万别慌,vagrant box list看名字,vagrant box remove 名字删掉残货,重新拉要么再本地导入。
国内网络环境下,走官方源确实慢,我采取了两条路:
- 短期解近渴:找到 box 直链,用下载工具拉到本地,然后
vagrant box add本地导入,就像上面说过的那样; - 长期保平安:搭建一个内网的 box 镜像目录,团队之间共享
.box文件,大家统一导入相同版本。这样 Vagrantfile 里的 box 名称不变,但拉取过程可以完全离线。
提示:有些 box 文件体积超过 1GB,导入之前记得确认磁盘剩余空间。Vagrant 在导入阶段会复制一份到
~/.vagrant.d/boxes,本地残留文件不要急着删,等三台机器全部 up 成功再清理。
4.3 共享目录同步失败的背后
如果你跟我一样在 Vagrantfile 里设置了同步目录,比如写config.vm.synced_folder ".", "/vagrant",那么 Guest Additions 版本必须和 VirtualBox 版本匹配。Ubuntu 24.04 刚出那会儿,很多 box 自带的 Guest Additions 还是旧版本,启动后 Vagrant 会在宿主机日志里警告 vboxsf 模块不存在,共享目录挂载失败,机器却照样能登录。
我的解法是安装vagrant-vbguest插件,让它在启动后自动更新 Guest Additions:
vagrant plugin install vagrant-vbguest装好后再次vagrant reload --provision,插件会尝试在虚拟机里编译新的 Guest Additions。这个过程依赖编译工具链,Ubuntu 上一般会自动装好 kernel headers。如果你的机器上网络源太慢,直接在初始化脚本里预装gcc make linux-headers-$(uname -r),能省很多时间。
5. 按发行版拆开看:CentOS 8、Ubuntu 22、Ubuntu 24 各有各的坑
5.1 CentOS 8 停服后的仓库和 box 问题
这是三个系统里最容易翻车的一个。CentOS 8 在 2021 年末就 EOL 了,官方仓库已经停止保留,yum install默认指向的 mirrorlist 地址根本解析不到。现象就是:
Errors during downloading metadata for repository 'AppStream': Status: 404 curl: (6) Could not resolve host: mirrorlist.centos.org解决办法是手动把 CentOS 8 的仓库源切到 vault.centos.org。在初始化脚本里提前处理,或者启动后手动执行。我的建议是直接用 vault 源的配置文件覆盖:
sudo sed -i 's|^mirrorlist=|#mirrorlist=|g' /etc/yum.repos.d/CentOS-Linux-*.repo sudo sed -i 's|^#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-Linux-*.repo具体版本号还需要和系统匹配,建议先写一个dl.vault.centos.org的 baseurl,验证下yum update是否正常工作,然后再批量应用。
如果 box 拉不到或启动失败,也可以试试改用bento/centos-stream-8,它是 CentOS Stream 的 box,不是标准 CentOS 8,但至少还在维护,仓库也是活的。两者差异需要你自己判断,我的项目里偏向模拟旧生产环境,所以最后还是用generic/centos8+ vault 源解决了。
5.2 Ubuntu 22.04 的 netplan 与私网配置
Ubuntu 22.04 早就用 netplan 管理网络了,Vagrant 的 private_network 本质上是在 VirtualBox 里新增一张 Host-Only 网卡,guest 里需要用 netplan 把这张网卡带上。大多数官方 box 已经做了自动化配置,但如果你的vagrant up之后发现ip addr看不到 192.168.56.x 的地址,八成是 netplan 没有生成对应配置文件。
最简单的排查方式是:
ip addr show cat /etc/netplan/01-netcfg.yaml如果发现缺失,手动写一个配置文件,指定 DHCP 或静态 IP:
network: version: 2 renderer: networkd ethernets: eth1: dhcp4: true然后sudo netplan apply即可。Vagrant box 的网卡名称不一定是 eth1,要根据ip addr输出里的实际接口名来改。这个坑在 VirtualBox 升级后偶尔会出现,因为网卡 MAC 变了,netplan 里的旧接口名匹配不上。
5.3 Ubuntu 24.04 的新内核和 VirtualBox 版本兼容
Ubuntu 24.04 的内核版本一路飙到了 6.8 以上,VirtualBox 7.0 早期版本对这种新内核的虚拟化支持并不完美,典型表现是启动时卡在 GRUB 或者 Guest Additions 编译失败。如果你遇到类似问题,优先升级 VirtualBox 到 7.0.10 以上,再配合vagrant-vbguest插件强制重建 vboxsf。
另外,Ubuntu 24.04 默认禁用了 root 用户 SSH 登录,Vagrant 使用的是 vagrant 用户,我这里没什么影响,但如果你习惯切到 root,记得手动配置PermitRootLogin yes。还有一个细节:Ubuntu 24.04 的apt默认使用deb822格式源文件,如果你手动改过/etc/apt/sources.list,更新后可能会发现源被系统提示忽略,建议老老实实沿用/etc/apt/sources.list.d/ubuntu.sources的结构。
6. 常见问题排查与速查表
6.1 碰到这些症状直接翻表
我把这次折腾过程中遇到的典型问题整理成了速查表,后面再踩坑直接对着查:
| 症状 | 可能原因 | 解决思路 |
|---|---|---|
vagrant up卡在 box 添加过程 | 网络访问 Vagrant Cloud 太慢 | 下载 .box 文件本地导入 |
Timed out while waiting | VirtualBox Host-Only 网卡丢失或端口转发异常 | 重建 Host-Only 网络,调大config.vm.boot_timeout |
| 虚拟机起来了但无法 SSH | SSH key 对接异常、防火墙拦截端口 | 检查宿主机防火墙,vagrant reload --provision |
共享目录/vagrant为空 | Guest Additions 版本不匹配 | 安装 vagrant-vbguest 插件并 reload |
| CentOS 8 内 yum 报 404 | CentOS 8 仓库已转 vault | 修改 yum repo 指向 vault.centos.org |
| Ubuntu 22 没有私有网络 IP | netplan 缺少对应网卡配置 | 编写 netplan 配置并 apply |
| Ubuntu 24 启动卡死 | VirtualBox 版本太旧,不支持新内核 | 升级 VirtualBox 到 7.0.10+ |
6.2 三台机器如何验证都正常
全部 up 起来之后,我习惯做一个快速健康检查,确认三台都能互通,然后再决定是否进入项目开发:
vagrant ssh centos8 -c "ip addr show eth0 | grep 'inet '; hostname; uptime" vagrant ssh ubuntu22 -c "ip addr show | grep 'inet '; hostname; uptime" vagrant ssh ubuntu24 -c "ip addr show | grep 'inet '; hostname; uptime"如果三台都返回了 IP 和系统信息,说明 Vagrantfile 基础配置没问题。接下来我还会测试一下宿主机到三台虚拟机的网络连通性,用ping和curl各试一轮。平时用的端口转发,比如 8080、3306,也应该逐一点一遍,确认没有防火墙拦路。
7. 最后的几个小技巧:省内存、省时间、少返工
在完整跑通这一套之后,我积累了几个能显著提升体验的习惯。第一个是善用vagrant snapshot。三台虚拟机同时跑起来后,再想重新测试某个系统的初始状态,重新 provision 一遍要浪费好几分钟。我通常在装好基础环境后执行:
vagrant snapshot save centos8 initial vagrant snapshot save ubuntu22 initial vagrant snapshot save ubuntu24 initial之后如果搞坏了,直接vagrant snapshot restore initial秒回春,这比重新建机省太多事。
第二个是不要迷信default这一台,多机环境下所有命令都带上机器名,比如vagrant up ubuntu24、vagrant reload centos8 --provision。不带机器名的话,Vagrant 会对所有机器执行操作,初看很爽,遇到某台机器没配置好时,报错都分不清是哪台。
第三个和资源占用有关:宿主机内存有限的情况下,不用的时候记得vagrant halt挂起,别一直让它占内存。如果三台同时开着不干活,光内存就吃掉 4GB,对开发机的编译任务也是一个不小的负担。
最后是给所有想折腾的人一句话:不要为了纠结某个 box 版本把时间全耗在网络上,box 的本质就是一个基础镜像,换不了源就本地导入,换不了版本就换维护方,先把环境跑起来,再慢慢优化配置。我自己第一次把三台全拉起来的时候,宿主机的可用内存只剩不到 300MB,鼠标都开始跳了,后来调整了内存分配和启动顺序,才终于稳定下来。这个配置我现在还留着,做多机网络实验和异构系统联调时直接复用,省下的时间比调试它的时候多出好几倍。