Vagrant 镜像制作与共享
镜像制作
有三种方式可以生成镜像文件:
- 将本地仓库中的镜像重新打包。由于只需要本地仓库,跟 Vagrant 项目没关系,这个命令不必在项目目录下,也不需要停任何虚拟机:
vagrant repackage
- 将一个 Vagrant 项目的虚拟机重新打包。这是基于某个项目的修改,需要停止该项目虚拟机并到该项目下执行命令:
vagrant package
- 从头开始制作一个新的镜像
事实上,万能的开源社区已经打造了一个强大的镜像制作工具 VeeWee ,支持定制虚拟机模板,自动安装系统并打包产生镜像。但无论如何,工具只是重复手工劳动的替代品,虽然已经省事,但要用得明白,所以还是需要了解一些内幕,比如镜像文件格式和虚拟机约定。
镜像文件格式
镜像文件只不过是一个伪装成 .box 、多塞入两个描述文件的 OVA 包而已,打包格式是 tar 并可能启用了 gzip 压缩。约定的目录结构是
$ tar ztf package.box
./box-disk1.vmdk # 虚拟机的磁盘文件
./box.ovf # OVF 描述文件,在这里定义虚拟机规格并引用磁盘文件
./Vagrantfile # 可能包含一些镜像相关的配置
./metadata.json # {"provider":"virtualbox"}
所谓的 OVA 就是 OVF 描述文件和它引用的虚拟磁盘文件合起来的 tar 包。考虑到不便从 OVF 描述文件中判断该虚拟机的管理器,还需要支持容器虚拟化技术, Vagrant 增加了一个 metadata.json
来跟踪虚拟机管理器。随镜像附带的 Vagrantfile 在不同管理器之间共享一段配置提供了方便,也可以预置一些镜像相关的项。
虚拟机约定
毫无疑问, Vagrant 的便利性需要虚拟机实例遵守一些约定(第 3 和 4 项假设 Linux 或者 Cygwin Windows ,若是 rdp Windows ,可以参考这里):
- 尽量裁剪系统,去掉音频和 USB 等没用的部件,减少虚拟磁盘和镜像的大小
- 虚拟机用最低配置,因为 Vagrant 支持在虚拟机启动前修改配置
- 虚拟机必须提供支持公钥登陆的 SSH 服务,且预装 SSH 公钥到
config.ssh.username
约定的 SSH 帐号下(默认是vagrant
),而宿主机上相应的私钥位置则由config.ssh.private_key_path
指定,默认是VAGRANT_HOME/insecure_private_key
- 这个 SSH 帐号必须拥有无密码 sudo ALL 权限,用于虚拟机启动后登入执行改主机名、provision 等操作
- 虚拟机中必须安装 VirtualBox Guest Additions ,用于支持目录共享,因为 provision 配置和项目代码都是在共享目录中的
-
删除一些捣乱的 udev 记录
$ rm /etc/udev/rules.d/70-persistent-net.rules $ mkdir /etc/udev/rules.d/70-persistent-net.rules $ rm -rf /dev/.udev/ $ rm /lib/udev/rules.d/75-persistent-net-generator.rules
如果 3 中采用默认帐号和官方公开密钥对的话,那么虚拟机中的操作是:
$ mkdir /home/vagrant/.ssh
$ chmod 700 /home/vagrant/.ssh
$ cd /home/vagrant/.ssh
$ curl -o authorized_keys \
'https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub'
$ chmod 600 /home/vagrant/.ssh/authorized_keys
$ chown -R vagrant /home/vagrant/.ssh
如果采用了自定义的账号,那么最好在随镜像附带的 Vagrantfile 中注明。
然后关闭虚拟机,执行下面的命令打包
vagrant package --base VirtualBoxGUI中显示的虚拟机名 [--vagrantfile 预置帐号的配置文件]
镜像仓库
制作完镜像,是时候分享了。
从使用者角度看, vagrant 会先查找本地仓库 VAGRANT_HOME/boxes
中是否有给定的镜像文件,没有的话就尝试下载远程镜像。此外,如果虚拟机是从远程镜像产生,那么 vagrant box outdated
命令会立即检查远程镜像是否有新版本,或者,在缺省配置下 config.vm.box_check_update = 1
,vagrant up
启动虚拟机时也会检查新版本。不过,检查版本并不会下载更新,而是需要 vagrant box update
来执行操作。
在获取镜像时,按 box_url 的不同风格,有不同的行为
box_url 示例 行为
shorthand hashicorp/precise64 用 VAGRANT_SERVER_URL 补全的镜像路径
如 https://vagrantcloud/hashicorp/precise64
name centos65 项目目录下的镜像
file:// 本地镜像路径
http(s):// 远程镜像路径
注意,只有镜像命名为 shorthand 方式,即 hashicorp/precise64
这种没有明确指定协议且名字中间带 / 字符的情况,才会从 VAGRANT_SERVER_URL
定义的远程仓库中查找。但不论是 shorthand 方式还是明确指定路径,最终都会获得一个镜像 URL ,然后可能有两种情况:这个 URL 指向镜像元数据文件,或者,指向镜像文件本身。
镜像元数据是本地 JSON 文件或者 application/json 格式的 HTTP 响应,由 box_metadata.rb 负责解析。若元数据是磁盘中的 JSON 文件,vagrant 会尝试用 JSON 解析器加载文件;完整的元数据请求响应交互,则可以参考这里。镜像元数据 JSON 内容说明如下:
{
"description": "...", # 必选,较长的镜像介绍
"short_description": "...", # 简短的介绍
"name": "owner/box" # 必选, shorthand 镜像名
"versions": [
{
"version": "x.y.z", # 必选,版本号
"status": "active",
"description_html": "...", # 格式的版本说明
"description_markdown": "...", # MarkDown 格式的版本说明
"providers": [
{
"name": "virtualbox", # 必选,虚拟机管理器
"url": "https://..." # 必选,镜像文件的完整路径
"checksum": "..."
"checksum_type": "MD5|SHA1|SHA2" # box_add.rb:validate_checksum
}
]
},
]
}
那么,远程仓库的维护可以有两种方式:虽然都在远程存储按版本组织镜像,但可以由用户自行维护版本号和镜像文件路径的映射关系,或者,由镜像的元数据来维护映射关系,而用户只需要知道固定的元数据路径和镜像版本号即可。从可维护性角度看,推荐第二种方式。也就是说,
- 镜像仓库需要支持
application/json
格式响应VAGRANT_SERVER_URL/owner/box
元数据请求 - 镜像仓库需要提供文件下载
- 用户设定
VAGRANT_SERVER_URL
指向镜像仓库根路径,然后vagrant init owner/box
即可引用镜像
让我们来回顾一下最初的设想:用户可以迅速获得一个环境,方便地在不同环境之间切换,完全不用担心环境维护,一切都在版本控制系统中。这,就是 Vagrant 带来的变革,它不仅仅是一个工具。