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

既然还在幸运的活着,当然要全力以赴的快乐。

“Vagrant uses Oracle’s VirtualBox to build configurable, lightweight, and portable virtual machines dynamically.”

Vagrant 是 Mitchell Hashimoto 用 ruby 写的,去年11月份,Mitchell 专门成立了一个公司 HashiCorp 来更好的开发 Vagrant, 并且申明,Vagrant会一直开源。Announcing HashiCorp
感兴趣的还可以看下作者在就HashiCorp成立在Hacker News上发的一个 topic

vagrant 是什么

Vagrant 提供了基于企业级标准技术的易配置、可重复、可移植的工作环境,从而最大化团队的生产力和灵活性。

Vagrant 可构建在由 VirtualBox,VMware,AWS 以及其他提供商提供的机器上,并且可以使用 shell 脚本,Chef,Puppet 等配置管理工具。

vagrant 的特点:

  • 将配置和依赖隔离在一次性和一致性的环境中
  • 使用简单,只需 Vagrantfile 和 vagrant up,适用人群广(开发者,运维人员,设计师)

vagrant 其实就是封装了的 Virtualbox 的 API 的 ruby DSL,抽象和简化了某些操作,用一个命令以及配置文件,而不是一堆命令去管理和使用 vm。

更多关于 vagrant 的介绍,网上比较多,这里就不在阐述,有兴趣的可以读一下 Go实战开发 这本书里关于 vagrant 的介绍,已经很详细了,我就简单的介绍点常用的即可

基础

1、基本命令

# 查看帮助
$ vagrant list-commands
-v, --version
-h, --help

# 把镜像加入到 vagrant 中
$ vagrant box add "centos-6.6-x86_64 py27" vagrantbox/centos-6.6-x86_64.box


# 查看 vagrant 环境
$ vagrant box list
centos-6.6-x86_64 py27 (virtualbox, 0)

# 初始化一个新的仓库
$ cd test_env
$ vagrant init "centos-6.6-x86_64 py27"
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

会在当前目录下生成一个 Vagrantfile 这个配置文件

2、下面贴个常见配置,修改 Vagrantfile 文件

config.vm.box = "centos-6.6-x86_64 py27"
config.vm.network "forwarded_port", guest: 8000, host: 8000
config.vm.network "forwarded_port", guest: 3306, host: 9999
config.vm.synced_folder ".", "/vagrant" # 将当前目录映射到虚拟机上的/vagrant 目录
config.vm.hostname = "devops-node1"

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"
vb.cpus = 1
end

3、服务管理

# 启动,重载,关机
$ vagrant up
$ vagrant reload
重新读取配置

$ vagrant halt
将虚拟机关闭,虚拟机内存释放,下次启动要慢一点。

$ vagrant suspend
将虚拟机挂起,虚拟机内存都保存到硬盘上,下次可以快速恢复

$ vagrant destroy
将虚拟机删除,所有变更都丢失,下次启动要重新克隆一个 Vagrant box。

$ vagrant status
查看虚拟机的状态

更多命令行:https://www.vagrantup.com/docs/cli/index.html

制作模板

当做好基础的环境后,方便打包发送给其他人和方便以此为模板衍生其他环境,所以需要对这个环境进行打包,形成模板

$ VBoxManage list vms
"win10" {f0fa02e2-48ca-439f-bfca-0e4ddb138485}
"centos6.5-node1" {57e5500f-e91b-469e-86c9-f0b90b2a01a8}
"env_default_1488966927566_38686" {16817773-c844-4412-af8d-df89bae489ca}

1、打包基础环境

$ vagrant package --base env_default_1488966927566_38686 --output centos66-base.box
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
==> env_default_1488966927566_38686: Attempting graceful shutdown of VM...
env_default_1488966927566_38686: Guest communication could not be established! This is usually because
env_default_1488966927566_38686: SSH is not running, the authentication information was changed,
env_default_1488966927566_38686: or some other networking issue. Vagrant will force halt, if
env_default_1488966927566_38686: capable.
==> env_default_1488966927566_38686: Forcing shutdown of VM...
==> env_default_1488966927566_38686: Clearing any previously set forwarded ports...
==> env_default_1488966927566_38686: Exporting VM...
==> env_default_1488966927566_38686: Compressing package to: /Users/song/Downloads/vagrant/env/centos66-base.box

2、还原基础环境

到此打包到封装好的环境就在当前目录下生成了,下次用这个模板重新开始初始化新环境就非常容易了

# 拷贝打包好的镜像到其他小伙伴的机器,或者共享目录
# 在本地导入并重新启动一个环境
$ vagrant box add "template_centos66" centos66-base.box
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'template_centos66' (v0) for provider:
box: Unpacking necessary files from: file:///Users/song/Downloads/vagrant/centos66-base.box
==> box: Successfully added box 'template_centos66' (v0) for 'virtualbox'!

$ vagrant box list
centos-6.6-x86_64 py27 (virtualbox, 0)
template_centos66 (virtualbox, 0)

$ mkdir test_env
$ cd test_env
$ rm -rf Vagrantfile
$ vagrant init template_centos66
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

$ vagrant up
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'template_centos66'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: test_env_default_1489043027159_6542
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...

3、测试完毕,销毁测试环境

$ vagrant destroy
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...

出现的错误

这里出现的错误主要在迁移的过程中,如果只是安装部署中出现错误,多数应该是配置文件Vagrantfile的语法错误,我这里先描述下错误出现的背景

– default: Warning: Authentication failure. Retrying…

1、当我打包一个系统镜像为模板的时候,想根据这个模板生成新的 vagrant 系统,所以有如下操作

$ vagrant package --base env_default_1488966927566_38686 --output centos66-base.box
$ vagrant box add "template_centos66" centos66-base.box
$ mkdir test_env
$ cd test_env
$ vagrant init template_centos66

适当修改 Vagrantfile,然后启动
$ vagrant up

如果一切正常,则会产生一个新的 vagrant 虚拟环境,但这里会报错

$ vagrant up
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Clearing any previously set forwarded ports...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 (guest) => 2200 (host) (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2200
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Authentication failure. Retrying...
default: Warning: Connection refused. Retrying...
default: Warning: Authentication failure. Retrying...
...

一直卡在这里无法过去,然后根据错误 google 找了下,在 vagrant 的 github 的 issue 里找到了有人提出了这个问题,根据里面的回答,我做了如下尝试

1、升级 vagrant 和 vbox ,确保都是最新版,怕有人提到的因为版本不匹配导致的原因,报错依旧

2、根据 @kikitux 这个哥们在 5 Mar 2015 的回答

Adding here my impressions for people that find this issue from google/internet:

This is my point of view here.

The source box use the insecure key
by default the actual version of vagrant will remove it, to make it secure
the new box, use a generated pair key.. that is not being used anymore
vagrant can’t connect to the new box.

You have 3 options here.

A. Tell vagrant in the middle box to NOT create a new safe/secure pair.
B. Run an Script before packaging to delete 70-persistent-net.rules
and put back the insecure pair key
C. Copy the new now secure pair to /vagrant and include it in the
package box plus Vagrantifle conf to use it

I will say, if this is for prototyping, just use A, just remember
delete 70-persistent-net.rules

On the first box, add:
config.ssh.insert_key = false

我在 Vagrantfile 里新增了config.ssh.insert_key = false这个配置,发觉无果,报错依旧

3、issue 上 @mtchavez 的回答得到了多数人的支持,很多人用了他的方法解决了问题

I had found a solution to this and haven’t had time to update this issue. I did something similar to what @dylanschoenmakers described.

The main thing which fixed it for me was adding the vagrant.pub to the authorized_keys with

wget https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub -O .ssh/authorized_keys
chmod 700 .ssh
chmod 600 .ssh/authorized_keys
chown -R vagrant:vagrant .ssh

Then when building the base box I think you need to add the config.ssh.insert_key = false to your Vagrantfile. If you built a new version of the box you can simply do a vagrant box update otherwise you can do what @dylanschoenmakers already mentioned to remove and re-add the box to get the newest box.

This all makes sense, but I am not clear on if this is something that needs to be documented or if there was indeed a change in Vagrant that used to do this transparently for previous versions which is broken now.

他其实做的方法和 @dylanschoenmakers 类似

a、首先在 Vagrantfile 中增加了这段
config.ssh.insert_key = false

b、其次在连接 vagrant 的 ssh-config 配置
$ vagrant ssh-config
/opt/vagrant/embedded/gems/gems/vagrant-1.9.2/lib/vagrant/util/platform.rb:24: warning: Insecure world writable dir /usr/local in PATH, mode 040777
Host default
HostName 127.0.0.1
User vagrant
Port 2200
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile /Users/song/.vagrant.d/insecure_private_key
IdentitiesOnly yes
LogLevel FATAL

这里的 IdentityFile 在基于模板创建新的 vagrant 虚机环境的时候 ssh 连接使用的 key,所以 @dylanschoenmakers 用了一个新的内容替换原有的内容

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key

c、再次重新打包环境

而我的解决方案并不和上述一样,我查看了下 ssh-config 配置

# 第一个正常连接的 vagrant 环境的配置
$ vagrant ssh-config

Host default
......
IdentityFile /Users/song/Downloads/vagrant/env_django/.vagrant/machines/default/virtualbox/private_key
......


# 登录异常的基于模板产生的 vagrant 环境
$ vagrant ssh-config

Host default
......
IdentityFile /Users/song/.vagrant.d/insecure_private_key
......

这里只贴出了不同的部分,所以我的想法就是把这个连接秘钥用正常环境的那个秘钥是否可以解决,所以在问题环境的 Vagrantfile 里增加如下配置

config.ssh.private_key_path = “/Users/song/Downloads/vagrant/env_django/.vagrant/machines/default/virtualbox/private_key”

再次启动虚拟环境,发觉再无报错,至此问题解决

另外好像还有个解决办法, 就是不指定用 key 连接,而是直接使用密码连接,虽然暴力,但是的确提供了一种思路

config.ssh.username = "vagrant"
config.ssh.password = "vagrant"

–warning: Insecure world writable dir /usr/local in PATH, mode 040777

曾经为了方便,改过 osx 下这个目录权限,现在操作 vagrant 都会报这个警告,修改权限如下即可

$ sudo chmod go-w /usr/local/

  

参考阅读