vagrant 做测试环境的一点总结(下)

生活不会因为某个节点而变得与众不同,未来的幸运,都是过往努力的积攒。

vagrant 是我在本地 osx 系统下做测试环境时候开始研究的,以前只是单一的用 vbox 装个本地虚机时并没有发觉用或者不用有什么差别,但随着本地开始有一些特殊需求的时候,才发觉 vagrant 提供的功能还是很值得称赞的。

provisioning

类似于开机启动,可以开机执行某个命令,可以执行某个脚本都可以

比如我想在开机后自动安装某个包,同步下时间,那么如果是 vbox 的虚机可能你得连到虚机里,然后在/etc/rc.local下写上命令等等,但在 Vagrantfile 里,可以直接以配置的形式体现,下面这段是配置里自带的一段,开机自动更新包,安装 Apache

config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y apache2
SHELL

所以只要把中间那部分换成自己的命令就好,但是如果命令太长,还有逻辑判断,最好是开机执行个脚本,那在配置文件里应该这样写

config.vm.provision :shell, path: "<scriptname.sh>"

注意这里的路径是以Vagrantfile所在的目录为根目录的,上述的写法,脚本就必须存放在和 Vagrantfile同级就可以

vagrant 创建集群

如果是 vbox 或者是 VMware 的话,模拟一个集群方法就是多建几个虚机环境,然后打通内网,无论是 clone 还是新建都还挺麻烦的,但是 vagrant 靠一个配置文件就可以完成,这里直接引用 go-best-practice 里的这段话

Vagrant支持单机模拟多台机器,而且支持一个配置文件Vagrntfile就可以跑分布式系统。这种多机器模式特别适合以下几种人:

  • 快速建立产品网络的多机器环境,例如web服务器、db服务器
  • 建立一个分布式系统,学习他们是如何交互的
  • 测试API和其他组件的通信
  • 容灾模拟,网络断网、机器死机、连接超时等情况

现在我们来建立多台VM跑起來,並且让他们之间能够相通信,假设一台是应用服务器、一台是DB服务器,那么这个结构在Vagrant中非常简单,其实和单台的配置差不多,你只需要通过config.vm.define来定义不同的角色就可以了,现在我们打开配置文件进行如下设置:

Vagrant.configure("2") do |config|
config.vm.define :web do |web|
web.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--name", "web", "--memory", "512"]
end
web.vm.box = "base"
web.vm.hostname = "web"
web.vm.network :private_network, ip: "11.11.1.1"
end

config.vm.define :db do |db|
db.vm.provider "virtualbox" do |v|
v.customize ["modifyvm", :id, "--name", "db", "--memory", "512"]
end
db.vm.box = "base"
db.vm.hostname = "db"
db.vm.network :private_network, ip: "11.11.1.2"
end
end

这里的设置和前面我们单机设置配置类似,只是我们使用了:web以及:db分別做了两个VM的设置,并且给每个VM设置了不同的hostname和IP,设置好之后再使用vagrant up将虚拟机跑起来:

再次启动并连接,连接并需要指定角色即可

$ vagrant up

$ vagrant ssh web
vagrant@web:~$

$ vagrant ssh db
vagrant@db:~$

批量生成机器

上面的情况适合于想建立个小集群,用于特定的环境,而现在有个需求想一次性生成10台机器,用上面的方法就略显复杂了,得写一大串配置文件,显得臃肿,不过 vagrant 也提供了特定的方式

以下这个配置来源于 https://jacobustczhi.gitbooks.io/-vagrant/content/chapter.html

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://atlas.hashicorp.com/search.
(0..10).each do |i|

config.vm.define "node#{i}" do |node|

# 设置虚拟机的Box
node.vm.box = "ubuntu/trusty64"

# 设置虚拟机的主机名
node.vm.hostname="node#{i}"

# 设置虚拟机的IP
node.vm.network "public_network", bridge: "eno1", ip: "192.168.17.20#{i}"

# VirtaulBox相关配置
node.vm.provider "virtualbox" do |v|
v.name = "node#{i}"
v.memory = 1024
v.cpus = 1
end
end
if ARGV[0] == "up" && ! File.exist?("./disk1.vdi"
# 运行脚本增加swap空间
config.vm.provision "shell", path: "increase_swap.sh"
end
end
end

可以看到,与创建单个虚拟机相比,这里多了层循环,而变量 i 可以用于设置节点的名称与IP,使用#{i}取值:

(0..10).each do |i|

end

plugin

根据网友KiwenLau的文章里提到了一个错误

VirtualBox 设置共享目录时需要在虚拟机中安装VirtualBox Guest Additions,这个 Vagrant会自动安装。但是,VirtualBox Guest Additions是内核模块,当虚拟机的内核升级之后,VirtualBox Guest Additions会失效,导致共享目录挂载失败,出错信息如下:

Failed to mount folders in Linux guest. This is usually because
the “vboxsf” file system is not available. Please verify that
the guest additions are properly installed in the guest and
can work properly. The command attempted was:
mount -t vboxsf -o uid=id -u vagrant,gid=getent group vagrant | cut -d: -f3 vagrant /vagrant
mount -t vboxsf -o uid=id -u vagrant,gid=id -g vagrant vagrant /vagrant
The error output from the last command was:
stdin: is not a tty
/sbin/mount.vboxsf: mounting failed with the error: No such device

安装 Vagrant 插件vagrant-vbguest可以解决这个问题,因为该插件会在虚拟机内核升级之后重新安装VirtualBox Guest Additions

$ vagrant plugin install vagrant-vbguest

  

参考阅读