简介
Vagrant 虚拟机管理
用于管理虚拟机集群
Vagrant 虚拟机管理,什么是 Vagrant
Vagrant is designed for everyone as the simplest and fastest way to create a virtualized environment
乍一看,这不是容器化的作用吗?这是 docker 干的事情。实际上,docker 和 vagrant 有很多相似之处,他们都能提供一致的环境。但是,区别是:
- Docker 管理的是容器(指的是 docker cli)
- Vagrant 管理的是虚拟机
Vagrant 支持 Virtualbox、Vmware Workstation Player、Hyper-V 等主流的虚拟机软件,通过插件 libvirt 管理 KVM 虚拟机等,这些软件就像Docker Engine 一样,提供虚拟化的平台。这里推荐使用 Virtualbox。
我之前写了一个 WPLY 项目,用于容器化部署 WordPress,用 Vagrant 也可以做到,但是容器更适合这种使用场景。那么 vagrant 的意义在哪?
为什么使用 Vagrant 虚拟机管理
原因是容器化还是在“上层”,它不能为不同的容器提供不同的 linux 系统,硬件配置等。其次,如果想在本地快速搭建一个虚拟机集群,你会不得不使用到 vagrant。
这就像:即使现在的网站再多,但你想访问一个网站,你得先把你的电脑连上网。就像 wifi 和有线网络,他们是相互辅助的关系。
搭建、维护这些集群的过程被称之为:Local Infrastructure Development 同时也有一个职业叫做 Infrastructure Engineer
此外 vagrant 在做测试时非常好用,可以迅速创建、销毁、再创建、再销毁不同的虚拟机,也许一天你就创建了数十乃至数百个虚拟机。
GUI 与 CLI
Vagrant 能做到的,Virtualbox 的 GUI 也能做到。但实际上,如果你只需要一个定制化的虚拟机,你可能使用 GUI 就可以做到,而如果你需要一组具有相似环境的虚拟机,这时候 GUI 就不够用了,这时候,即使是模板功能,也不够用了。
PS: 这个 Vagrant 的 cli 和 Virtualbox 的 cli 不一样,它们不是干一个事情的,它们的逻辑不同。
Box
盒子,这个名字很形象,vagrant 和 docker 一样,有自己的镜像,叫做 Vagrant Cloud。你可以从这里拉取 box。很多发行版,例如 Arch、Debian、Ubuntu、CentOS 等,都提供了 box 镜像,你也可以从它们的镜像源里找到。
box 主要有三种来源:
- 来自于发行版,某些发行版提供自己的 box 镜像,可以直接在该发行版的源里找到。和 vagrant cloud 里以发行版名字开头的组织提供的 box 相同
- 来自于 Roboxes 项目的镜像,以 generic 为组织名
- 来自于个人,用户也可以发布自己的 box
在 Vagrant Cloud 里可以看到容器化技术对这种传统虚拟化技术的冲击,很多镜像已经数年没更新了。
使用
注释
我把 vagrant 的文档看了一遍,发现还是以时间为顺序来写个指南比较好,直接读文档需要有一定的记忆和理解能力。
国内网络环境糟糕,请自建代理,或提前下载box。
概览
要使用 Vagrant,需要按照以下步骤进行设置和配置:
- 安装虚拟化软件:
- 首先,安装虚拟化软件,如 Virtualbox 或 VMware。
- 安装 Vagrant:
- 在安装虚拟化软件之后,前往 Vagrant 官方网站下载安装适用于的操作系统的安装程序。
- Linux 使用自己源里的 Vagrant
- 选择和配置 Vagrant box:
- Vagrant box 是预配置的虚拟机映像文件,可以作为 Vagrant 环境的基础。在之前介绍的 Vagrant Cloud 上找到各种可用的 Vagrant box。
- 选择一个适合需求的 box,并通过命令行运行
vagrant init <box-name>
来初始化 Vagrant 环境。
- 编辑 Vagrantfile:
- Vagrantfile 是 Vagrant 环境的配置文件,可以定义虚拟机的硬件配置、网络设置、共享文件夹等。
- 启动 Vagrant 环境:
- 完成 Vagrantfile 的配置之后,通过运行
vagrant up
命令来启动 Vagrant 环境。 - Vagrant 会自动下载和启动虚拟机,并根据 Vagrantfile 中的配置进行设置。
- 完成 Vagrantfile 的配置之后,通过运行
- 登录到虚拟机:
- 一旦 Vagrant 环境启动成功,可以通过运行
vagrant ssh
命令来登录到虚拟机的终端。
- 一旦 Vagrant 环境启动成功,可以通过运行
前两个步骤不是本文的重点,这里就省略不写了,直接进入后续内容。
在使用 vagrant 之前,建议先使用终端,进入到一个新的目录中,在这个目录下使用 vagrant。vagrant 产生的文件如:密钥、配置等均在这个目录下。
获取 box
这里以 debian/bookworm64
为例:
首先使用 vagrant box add <address> 来下载镜像,这个 address 可以从镜像源找到。如果你和 vagrant cloud 的网络连接正常,则可以使用:
vagrant box add debian/bookworm64
除了 add 子命令,box 命令还有其它常用的子命令
vagrant box list
列出下载的 boxvagrant box prune
删除旧版本的 boxvagrant box remove <NAME>
删除指定的 boxvagrant box update
更新下载的 box
初始化
初始化时如果镜像没有被下载,那么 vagrant 会自动拉取镜像。
vagrant init debian/bookworm64
使用该命令,将会在当前目录下生成一个名为 Vagrantfile 的文件,这个文件里包含了虚拟机的配置。默认的配置就能够运行了,一会儿再回来说 Vagrantfile 的使用。
如果当前目录下已有一个 Vagrantfile,可以使用 -f 参数来覆盖当前文件 。
vagrant init -f debian/bookworm64
启动
vagrant up
使用该命令,即可启动虚拟机。和其它虚拟机一样,也可以在 Virtualbox 的 GUI 看到虚拟机的状态。
关于虚拟机的电源管理还有以下命令:
- vagrant halt 尝试关闭虚拟机,关闭失败后强制关机(断电)
- vagrant suspend 休眠虚拟机,简单来说就是把内存写进硬盘
- vagrant resume 从 suspend 状态启动
- vagrant reload 相当于 halt 后再 up
连接
vagrant ssh
vagrant 将会使用它插入的密钥来连接虚拟机。在 Windows 下使用 ssh 时,vagrant 将会寻找Windows下的 ssh 命令,Windows 11 自带的 ssh 可能不能正常工作,可以考虑安装 Cygwin 这类工具。
查看虚拟机状态
vagrant status
将列出当前 vagrantfile 中虚拟机的状态。
删除
vagrant destroy
该命令将删除整个虚拟机,在确保虚拟机里没有要保留的文件的情况下,可以放心的使用该命令来删除虚拟机,日后如果需要,直接 up 就可以了。 Vagrantfile 所在的目录不会被删除。
Vagrantfile
Vagrantfile 是一个用于定义和配置虚拟机环境的文件,它基于 Ruby 语法。通过修改 Vagrantfile 文件,你可以指定虚拟机的操作系统、网络设置、共享文件夹和其他配置选项。它可以定义多个虚拟机、多个不同系统。
首先请建立一个文件夹用于存放 vagrant 生成的虚拟机相关的文件,然后可以直接使用 vagrant init
来生成一个示例配置文件,大概看起来是这样:
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "base"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Disable the default share of the current code directory. Doing this
# provides improved isolation between the vagrant box and your host
# by making sure your Vagrantfile isn't accessable to the vagrant box.
# If you use this you may want to enable additional shared subfolders as
# shown above.
# config.vm.synced_folder ".", "/vagrant", disabled: true
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2
# SHELL
end
来看那这一部分的重点配置
config.vm.box
15行的 config.vm.box
定义了虚拟机的 box,在 vagrant cloud 上找到的想要使用的 box ,例如 debian/bookworm64
config.vm.network
网络和我们平时认知的虚拟机网络稍稍有点差别,除了虚拟机默认有一个 nat 网络以外,在 vagrant 中只有三种网络(实际上是后两种),分别是:
- forwarded_port
- private_network
- public_network
forwarded_port
和字面意思一样,很好理解,就是端口转发,将虚拟机的某个端口转发至宿主机,例如在虚拟机启动阶段,vagrant 会自动把虚拟机的 22 端口转发到宿主机的 2222 端口(如果被占用 vagrant 会尝试其它端口)
如果你需要测试某个服务,你可以把该端口映射出来,例如文中的 config.vm.network "forwarded_port", guest: 80, host: 8080
即把虚拟机的 80 端口映射到宿主机的 8080 端口。
private_network
类似于 hostonly 即虚拟机能访问主机的虚拟网卡。另外 vagrant 会使用 provider 的 DHCP 功能,尝试自动分配 ip, 不过你也可以选择手动分配。
public_network
类似于 bridge 即桥接网卡,虚拟机与宿主机在网络上是同等的地位,都有相同网段的 ip,根据网络的不同情况,vagrant 可能会询问需要桥接到哪个网卡。
config.vm.synced_folder
共享文件夹,如果什么都不写,默认是把有对应 Vagrantfile 的目录映射到 /vagrant 下。你也可以指定把某个目录映射到虚拟机里。
config.vm.provider
这是一些对于某些 provider 的特殊设置,例如设置虚拟机的内存使用的资源等,对于不同 provider 的表象不同。
config.vm.provision
对在这里面可以写一些 shell 脚本虚拟机进行初始化,例如安装软件,做一些简单的配置。不过除了 shell 脚本,我更推荐使用 ansible/chef/puppt 这类自动化软件做 provision。如果你不熟悉,或者内容很简单(不超过20行)那就用 shell 好了。
结论
以上就是现在你可以创建一个虚拟机试试,打开终端然后
- 使用
vagrant init
获得示例配置 - 根据需要修改配置,可以只更改
config.vm.box
其余保持不变 vagrant up
启动虚拟机- 等待启动后使用
vagrant ssh
连接虚拟机
多虚拟机场景
下面是一个示例使用了一些小技巧,将脚本嵌入到 Vagrantfile 的其它位置,我的 provision 脚本使用 sed 做了换源和更新。
我定义了三个虚拟机,分别是 ctrlnode、 node01 和 node02,它们有个性化的配置,而不再是 config.vm.xxx
原理是:如果在 config.vm.define do...end
语句块中的定义只在该语句块内有用,即有自己的作用域。
注意:位于语句块的 provision 脚本将会在语句块外的 provision(即换源、更新操作)执行后执行。
注意:
# -*- mode: ruby -*-
# vi: set ft=ruby :
$changeRepo = <<-'REPO'
sudo sed -i 's/deb.debian.org/mirrors.bfsu.edu.cn/g' /etc/apt/sources.list
sudo sed -i 's/security.debian.org/mirrors.bfsu.edu.cn/g' /etc/apt/sources.list
sudo apt update
sudo apt -y upgrade
REPO
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "debian/bookworm64"
config.vm.synced_folder "share", "/vagrant_share"
config.vm.provision "shell", inline: $changeRepo
config.vm.define "ctrlnode" do |ctrlnode|
ctrlnode.vm.network "private_network", ip: "192.168.33.10",
name: "servicenet",
virtualbox__intnet: true
ctrlnode.vm.provision "shell",
inline: "sudo apt -y install ansible"
ctrlnode.vm.hostname = "ctrlnode"
end
config.vm.define "node01" do |node01|
node01.vm.network "private_network", ip: "192.168.33.20",
name: "servicenet",
virtualbox__intnet: true
node01.vm.hostname = "node01"
end
config.vm.define "node02" do |node02|
node02.vm.network "private_network", ip: "192.168.33.21",
name: "servicenet",
virtualbox__intnet: true
node02.vm.hostname = "node02"
end
end
现在我创建了一个有三个虚拟机的节点,我们可以 vagrant up
了。vagrant 将会创建三个虚拟机并有自己的名字,每个虚拟机都有两块网卡,一个默认的 nat 和一个 private_network 且由于它们在相同ip段,它们可以通过该网卡相互访问。
结尾
以上是对 vagrant 的基础使用的指南,如果想要进阶使用,请参考官方文档。值得一提的是 HashiCorp 的文档一直都不错,非常详细,通俗易懂。
一些小坑:
- 如果你使用 docker 和 KVM 你可能会遇到 Starting Docker breaks KVM bridged networking 这个问题
- Windows 下自带的 ssh 好像不太正常可能会遇到问题
- vagrant 对 Hyper-v 的支持还不是很好