跳到主要内容

Vagrant 使用教程

小林
后端开发工程师, 专注Go开发、微服务和云原生

学习 Kubernetes 等分布式系统时, 硬件资源限制常成为实践瓶颈, 有个方法是用虚拟机模拟机器节点. 本文将介绍如何使用 Vagrant 工具管理虚拟机, 在单机环境中快速构建多节点虚拟机集群

cool-one.png

为什么不用 Docker 搭建集群?

Docker 容器间共享宿主机内核, 隔离仅限于命名空间, 而虚拟机拥有独立的系统内核, 有自己的网卡, 节点间完全隔离, 用多台虚拟机模拟更接近真实场景

Vagrant 是什么?

Vagrant 是一个用于构建和管理虚拟机环境的命令行工具, 它通过 Vagrantfile 配置文件, 自动化定义虚拟机的计算资源(CPU、内存)、存储配置、网络拓扑以及操作系统等关键参数, 只要使用相同的 Vagrantfile, 就能创建出完全一致的开发环境, 避免手动操作导致的环境差异

Vagrant 本身不是虚拟机管理程序, 不直接创建或运行虚拟机. 它是一个虚拟化环境的抽象层和自动化工具, 依赖于底层虚拟化平台(如 VirtualBox、VMware、Hyper-V 或 Docker 等)来实际执行虚拟机的创建和管理操作

安装

安装 Vagrant

Windows 系统可通过安装包安装 vagrant_2.4.9_windows_amd64.msi, 其他系统参考 Install Vagrant

通过下面命令校验是否成功安装

vagrant --help

安装虚拟化软件

Vagrant 支持多种虚拟化软件, VirtualBox, Hyper-V, VMware 和 Docker, 个人建议使用 VirtualBox, 这也是 Vagrant 的默认虚拟化软件

可通过官网下载安装包 Download VirtualBox

开始

创建项目目录并进入

mkdir learn-vagrant-get-started && cd learn-vagrant-get-started

初始化 Vagrant 环境

vagrant init hashicorp-education/ubuntu-24-04 --box-version 0.1.0

Vagrant 会在本地创建一个 Vagrantfile 配置文件, 省略了注释后内容如下

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

Box

Vagrant 的 Box 类似于 Docker 的容器镜像, Vagrant 使用配置文件中指定的基础镜像构建虚拟机, 基础镜像通常从官方镜像仓库拉取

上面配置表示, 使用官方镜像仓库上的 hashicorp-education/ubuntu-24-04 镜像, 版本为 0.1.0

官方镜像仓库

Vagrant 也有类似 Docker Hub 的官方镜像仓库, 地址为 HCP Vagrant Registry

img

启动虚拟机

vagrant up

如果没有明显报错, 输出完下面日志后就代表虚拟机创建成功

vagrant up 日志

Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'hashicorp-education/ubuntu-24-04'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp-education/ubuntu-24-04' version '0.1.0' is up to date...
==> default: Setting the name of the VM: learn-vagrant-get-started_default_1764658229098_38119
==> default: Fixed port collision for 22 => 2222. Now on port 2202.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2202 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2202
default: SSH username: vagrant
default: SSH auth method: private key
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
default: The guest additions on this VM do not match the installed version of
default: VirtualBox! In most cases this is fine, but in rare cases it can
default: prevent things such as shared folders from working properly. If you see
default: shared folder errors, please make sure the guest additions within the
default: virtual machine match the version of VirtualBox you have installed on
default: your host and reload your VM.
default:
default: Guest Additions Version: 7.1.0
default: VirtualBox Version: 7.2
==> default: Mounting shared folders...
default: D:/workspace/learn-vagrant-get-started => /vagrant

Vagrant 做了什么?

  • 拉取基础镜像, 通常会从官方镜像仓库拉取
  • 使用虚拟化软件创建虚拟机, 无特殊配置的话默认使用 VirtualBox
  • 网络配置, 配置 NAT 网络使虚拟机可访问外部网络
  • 开启 SSH 服务并将虚拟机的 22 端口转发到宿主机, 使宿主机可以通过 SSH 连上虚拟机
  • 生成 SSH 密钥对并将公钥注入虚拟机
  • 挂载共享文件夹, 将项目目录映射到虚拟机的 /vagrant 目录

打开 VirtualBox 软件可以发现 Vagrant 成功创建了新的虚拟机

img

访问虚拟机

因为 Vagrant 已为虚拟机开启 SSH 服务并且将公钥注入虚拟机, 所以宿主机可通过 SSH 连接免密访问虚拟机, 通过下面命令即可连上虚拟机

vagrant ssh

在虚拟机内尝试运行命令

vagrant@vagrant-ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.1 LTS
Release: 24.04
Codename: noble

从虚拟机返回宿主机可运行下面命令

logout

休眠虚拟机

vagrant suspend

img

唤醒虚拟机

vagrant resume

img

关闭虚拟机

vagrant halt

img

销毁虚拟机

vagrant destroy
注意

销毁虚拟机后并不会删除拉取的镜像文件, 如果需要删除镜像需要执行下面命令

vagrant box remove hashicorp-education/ubuntu-24-04

网络

网络配置      Mode      VM→Host  VM←Host  VM1↔VM2VM→Net/LANVM←Net/LAN
private_networkHost-only
private_network + virtualbox__intnetInternal
public_networkBridged
forwarded_portNATPort forwardPort forward
NAT NetworkPort forwardPort forward

Forwarded Port

Vagrant 的 Forwarded Port 网络模式对应 VirtualBox 的 NAT 网络模式, 这种模式下

  • 虚拟机可以访问外部网络
  • 外部网络无法访问虚拟机
  • 虚拟机之间不互通

在 VirtualBox 中 NAT 网络模式可选开放端口映射让外部网络访问虚拟机, 而在 Vagrant 中 Forwarded Port 网络模式的端口映射是必选项

Vagrant 启动虚拟机时默认会开启 Forwarded Port 网络模式, 并且将虚拟机的 22 端口映射到宿主机, 这样保证宿主机可以通过 vagrant ssh 命令连接到虚拟机

img

在 VirtualBox 的管理器中可以看到 Vagrant 启动的虚拟机中默认有一张 NAT 网卡, 并且有条名称为 ssh 的端口转发规则, 将虚拟机的 22 端口映射到宿主机的 2222 端口

Forwarded Port 网络模式配置

config.vm.network "forwarded_port", guest: 80, host: 8080

如果希望除了宿主机的其他外网无法访问虚拟机

config.vm.network "forwarded_port", guest: 81, host: 8081, host_ip: "127.0.0.1"

可以发现在同块 NAT 网卡上增加了两条端口转发规则

img

Forwarded Port 网络模式会给虚拟机分配 10.0.2.15 地址, 并且可通过 10.0.2.2 地址直接访问宿主机

img

Private Network

Vagrant 的 Private Network 网络模式对应 VirtualBox 的 Host-only 网络模式, 这种模式下

  • 同一宿主机上的虚拟机之间可互相访问
  • 虚拟机与宿主机之间可相互访问
  • 其他外部网络无法访问该私有网络

Private Network 网络模式可配置静态 IP 或动态 IP

静态 IP

config.vm.network "private_network", ip: "192.168.50.4"

可以看到虚拟机多了一张 Host-Only 网络模式的网卡

img

在宿主机可以看到 VirtualBox 创建的虚拟网卡, IP 地址跟虚拟机设置的 IP 在同个网段

img

在虚拟机查看 IP 可以发现正是我们说配置的静态 IP

img

动态 IP

config.vm.network "private_network", type: "dhcp"

Internal 网络

当配置 virtualbox__intnet 参数时, Private Network 则对应 VirtualBox 的 Internal 网络模式, 这种模式下

  • 虚拟机之间可相互通信
  • 虚拟机和宿主机以及外部网络不互通
config.vm.network "private_network", ip: "192.168.50.4",
virtualbox__intnet: "mynetwork"
注意

virtualbox__intnet 有两条下划线, 要求网络名称相同的虚拟机才可相互通信

可以看到虚拟机的网卡变成了 Internal 网络模式, 并且名称正是我们所设置的 mynetwork

img

Public Network

Vagrant 的 Public Network 网络模式对应 VirtualBox 的桥接(Bridged)网络模式, 这种模式下

  • 虚拟机相当于局域网的一台真实机器, 可跟局域网内的任意机器互通
  • 会消耗局域网一个 IP 地址

静态 IP

config.vm.network "public_network", ip: "192.168.0.17"

Public Network 网络模式会直接使用宿主机的网卡, 所以在启动虚拟机后需要你选择一张网卡

img

可以看到虚拟机使用了桥接模式, 名称正是我们选择的网卡名称

img

注意

设置静态 IP 时要处于局域网的网段, 否则外部网络无法访问虚拟机

img

动态 IP

如下配置即为设置动态 IP, 局域网会自动分配一个 IP 地址给我们

config.vm.network "public_network"

CPU和内存

我们在使用虚拟机时经常对 CPU 和内存有要求, 可通过下面配置设置

config.vm.provider "virtualbox" do |v|
v.memory = 1024
v.cpus = 2
end
提示

内存的单位是 MB, 不进行设置虚拟机默认为1个CPU和2048MB内存

多节点

多台机器通过 config.vm.define 方法在配置文件中定义

# 全局公共配置
config.vm.box = "hashicorp-education/ubuntu-24-04"
config.vm.box_version = "0.1.0"

config.vm.define "web"
config.vm.define "db"

多节点命令使用变化

命令说明
vagrant up默认启动所有定义的机器
vagrant up web仅启动名为"web"的机器
vagrant ssh db连接到名为"db"的机器(必须指定机器名)
$ vagrant ssh
This command requires a specific VM name to target in a multi-VM environment.
$ vagrant ssh db
Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-51-generic x86_64)

可通过 primary 参数设置主机器, vagant ssh 可省略机器名, 默认连到主机器上

config.vm.define "web", primary: true
config.vm.define "db"

一主双从节点

下面我们将配置一个一主双从节点, 每个节点设置各自的主机名、CPU和内存、私有静态IP

Vagrant.configure("2") do |config|

config.vm.box = "hashicorp-education/ubuntu-24-04"
config.vm.box_version = "0.1.0"

config.vm.define "master", primary: true do |master|
master.vm.hostname = "master"
master.vm.network "private_network", ip: "192.168.50.10"
master.vm.provider "virtualbox" do |vb|
vb.name = "vagrant-master"
vb.memory = "2048"
vb.cpus = 2
end
end

config.vm.define "worker1" do |worker1|
worker1.vm.hostname = "worker1"
worker1.vm.network "private_network", ip: "192.168.50.11"
worker1.vm.provider "virtualbox" do |vb|
vb.name = "vagrant-worker1"
vb.memory = "1024"
vb.cpus = 1
end
end

config.vm.define "worker2" do |worker2|
worker2.vm.hostname = "worker2"
worker2.vm.network "private_network", ip: "192.168.50.12"
worker2.vm.provider "virtualbox" do |vb|
vb.name = "vagrant-worker2"
vb.memory = "1024"
vb.cpus = 1
end
end
end

成功启动了三台虚拟机

img

使用变量和each简化配置

将每个节点的专有配置提取到 NODES 变量中, 然后用 each 语法定义每台机器

NODES = {
'master' => {
ip: '192.168.50.10',
cpus: 2,
memory: 2048,
},
'worker1' => {
ip: '192.168.50.11',
cpus: 1,
memory: 1024,
},
'worker2' => {
ip: '192.168.50.12',
cpus: 1,
memory: 1024,
},
}

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

NODES.each do |name, cfg|
config.vm.define name do |node|
node.vm.hostname = name
node.vm.network "private_network", ip: cfg[:ip]
node.vm.provider "virtualbox" do |vb|
vb.name = "vagrant-#{name}"
vb.cpus = cfg[:cpus]
vb.memory = cfg[:memory]
end
end
end
end

参考