跳到正文

Development

从零开始创建自定义 Vagrant Box

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

阅读约需 5 分钟

我们首先来了解一下什么是“.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 中打包虚拟机需要更多手动操作。在终端中:

  1. 进入 vmwarevm 所在的位置。默认位置为 ~/Virtual Machines/。

  2. 右键单击 .vmwarevm 文件,选择 Show Package Contents

  3. 创建一个名为 metadata.json 的文件,并输入以下内容:

{"provider": "vmware_fusion"}
  1. 创建一个名为 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
  1. 接下来优化 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
  1. 最后压缩 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
分享