一、Vagrant 介绍
Vagrant 是一个软件,可以自动化虚拟机的安装和配置流程,用来管理虚拟机,如 VirtualBox、VMware、AWS 等目前市面上个人 PC 的主流操作系统不是Windows 就是 MacOS。对于这些用户,如果需要用 Linux 环境进行开发或学习,使用虚拟机无疑是最方便的选择。主要好处是可以提供一个可配置、可移植和复用的软件环境,可以使用 shell、chef、puppet 等工具部署。所以 vagrant 不能单独使用,如果你用它来管理自己的开发环境的话,必须在自己的电脑里安装了虚拟机软件,如 virtualbox。
更进一步,Vagrant 提供一个命令行工具 vagrant,通过这个命令行工具可以直接启动一个虚拟机,当然你需要提前定义一个 Vagrantfile 文件,这有点类似Dockerfile 之于 docker了。可以通过编写一个 Vagrantfile 来控制虚拟机的启动、虚拟机网络环境的配置、虚拟机与主机间的文件共享,以及启动后自动执行一些配置脚本,比如自动执行一个 shell script 来安装一些必备的开发工具,如Mysql。这意味着,当你需要在多台机器间同步开发进度时,只需要同步Vagrantfile,就可以保证各台机器拥有一致的开发环境。另外,即便对于计算机小白用户,Vagrant也是一个利器。以前我们为了学习一门语言,必须先手动安装这门语言的编译环境。有了 Vagrant后,我们可以下载别人写好的 Vagrantfile,然后运行 vagrant up,vagrant 就会自动下载虚拟机镜像,自动加载镜像并配置虚拟机,然后交给我们一个即开即用的学习环境。
二、 安装与使用
Vagrant 既然是配置虚拟机,那么自然需要虚拟机程序和被虚拟的操作系统镜像(Image)。前者常用的选择有 VirtualBox 和 VMWare,后者则包括 Ubuntu、FreeBSD 等等。Vagrant 称前者为 provider,称后者为 box。原则上,我们可以自由搭配 provider 和 box,但由于 VirtualBox 开源且免费,Vagrant将其作为默认的 provider。所以,一般会先安装 VirtualBox,再安装Vagrant。
我这里在 mac 上做测试,直接使用官方的安装包来安装 Vagrant
https://www.vagrantup.com/downloads.html
使用 VirtualBox
本文将使用 VirtualBox 作为虚拟机管理器(providers),因为它是免费的、适用于各大平台,且在 Vagrant 已集成。
可以通过下面的命令启动运行一个虚拟机
$ vagrant init hashicorp/precise32
$ vagrant up
在执行以上两条命令后, 将拥有一台运行在 VirtualBox 下的 Ubuntu 12.04 LTS 32位 虚拟机。 我们可以通过 vagrant ssh
命令来 SSH 登录到这台虚拟机上,当用完以后,可以通过 vagrant destroy
命令来销毁所有的使用痕迹。
项目建立
在创建使用 Vagrant 的第一步,就是对 Vagrantfile 配置文件进行配置。Vagrantfile 配置文件的作用有两个方面:
设置项目的根目录,很多 Vagrant 的配置都是与根目录有紧密关系。
指定在项目中所需的虚拟机类型及资源,例如需要安装哪些软件以及在哪里可以访问到这些资源。
Vagrant 有一个内置的命令来初始化一个目录作为 Vagrant 项目的根目录: vagrant init
$ mkdir vagrant
$ cd vagrant
$ vagrant init
上面这些命令会创建一个 Vagrantfile 文件在当前的目录,可以打开 Vagrantfile 配置文件查看一下,内容包含了注释说明及实例。
也可以在已存在的项目目录中执行 vagrant init 命令,来设置一个已存在的项目
Boxes
Vagrant 是通过基础镜像包来实现快速克隆创建虚拟机的。这些基础镜像包在 Vagrant 中被称为 boxes , 而在创建 Vagrantfile 文件后的第一件事情就是指定 Vagrant 环境使用哪一个 Box。
$ vagrant box add hashicorp/precise32
Boxes 是通过 vagrant box add 命令来添加到 Vagrant 中的。这将从 HashiCorp's Atlas box catalog 这个专门用来存放 boxes 的地方下载一个名叫 "hashicorp/precise32" 的 box。不但可以从 HashiCorp's Atlas 下载 boxes,其外还可以从本地文件、自定义 URL 等方式添加 boxes。
已经添加了的 boxes 可以被多个项目重复使用。每个项目其实是从 box 克隆并初始化出一个镜像,不会对原有的 box 基础镜像进行任何修改。所以,当两个项目都使用了 hashicorp/precise32
这个 box,在其中一个项目虚拟机中添加了文件,不会对另外一个项目中的虚拟机造成任何影响。
上面可以看到已经将 box 添加到了 Vagrant 中,我们需要对我们的项目进行配置,才能将这个项目作为我们今后的基础环境。打开 Vagrantfile 文件,对其内容依照以下进行编辑:
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise32"
end
"hashicorp/precise32" 这个名字必须和你前面添加进去的 box 名称相同。 Vagrant 是根据这个名字去判断进行哪种操作的。如果你之前没有添加过 box,当你运行 Vagrant 时它会根据这个名字自动下载并添加该 box 进来。
启动和登录
启动使用如下命令:
$ vagrant up
一分钟之内,这个命令会执行完毕,我们将拥有一个运行 Ubuntu 的虚拟机。但是我们无法真实地看到任何变化,因为 Vagrant 在运行时没有提供 UI 界面。为了证实 Vagrant 已经正确地运行,你可以通过 SSH 登录到虚拟机中查看:
刚开始启动我的一直有报错如下:
后面查阅资料貌似是一个bug,我将本地的virtualbox 升级到 5.2.18 之后,重启reload 解决
$ vagrant ssh
这个命令会进入一个完整的 SSH 会话,可以继续与虚拟机进行交互,也可以进行任何你想做的操作。虽然这个环境可能是临时的,但轻易不要执行 rm -rf / 命令,因为 Vagrant 共享了一个 /vagrant 目录,这个目录是存放在宿主机上的(具体在宿主机在哪个路径是由 Vagrantfile 文件中设置的),如果执行了这个命令,也将删除了宿主机上的这个目录。当这台虚拟机不想再使用的时候, 在宿主机器上执行 vagrant destroy 命令,Vagrant 就会删除所有数据及痕迹。
vagrant ssh $name ,如果主机上就一个vagrant可以不指定名字。默认进入的用户是vagrant。
与宿主机同步目录
默认情况下,Vagrant 共享项目根路径(注意,这个可在 Vagrantfile 中配置)到你宿主机的 /vagrant 目录中。 再次执行 vagrant up 命令,SSH 登录到虚拟机中查看,发现与宿主机的 vagrant 根目录相同:
再次 touch 文件 验证:
因此,Vagrant 是保持了虚拟机与宿主机间这个目录的同步的。
有了 /Vagrant 这个同步目录,我们可以继续在宿主机上使用惯用的编辑器进行开发,文件则会自动同步至虚拟机中。
Provision 软件安装
这一步相当于自动执行“安装各类软件”、“调整系统设置”等步骤。其实,这一步的操作结果可以被打包到 box 中,从而完全避免 Provision。比如,我们既可以在Provision 中安装Python,也可以直接将一个已经安装好 Python 的系统打包为box,然后使用该 box 创建虚拟机。两种方式各有优劣,显然前者更灵活、更轻量。毕竟,不是所有打包到box中的功能都为用户所需。使用 Provision 可以最大限度的“按需定制”。
在这一步,Vagrant会可能需要调用第三方的 Provision System,比如Chef、Puppet。而最基本的Provision可以通过shell script来指定,反映在Vagrantfile中,便是如下的代码:
Vagrant.configure("2") do |config|
...
config.vm.provision "shell", inline: "echo Hello, World"
config.vm.provision "shell", path: "script.sh"
...
end
其中,inline表示script直接写在Vagrantfile中,而path则表示script被写在指定的文件中。
Provision可以说是自动装机的核心步骤,Vagrant则提供了一个方便的接口。
可以在 Vagrantfile 中定义要安装的软件和操作,例如我们安装 Apache。
在与Vagrantfile同级的目录下创建一个bootstrap.sh文件。
#!/usr/bin/env bash
apt-get update
apt-get install -y apache2
if ! [ -L /var/www ]; then
rm -rf /var/www
ln -fs /vagrant /var/www
fi
然后在 Vagrantfile 中使用它。
Vagrant.configure("2") do |config|
config.vm.box = "hashicorp/precise64"
config.vm.provision :shell, path: "bootstrap.sh"
end
"provision" 这一行告诉 Vagrant 使用 shell provisioner 去启动机器并使用bootstrap.sh。
加入
config.vm.network :forwarded_port, guest: 80, host: 4567
可以做网络端口转发,然后执行 vagrant reload 或者 vagrant up 可以生效。如果之前已经在 running了,则使用 vagrant reload --provision 可以快速 restart 而跳过 initial。
访问本地的 4567 端口,可以看到之前写进脚本的均已成功显示:
Share
我们做的 vagrant 是可以分享给别人的用的,只要有一个 hashicorp 账号,vagrant login 后就可以执行 vagrant share 分享,会生成一个 URL,其它人也可以访问到你的 vagrant 里的服务。
如果有了账号,我们就可以通过 vagrant login 进行登录
$ vagrant login
Username or Email: mitchellh
Password (will be hidden):
You're now logged in!
可以通过 vagrant share 来分享
$ vagrant share
...
==> default: Your Vagrant Share is running!
==> default: URL: http://frosty-weasel-0857.vagrantshare.com
...
可以通过 Ctrl+C 来中止。
中止
vagrant suspend
Vagrant halt
Vagrant destroy
三、网络
vagrant 提供了三种网络配置方式:端口转发(默认)、私有网络、公有网络,可以在配置文件 Vagrantfile 进行网络配置,推荐使用私有网络。
端口转发(forwarded ports)
1 .定义
端口转发指把宿主机的端口映射到虚拟机的某一个端口上,访问宿主机端口时,请求实际是被转发到虚拟机上指定端口的。
注:宿主机指运行虚拟机的物理机。
2 .优点
- 容易实现外网访问虚拟机
3 .缺点
- 如果端口较少需要映射很容易,但是端口比较多时,就比较麻烦,例如:MySQL,redis,nginx等服务。
- 不支持在宿主机使用小于1024的端口来转发,例如:不能使用SSL的443端口来进行https连接。
4 .配置
在配置文件Vagrantfile下做如下编辑
Vagrant.configure("2") do |config|
config.vm.network
"forwarded_port"(必须) //端口转发标识
, guest(必须): //虚拟机端口
, host(必须): //宿主机端口,值必须大于1024
,guest_ip(可选): //虚拟机端口绑定虚拟机ip地址
,host_ip(可选): //虚拟机端口绑定宿主机ip
,protocol(可选)://指定通信协议,可以使用tcp/udp,默认tcp
,auto_correct(可选)://true/false,若配置为true,则每次开启虚拟机的时候自动检查是否存在端口冲突
end
注:若guest_ip和host_ip两项配置为空,则局域网下的所有设备都可以访问该虚拟机。
示例配置,如下:
Vagrant.configure("2") do |config|
config.vm.network "forwarded_port", guest: 80, host: 8080,
auto_correct: true
end
访问宿主计算机8080端口的请求都转发到虚拟机的80端口上进行处理。
私有网络(private networks)
1 .定义
私有网络是指只有宿主机可以访问虚拟机,如果多个虚拟机设定在同一个网段也可以互相访问。
2 .优点
- 安全,只有自己可以访问
3 .缺点
- 团队成员不能访问你的虚拟机
4 .配置
使用私有网络的最简单方法是允许通过DHCP分配IP。
Vagrant.configure("2") do |config|
config.vm.network "private_network", type: "dhcp"
end
这将自动从保留的地址空间分配IP地址。 可以通过使用 vagrant ssh 将 SSH 连接到计算机并使用适当的命令行工具查找 IP(例如ifconfig)来确定 IP 地址。
还可以为计算机指定静态IP地址。 可以使用已知的静态 IP 访问 Vagrant 受管计算机。 配置如下:
config.vm.network
"private_network"//必须 ,私有网络标识
, ip: "192.168.33.10"
注:私有ip可以自行指定
如果您想自己手动配置网络接口,可以通过指定auto_config来禁用Vagrant的自动配置功能:
Vagrant.configure("2") do |config|
config.vm.network "private_network", ip: "192.168.50.4",
auto_config: false
end
公有网络(public networks)
1 .定义
公有网络是指设置虚拟机和宿主机有相同的网络配置。
2 .优点
- 方便团队协作,别人可以访问你的虚拟机
3 .缺点
- 只有在有网络的情况下才能访问虚拟机
4 .配置
Vagrant.configure("2") do |config|
config.vm.network
"public_network" //必须 公有网络标识
,ip(string): //可选,配置静态ip
,bridge(string/array): "en1: Wi-Fi (AirPort)"//可选,设置桥接的网卡
end
四、分布式环境
我们可以在 Vagrantfile 里使用 config.vm.define 方法定义多个主机:
Vagrant.configure("2") do |config|
config.vm.provision "shell", inline: "echo Hello"
config.vm.define "web" do |web|
web.vm.box = "apache"
end
config.vm.define "db" do |db|
db.vm.box = "mysql"
end
end
如上,config.vm.define 采用定义一个变量的块。 此变量(如上面的web)与config 变量完全相同,只是内部变量的任何配置仅适用于正在定义的计算机。 因此,web 上的任何配置都只会影响 web 计算机。也可以继续使用 config 对象。 config 对象在特定于机器的配置之前加载和合并。使用这些范围时,配置程序等事务的执行顺序变得很重要。 Vagrant 按照 Vagrantfile 中列出的顺序强制执行从外到内的排序。 例如,使用下面的 Vagrantfile,输出顺序为 "A", "C", "B"
Vagrant.configure("2") do |config|
config.vm.provision :shell, inline: 'echo A'
config.vm.define :testing do |test|
test.vm.provision :shell, inline: 'echo B'
end
config.vm.provision :shell, inline: 'echo C'
end
当在 Vagrantfile 中定义了多台计算机时,各种 vagrant 命令的使用会略有变化。
仅针对单个机器有意义的命令(例如 vagrant ssh)现在需要控制机器的名称。例如上面的例子,需要使用 vagrant ssh web 或 vagrant ssh db。
默认情况下,其他命令(例如 vagrant up)在每台机器上运行。因此,如果vagrant up ,Vagrant 会启动 web 和 db 机器。也可以选择具体启动 vagrant up web 或 vagrant up db。此外,也可以指定正则表达式以仅匹配某些计算机。
另外,可以使用自动启动设置允许告知 Vagrant 不启动特定计算机。 例:
config.vm.define "web"
config.vm.define "db"
config.vm.define "db_follower", autostart: false
当使用上述设置运行 vagrant 时,Vagrant 将自动启动 "web" 和 "db" 机器,但不会启动 "db_follower" 机器。 可以通过运行 vagrant up db_follower 来手动强制 "db_follower" 计算机启动。
可以指定主计算机。 主计算机将是未指定分布式环境中的特定计算机时使用的默认计算机。要指定默认计算机,只需在定义时将其标记为主计算机。 只能指定一台主机。
config.vm.define "web", primary: true do |web|
# ...
end
Push
从版本1.7开始,Vagrant 能够将与 Vagrantfile 相同的目录中的应用程序代码部署或“推送”到远程数据库(如FTP服务器或HashiCorp的Atlas)。
推送的定义在应用程序的 Vagrantfile 中定义,并使用 vagrant push 子命令调用。 与 Vagrant 的其他组件非常相似,每个 Vagrant Push 插件都有自己的配置选项。 有关更多信息,请参阅Vagrant Push插件的文档。 以下是Vagrantfile中的Vagrant Push配置部分示例:
config.push.define "ftp" do |push|
push.host = "ftp.company.com"
push.username = "..."
# ...
end
当应用程序准备好部署到FTP服务器时,只需运行一个命令:
vagrant push
与 Vagrant Providers 非常相似,Vagrant Push也支持多个后端声明。 考虑staging 和 QA 环境的常见情况:
config.push.define "staging", strategy: "ftp" do |push|
# ...
end
config.push.define "qa", strategy: "ftp" do |push|
# ...
end
在这种情况下,用户必须将 Vagrant Push 的名称传递给子命令:
vagrant push staging
参考:
https://www.vagrantup.com/docs/
https://jimmysong.io/posts/vagrant-intro/
https://www.jianshu.com/p/050b0a4468c4