从零开始创建自定义 Vagrant Box
了解如何从零开始为 VirtualBox 和 VMware Fusion 构建自定义 Vagrant box。本文提供分步指南,涵盖从创建虚拟机到打包的全部流程,帮助你打造轻量、可复用、完全符合需求的开发环境。

我们首先来了解一下什么是“.box”文件。Vagrant 的“.box”文件其实就是一个经过 tar 打包并用 gzip 压缩的软件包,其中至少包含虚拟机的元数据文件、磁盘镜像以及一个 metadata.json 文件,后者用于标明该 box 是为哪个 provider 创建的。如有需要,还可以将其他可选的辅助文件(例如自定义的 Vagrantfile)一并打包进 box。
环境检查
先快速做个环境检查。本文的步骤已做了通用化处理,应该适用于大多数配置相近的宿主机(Host)和客户机(Guest)。但实际只测试过以下环境,因此不做任何明示或暗示的保证。
宿主机
本文假定使用 OS X 开发环境。除非另有说明,宿主机上的所有软件均为 OS X 版本。
- Apple OS X Mountain Lion (10.7.5)
- VirtualBox 4.2.12
- VMware Fusion 5.0.4
- Vagrant 1.2.2
- Vagrant 的 VMware Fusion provider 0.6.3(需有效许可证)。
可用的客户机
所有测试过的客户机均为 64 位 Linux 发行版。
- CentOS 6.4
- Debian 7.0
- Scientific Linux 6.4
- Ubuntu 12.10 Desktop
- Ubuntu 12.10 Server
创建虚拟机
首先启动虚拟化软件,创建一个作为 Vagrant box 基础的虚拟机。定义虚拟机时建议使用以下配置:
VirtualBox
在 VirtualBox 中新建虚拟机:
- 名称:vagrant-<distro><arch>,例如 vagrant-centos64
- 类型:Linux
- 版本:<distro> (64-bit)
- 内存大小:1024MB*
- 新建虚拟磁盘:
- 类型:VMDK(动态分配)
- 最大容量:40GB
修改虚拟机设置:
- 禁用音频
- 禁用 USB
- 确保网络适配器 1 设置为 NAT
- 按如下方式添加端口转发规则:
- 名称:SSH
- 协议:TCP
- 主机 IP:
- 主机端口:2222
- 子系统 IP:
- 子系统端口:22
- 挂载 Linux 发行版的 ISO
VMware Fusion
使用向导新建虚拟机:
- 选择“Continue without disc”
- 选择“Choose a disc or disc image…”
- 找到要安装的发行版 ISO,然后选择“Open”
- 取消勾选“Use Easy Install”
- 选择“Customize Settings”
- 为 VMware 文件输入名称,然后选择“Save”
自定义虚拟机设置:
- 开启共享文件夹(Shared Folders)
- 将网络更改为 Internet Sharing > Share with my Mac(即 NAT)
- 将磁盘大小改为 40 GB,并取消勾选“Split into 2GB files”
- 关闭声卡
- 关闭“Share Bluetooth devices with Linux”
安装客户机操作系统
启动虚拟机,安装客户机操作系统,并在出现提示时按如下方式设置:
- 主机名:vagrant-<distro><arch>
- Root 密码:vagrant
- 全名:vagrant
- 用户名:vagrant
- 密码:vagrant
配置客户机操作系统
以下是让客户机操作系统跑起来所需的最少步骤。我个人建议不要往 box 里塞非必要的额外内容,其他软件包可以交给配置管理(provisioning)工具来安装。这样你的基础 box 就可以在不同项目或团队之间复用。
更新 sudoers 文件
所有工作都将由 vagrant 用户替我们完成。vagrant 用户需要免密码的 sudo 权限,并且需要能在没有 tty(终端)的情况下运行。
由于大多数 Linux 发行版只将 root 用户加入 sudoers 组,我们必须把 vagrant 用户添加到 sudoers 文件中。这一步需要以 root 身份执行
$ su -
$ visudo
Ubuntu 发行版会把安装过程中创建的用户加入 sudoers 列表。虽然该用户已有 sudo 权限,我们仍需修改相关设置。
根据需要添加或修改以下几行:
Defaults:vagrant !requiretty
#Defaults !visiblepw
Defaults env_keep = "SSH_AUTH_SOCK"
vagrant ALL=NOPASSWD: ALL
保存更改并退出编辑器。如有必要,退出 root shell。现在 vagrant 用户应该可以无需密码使用 sudo 了。在终端中运行以下命令进行验证:
$ sudo pwd
更新软件包
建议此时更新已安装的软件包。
RHEL6
$ sudo yum update -y
Debian
$ sudo apt-get upgrade -y
更新完成后,重启虚拟机以确保更新正确生效。在终端中运行以下命令可立即重启虚拟机:
$ sudo shutdown -r now
下载 Vagrant 的不安全密钥
vagrant 用户将使用 SSH 密钥获得访问 box 的授权。
$ mkdir -p /home/vagrant/.ssh
$ chmod 0700 /home/vagrant/.ssh
$ wget --no-check-certificate
https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub
-O /home/vagrant/.ssh/authorized_keys
$ chmod 0600 /home/vagrant/.ssh/authorized_keys
$ chown -R vagrant /home/vagrant/.ssh
安装并配置 OpenSSH Server
vagrant 用户将通过 SSH 访问和配置 box。
RHEL6
$ sudo yum install -y openssh-server
$ sudo chkconfig sshd on
Debian
$ sudo apt-get install -y openssh-server
编辑并更新 OpenSSH Server 的配置。
$ sudo vi /etc/ssh/sshd_config
添加或修改以下几行:
Port 22
PubKeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
PermitEmptyPasswords no
PasswordAuthentication no
保存并退出文件。重启 SSH 服务。
RHEL6
$ sudo service sshd restart
Debian
$ sudo service ssh restart
安装客户机工具
虚拟机客户机工具可以提升性能,并改善对客户机操作系统的管理。Vagrant 也会借助客户机工具在宿主机和客户机操作系统之间创建共享目录。
在安装 Guest Additions 或 VMware Tools 之前,我们需要先安装额外的开发包,以便这些工具能够正确编译和安装。
RHEL6
$ sudo yum install -y gcc make kernel-devel
Debian
# Server
$ sudo apt-get install -y gcc build-essential linux-headers-server
# Desktop
$ sudo apt-get install -y gcc build-essential linux-headers-$(uname -r)
接下来为我们的虚拟机软件安装客户机工具。
VirtualBox
首先挂载 Guest Additions。在菜单栏中选择 Devices > Install Guest Additions…。
$ cd /media/VBOXADDITIONS_4.2.12_84980
$ sudo ./VBoxLinuxAdditions.run
$ sudo umount /media/VBOXADDITIONS_4.2.12_84980 | cd ~
VMware Fusion
首先在菜单栏中选择 Virtual Machines > Install VMware Tools,挂载 VMware Tools。
$ sudo mkdir -p /mnt/cdrom
$ sudo mount /dev/cdrom /mnt/cdrom
$ tar xzvf /mnt/cdrom/VMwareTools-9.2.2-893683.tar.gz -C /tmp
$ cd /tmp/vmware-tools-distrib/
$ sudo ./vmware-install.pl
清理
在打包 box 之前,我们需要对其进行清理,以尽量减小体积。
RHEL6
$ sudo yum clean all
确认虚拟机状态满意后,将其关机,准备打包。
$ sudo shutdown -h now
打包 box
打包虚拟机将生成前文所述的 .box 文件。
VirtualBox
Vagrant 会在执行 vagrant package 命令的目录中创建 .box 文件。如果你希望将 box 创建在特定位置,应在运行 vagrant package 命令之前切换到该目录。下面的示例中,我们打包的是一个 CentOS 客户机。
$ mkdir -p ~/workspace/centos64/
$ cd ~/workspace/centos64/
$ vagrant package --base vagrant-centos64
VMware Fusion
在 VMware Fusion 中打包虚拟机需要更多手动操作。在终端中:
进入 vmwarevm 所在的位置。默认位置为 ~/Virtual Machines/。
右键单击 .vmwarevm 文件,选择 Show Package Contents
创建一个名为 metadata.json 的文件,并输入以下内容:
{"provider": "vmware_fusion"}
- 创建一个名为 Vagrantfile 的文件,并输入以下内容:
# -*- mode: ruby -*-
# vi: set ft=ruby
Vagrant.configure("2") do |config|
config.vm.provider :vmware_fusion do |v, override|
v.gui = true
end
end
- 接下来优化 box 以减小其体积:
$ /Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager -d Virtual Disk.vmdk
$ /Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager -k Virtual Disk.vmdk
- 最后压缩 box:
$ tar cvzf package.box ./*
测试启动 box
$ vagrant box add testbox package.box
$ vagrant init testbox
$ vagrant up
如果 box 创建成功,vagrant up 将输出以下内容。
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'testbox'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Configuring and enabling network interfaces...
[default] Mounting shared folders...
[default] -- /vagrant
要从宿主机登录客户机,可以运行:
$ vagrant ssh