vagrant+virtualbox 构建mac虚拟机环境

vagrant+virtualbox 构建mac虚拟机环境

vagrant 简介

什么是vagrant

Vagrant是一个基于Ruby的工具,用于创建和部署虚拟化开发环境。它使用Oracle的开源VirtualBox虚拟化系统,使用 Chef创建自动化虚拟环境。

Vagrant的运行是需要依赖某个虚拟化平台的,如上面安装的virtualBox

它可以实现的功能有:

  • 建立和删除虚拟机
  • 配置虚拟机运行参数
  • 管理虚拟机运行状态
  • 自动配置和安装开发环境
  • 打包和分发虚拟机运行环境

在Vagrant体系中,有个box(箱子)的概念,这点类似于docker体系中的image(镜像)。基于同一个box,不同的人可以运行得到相同的内容

开始安装基础软件

主要安装以下三个软件

  • Vagrant 2.2 (brew cask install vagrant)
  • VirtualBox 6.0 (brew cask install virtualbox)
  • VirtualBox Guest Additions (vagrant plugin install vagrant-vbguest)
1
2
3
4
brew cask install vagrant
brew cask install virtualbox
vagrant plugin install vagrant-vbguest
brew install gnu-tar ## 增强型的打包工具GUN_TAR 可以不安装

自己制作cento7的镜像

第一步下载官方的centos7的镜像

1
wget https://cloud.centos.org/centos/7/vagrant/x86_64/images/CentOS-7-x86_64-Vagrant-2004_01.VirtualBox.box

centos 镜像下载页面: https://cloud.centos.org/centos/7/vagrant/x86_64/images/

下载完成后开始导入到vagrant中,导入完成后会有一个centos7-2004的box可以使用。

1
2
3
4
vagrant box add centos7-2004  CentOS-7-x86_64-Vagrant-2004_01.VirtualBox.box
## 查看导入的镜像
vagrant box list
centos7-2004 (virtualbox, 0)

init创建Vagrantfile 文件

1
vagrant init centos7-2004

编辑 Vagrantfile,执行base/common 的role来初始化系统。

1
2
3
4
5
6
7
8
Vagrant.configure("2") do |config|
config.vm.box = "centos7-2004"
config.vm.network "private_network", type: "dhcp"
config.vm.synced_folder ".", "/vagrant"
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end
1
2
3
4
5
6
7
8
cat playbook.yml
---
- hosts: all # All Vagrant VMs
vars:
become: yes
become_user: 'root'
roles:
- base/common

执行vagrant up 启动虚拟机

1
2
3
4
5
6
vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'centos7-2004'...
==> default: Matching MAC address for NAT networking...
...

vagrant ssh 登录机器,验证role的执行结果确认。

机器初始化完成。先关闭虚拟机: vagrant halt , 然后开始执行打包程序: vagrant package 将package的包作为一个模板,在模板只是执行相关命令。

基于模板的(package.tar)box,安装nginx 配置

第一步:先将打包完成的镜像导入。

1
vagrant box add centos7-init package.box

第二步:初始化配置文件

1
vagrant init centos7-init

编辑Vagrantfile,执行nginx 的role来安装nginx。

1
2
3
4
5
6
7
Vagrant.configure("2") do |config|
config.vm.box = "centos7-init"
config.vm.network "private_network", type: "dhcp"
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end
1
2
3
4
5
cat playbook.yml
---
- hosts: all # All Vagrant VMs
roles:
- nginx

vagrant up 启动nginx虚拟机
vagrant ssh 连接上服务器,确认服务器的ip和nginx服务是否正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:4d:77:d3 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
valid_lft 86183sec preferred_lft 86183sec
inet6 fe80::5054:ff:fe4d:77d3/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:ae:57:2e brd ff:ff:ff:ff:ff:ff
inet 172.28.128.9/24 brd 172.28.128.255 scope global noprefixroute dynamic eth1
valid_lft 382sec preferred_lft 382sec
inet6 fe80::a00:27ff:feae:572e/64 scope link
valid_lft forever preferred_lft forever
[root@localhost ~]# curl -I 127.0.01 ## 验证nginx服务是否正常。
HTTP/1.1 200 OK
Server: nginx/1.17.6
Date: Wed, 27 May 2020 03:46:09 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 27 May 2020 03:15:14 GMT
Connection: keep-alive
ETag: "5ecddb42-264"
Accept-Ranges: bytes

[root@localhost ~]#

在本机执行curl命令,确认nginx服务。

1
2
3
4
5
6
7
8
9
10
curl 172.28.128.9 -I
HTTP/1.1 200 OK
Server: nginx/1.17.6
Date: Wed, 27 May 2020 03:47:06 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Wed, 27 May 2020 03:15:14 GMT
Connection: keep-alive
ETag: "5ecddb42-264"
Accept-Ranges: byte

基于VBoxManage 打包box镜像

如果你想 将 virtualbox 中的虚拟机打包导入的vagrant的中,可以使用如下命令

  • 查询虚拟机名称: VBoxManage list vms
  • 指定虚拟机名称来创建 Box: vagrant package –base centos7 –output centos7.box
  • 添加创建的Box到Vagrant环境中: vagrant box add centos7 centos7.box
  • 初始化运行环境并设置Vagrantfile: vagrant init centos7
  • 使用Vagrant运行虚拟机,vagrant up
1
2
3
4
5
6
7
8
9
10
11
12
13
$ VBoxManage list vms
"centos7" {28ec4326-eb24-4fa6-b867-e49955e18c1d}

$ vagrant package --base centos7 --output centos7.box
==> centos7: Exporting VM...
==> centos7: Compressing package to: /Users/niu/centos7.box

$ vagrant box add centos7 centos7.box
==> box: Box file was not detected as metadata. Adding it directly...
==> box: Adding box 'centos7' (v0) for provider:
box: Unpacking necessary files from: file:///Users/niu/centos7.box
==> box: Successfully added box 'centos7' (v0) for 'virtualbox'!

通过vm.define 管理多个虚拟机

编辑Vagrantfile配置文件。增加 vm.define 的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Vagrant.configure("2") do |config|
config.vm.box = "centos7-init"

config.vm.define "nginx" do |nginx|
nginx.vm.hostname = "nginx-01"
nginx.vm.network "private_network", type: "dhcp"
nginx.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbooks/nginx.yml"
end
nginx.vm.provider "virtualbox" do |v|
v.name = "v-nginx-01" ##用来在virtualbox 定义标识名称,默认是随机名称
v.memory = 512
v.cpus = 1
end
end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
vagrant up nginx
Bringing machine 'nginx' up with 'virtualbox' provider...
==> nginx: Importing base box 'centos7-init'...
==> nginx: Matching MAC address for NAT networking...
==> nginx: Setting the name of the VM: jenkins-master
==> nginx: Clearing any previously set network interfaces...
==> nginx: Preparing network interfaces based on configuration...
nginx: Adapter 1: nat
nginx: Adapter 2: hostonly
==> nginx: Forwarding ports...
nginx: 22 (guest) => 2222 (host) (adapter 1)
==> nginx: Running 'pre-boot' VM customizations...
==> nginx: Booting VM...
==> nginx: Waiting for machine to boot. This may take a few minutes...
nginx: SSH address: 127.0.0.1:2222
nginx: SSH username: vagrant
nginx: SSH auth method: private key
==> nginx: Machine booted and ready!
[nginx] GuestAdditions 6.1.6 running --- OK.
==> nginx: Checking for guest additions in VM...
==> nginx: Setting hostname...
==> nginx: Configuring and enabling network interfaces...
==> nginx: Mounting shared folders...
nginx: /vagrant => /Users/niu/git/oschina/playbooks
==> nginx: Running provisioner: ansible_local...
nginx: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [nginx]

TASK [nginx : add nginx group] *************************************************
ok: [nginx]

TASK [nginx : add nginx user] **************************************************
ok: [nginx]

TASK [nginx : install lib] *****************************************************
ok: [nginx]

TASK [nginx : add nginx tar file to /usr/local/src] ****************************
changed: [nginx]

TASK [nginx : Extract nginx.tar.gz into /usr/local/src/] **********************
changed: [nginx]

TASK [nginx : install nginx] ***************************************************
changed: [nginx]

TASK [nginx : change nginx directory mode] *************************************
changed: [nginx]

TASK [nginx : link nginx] ******************************************************
changed: [nginx]

TASK [nginx : add nginx path] **************************************************
changed: [nginx]

TASK [nginx : create nginx configure directory] ********************************
changed: [nginx]

TASK [nginx : copy nginx z-default.conf configure file] ************************
changed: [nginx]

TASK [nginx : copy nginx gzip.conf configure file] *****************************
changed: [nginx]

TASK [nginx : copy nginx 1-logformat configure file] ***************************
changed: [nginx]

TASK [nginx : copy nginx z-default.conf configure file] ************************
changed: [nginx]

TASK [nginx : copy nginx service file] *****************************************
changed: [nginx]

TASK [nginx : nginx service state] *********************************************
changed: [nginx]

RUNNING HANDLER [nginx : reload nginx] *****************************************
changed: [nginx]

RUNNING HANDLER [nginx : reload systemd] ***************************************
ok: [nginx]

PLAY RECAP *********************************************************************
nginx : ok=19 changed=14 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
1
2
3
4
5
vagrant ssh nginx
Last login: Wed May 27 03:01:07 2020 from 10.0.2.2
[vagrant@nginx-01 ~]$ hostname
nginx-01
[vagrant@nginx-01 ~]$

补充 vagrant 常见命令

命令 参数
vagrant init <名称> 初始化box的操作
vagrant box list 显示当前已经添加的box列表
vagrant box add <虚拟机名> <box文件名> 添加box的操作
vagrant box remove 名称 删除相应的box
vagrant up 启动虚拟机的操作
vagrant halt 关机
vagrant destroy 停止当前正在运行的虚拟机并销毁所有创建的资源
vagrant ssh 登录拟机的操作,也可以指定hostname登陆
vagrant status 获取当前虚拟机的状态,也可以查看指定hostname
vagrant suspend 挂起当前的虚拟机
vagrant resume 恢复前面被挂起的状态
vagrant reload 重新启动虚拟机,主要用于重新载入配置文件
vagrant plugin 用于安装卸载插件
vagrant package 打包命令,可以把当前的运行的虚拟机环境进行打包
vagrant global-status 查看所有虚拟机的ID号
vagrant ssh-config 查看ssh登录信息,可以把这些信息 保存到.ssh文件下config中,先用vagrant ssh 登录,然后把宿主机的ssh公钥保存到虚拟机的authorized_keys文件里,然后在宿主机ssh <名称> 就可以免密码登录

报错汇总

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    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. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.

If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.

因为镜像是自己制作的,就导致了没法登录(默认使用公钥和私钥的方式)。

解决办法一:导入官方的镜像到配置文件中

1
sudo -u vagrant wget https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub -O   /home/vagrant/.ssh/authorized_keys

vagrant 仓库地址: https://github.com/hashicorp/vagrant/tree/master/keys

解决办法二:自定义使用自己配置的用户名和密码

1
2
config.ssh.username = "root"
config.ssh.password = "redhat"

按照插件提示超时

timed out (https://rubygems.org/specs.4.8.gz)

Source: https://rubygems.org/

解决办法:

1
2
3
4
5
6
7
8
$ gem update --system # 这里请翻墙一下
$ gem -v
2.6.3

$ gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
$ gem sources -l
https://gems.ruby-china.com
# 确保只有 gems.ruby-china.com

vagrant plugin install vagrant-vbguest –plugin-clean-sources –plugin-source https://gems.ruby-china.com/

参考文档

官方镜像站
如果你要其他系统的镜像,可以来这里下载
virtualbox+vagrant学习-1-环境安装及vagrantfile的简单配置-Mac系统
Vagrant入门
利用Ansible将开发环境纳入版本管理
centos7 virtualbox 镜像下载
国内开源镜像站
Vagrant搭建虚拟机集群
制作 Vagrant Box
使用vagrant和vitrualBox搭建虚拟开发环境
Vagrant快速入门