### 使用 Vagrant 管理虚拟机
> In 1974 computers were oppressive devices in far-off air-conditioned places. Now you can be oppressed in your own living room.
>
> — Ted Nelson
虽然能够在云中部署虚拟机是一个创举,但若能将虚拟机运行在你自己的桌面系统中有时甚至是更方便的, 尤其对于测试来说更是如此。如果每个开发者都有一个克隆自生产系统的运行在自己机器上的虚拟机, 那么实际部署时就不太可能遇到问题。 同样地,每个系统管理员也可以在私人的虚拟机上测试配置管理的变化, 这是一种使错误配置实际影响客户之前捕捉错误的良好方式。
几年前出现的工具(如 VirtualBox 或 VMware)就已经能在桌面系统上创建虚拟机。 然而,**Vagrant** 的到来使桌面云技术真正实现了起飞,它是一个管理和供应虚拟化环境的自动化工具。 Vagrant 是 VirtualBox 的前端工具,它驱动 VirtualBox 实现自动创建虚拟机的过程, 并使用自动化管理配置工具(Chef 或 Puppet)为虚拟机调配所需的资源, 设置网络,端口转发,以及对运行着的虚拟机打包生成映像文件以便其他人使用。
你可以使用 Vagrant 管理你用于开发目的虚拟机,这些虚拟机既可以运行在你自己的桌面上, 也可以运行在一台共享的机器上,比如一台持续集成服务器(Continuous Integration Server)。 例如,你可以使用像 **Jenkins** 那样的 CI 工具启动一个由 Vagrant 管理的虚拟机, 部署你的应用程序,然后在虚拟机里运行测试实验,就好像是在生产环境中一样。
#### 操作步骤
1. 创建一个 vagrant 模块:
```
# mkdir /etc/puppet/modules/vagrant
# mkdir /etc/puppet/modules/vagrant/manifests
# mkdir /etc/puppet/modules/vagrant/files
```
2. 使用如下内容创建 /etc/puppet/modules/vagrant/manifests/init.pp 文件:
```
class vagrant {
$virtualbox_deps = [ "libgl1-mesa-glx",
"libqt4-network",
"libqt4-opengl",
"libqtcore4",
"libqtgui4",
"libsdl1.2debian",
"libxmu6",
"libxt6",
"gawk",
"linux-headers-${kernelrelease}" ]
package { $virtualbox_deps: ensure => installed }
exec { "download-virtualbox":
cwd => "/root",
command => "/usr/bin/wget http://download.virtualbox.org/
virtualbox/4.1.0/virtualbox-4.1_4.1.0-73009~Ubuntu~lucid_
i386.deb",
creates => "/root/virtualbox-4.1_4.1.0-73009~Ubuntu~lucid_
i386.deb",
timeout => "-1",
}
exec { "install-virtualbox":
command => "/usr/bin/dpkg -i /root/virtualbox-4.1_4.1.0-
73009~Ubuntu~lucid_i386.deb",
unless => "/usr/bin/dpkg -l |/bin/grep virtualbox-4.1",
require => [ Exec["download-virtualbox"],
Package[$virtualbox_deps] ],
}
$vagrant_deps = [ "build-essential",
"rubygems" ]
package { $vagrant_deps: ensure => installed }
exec { "install-rubygems-update":
command => "/usr/bin/gem install -v 1.8.6 rubygemsupdate",
unless => "/usr/bin/gem -v |/bin/grep 1.8.6",
require => Package["rubygems"],
}
exec { "run-rubygems-update":
command => "/var/lib/gems/1.8/bin/update_rubygems",
unless => "/usr/bin/gem -v |/bin/grep 1.8.6",
require => Exec["install-rubygems-update"],
}
package { "vagrant":
provider => gem,
ensure => installed,
require => [ Package["build-essential"],
Exec["runrubygems-update"] ],
}
define devbox( $vm_user ) {
include vagrant
$vm_dir = "/home/${vm_user}/${name}"
file { [ $vm_dir,
"${vm_dir}/data" ]:
ensure => directory,
owner => $vm_user,
}
file { "${vm_dir}/Vagrantfile":
source => "puppet:///modules/vagrant/devbox.
Vagrantfile",
require => File[$vm_dir],
}
}
}
```
3. 使用如下内容创建 /etc/puppet/modules/vagrant/files/devbox.Vagrantfile 文件:
```
Vagrant::Config.run do |config|
config.vm.box = "lucid32"
config.vm.box_url = "http://files.vagrantup.com/lucid32.box"
config.vm.forward_port "http", 80, 8080
config.vm.share_folder "v-data", "/vagrant_data", "./data"
config.vm.customize do |vm|
vm.name = "devbox"
end
config.vm.provision :puppet,:module_path => "puppet/modules-0"
do |puppet|
puppet.manifests_path = "puppet/manifests"
puppet.manifest_file = "site.pp"
end
end
```
4. 在一个你想要运行虚拟机的节点上包含如下代码(将 john 替换为你自己的用户名):
```
vagrant::devbox { "devbox":
vm_user => "john",
}
```
5. 添加一个名为 devbox 的节点:
```
node devbox {
group { "puppet": ensure => present }
file { "/etc/motd":
content => "Puppet power!\n",
}
}
```
6. 运行 Puppet:
```
# puppet agent --test
```
7. 你应该在要运行虚拟机的宿主机上找到用户 john 自家目录下已创建的 devbox 目录。 在此目录中需要拥有一套 Puppet 配置清单的子目录(名为 puppet), 既可以从你的 Puppet 仓库检出到名为 puppet 的目录,也可以创建一个名为 puppet 的 **符号链接**(**symlink**)指向宿主机上已存在的 Puppet 配置清单目录:
```
# cd ~/devbox
# git clone git@github.com:Example/Puppet.git puppet
```
或者
```
# ln -s /etc/puppet ~/devbox/puppet
```
8. 在 devbox 目录中,运行如下命令行:
```
# vagrant up
[default] Box lucid32 was not found. Fetching box from specified
URL...
[default] Downloading with Vagrant::Downloaders::HTTP...
[default] Downloading box: http://files.vagrantup.com/lucid32.box
[default] Extracting box...
[default] Verifying box...
[default] Cleaning up downloaded box...
[default] Importing base box 'lucid32'...
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- http: 80 => 8080 (adapter 1)
[default] -- ssh: 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Running any VM customizations...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant
[default] -- v-data: /vagrant_data
[default] -- manifests: /tmp/vagrant-puppet/manifests
[default] Running provisioner: Vagrant::Provisioners::Puppet...
[default] Running Puppet with site.pp...
[default] stdin: is not a tty
[default] notice: /Stage[main]//Node[devbox]/File[/etc/motd]/
ensure: defined content as '{md5}0bdeca690dbb409d48391f3772d389b7'
[default]
[default] notice: /Group[puppet]/ensure: created
[default]
[default] notice: Finished catalog run in 0.36 seconds
[default]
```
登录到 devbox 虚拟主机进行测试:
```
# vagrant ssh
Puppet power!
Last login: Thu Jul 21 13:07:53 2011 from 10.0.2.2
vagrant@devbox:~$ logout
Connection to 127.0.0.1 closed.
```
#### 工作原理
vagrant 类安装 Vagrant 和 VirtualBox 以及所有的依赖。它同时还定义了名为 devbox 的 define,你可以使用它为一台宿主机的多个用户创建 devbox 的多个实例。 devbox 的一个实例如下:
```
vagrant::devbox { "app-foo-devbox":
vm_user => "john",
}
```
此实例在用户(本例为 john)的家目录下创建一个名为 app-foo-devbox 的 Vagrant 项目目录 (此目录包含一个配置文件 Vagrantfile,它指定了一个虚拟机的配置定义)。
当 Vagrant 首次启动虚拟机,它会在项目目录的名为 puppet 的子目录中查找提供给本虚拟机的 Puppet 配置清单。 这可以是你当前 Puppet 工作副本的一个符号链接, 也可以是仅为 devbox 编制的独立的 Puppet 配置清单 (无论你使用哪一种方式,只要 Vagrant 能找到即可)。
一旦虚拟主机已经配置好,它就可以投入使用了。运行 vagrant up 命令即可启动虚拟机; vagrant ssh 命令用于登录虚拟机;vagrant halt 命令用于停止虚拟机的运行。
顺便指出,节点定义中名为 puppet 的 group 资源在 Vagrant 的 Puppet 供应时会引发一个错误, 当你看到本书时可能已经被修复。Vagrant 正处于开发活跃期,所以可能会有一两处无法正常工作: 如有疑问,请查看本节最后的文档链接。
你可能会发现有时虚拟机无法完全启动,Vagrant 只是处于超时等待状态。 这似乎也是由于 Vagrant 的一个错误引起的,当你看到本书时可能已经被修复。如果还没有修复, 你可以在 Vagrantfile 中通过添加如下的代码片段来解决这个问题:
```
config.vm.boot_mode = :gui
```
修改之后重新启动虚拟机。现在虚拟机在 GUI 模式下启动,同时运行了一个控制台窗口。 在此窗口中,以用户名 vagrant(口令为 vagrant)登录,然后运行如下命令:
```
# sudo /etc/init.d/networking restart
```
现在你发现 Vagrant 会完成配置阶段并且 vagrant ssh 命令也会工作正常。
#### 更多用法
在本例中,我们仅对 devbox 配置了一个极其简单的配置清单,它在 /etc/motd 文件中添加了消息。 为了使其更实用,可以让 devbox 提取与你要部署的实际服务器相同的配置清单。例如:
```
node production, devbox {
include myapp::production
}
```
因此,应用到生产服务器配置的任何改变将同时反映在你用于测试的机器上, 这样就可以在实际部署之前先解决出现的问题,如果你需要进行配置的变化以支持新的功能, 可以首先在虚拟机上测试它,看看是否有什么不正常。
如果你不再使用虚拟机,想要挂起或关闭它,只要运行:
```
# vagrant suspend
```
或
```
# vagrant halt
```
想要完全删除虚拟机,例如你要重新测试供应,运行:
```
# vagrant destroy
```
Vagrant 的维护者为了使其使用简单做了相当多的工作,如果你需要阅读更多关于 Vagrant 的内容请访问其文档站点: [http://vagrantup.com/docs/index.html](http://vagrantup.com/docs/index.html) 。
- Puppet 2.7 Cookbook 中文版
- 中文翻译版
- 译者序
- 项目缘起
- 翻译方法
- 社区链接
- 社区建议
- 贡献者
- 原书版权页
- 关于作者
- 前言
- 本书内容
- 阅读前提
- 适用读者
- 格式约定
- 读者反馈
- 客户支持
- 下载案例代码
- 勘误表
- Puppet 基础设施
- 使用版本控制
- 使用提交钩子
- 使用 Rake 部署变更
- 配置 Puppet 的文件服务器
- 从 cron 运行 Puppet
- 使用自动签名
- 预签名证书
- 从 Puppet 的 filebucket 检索文件
- 使用 Passenger 扩展 Puppet 的部署规模
- 创建去中心化的分布式 Puppet 架构
- 监控、报告和排错
- 生成报告
- 通过 Email 发送包含特定标签的日志信息
- 创建图形化报告
- 自动生成 HTML 文档
- 绘制依赖关系图
- 测试你的 Puppet 配置清单
- 执行模拟运行
- 检测编译错误
- 理解 Puppet 的错误信息
- 显示命令的输出结果
- 输出调试信息
- 检查配置设置
- 使用标签
- 使用运行阶段
- 使用不同的环境
- Puppet 语言及其写作风格
- 使用 Puppet 社区规范
- 使用模块
- 使用标准的命名规范
- 使用嵌入式 Ruby 代码
- 使用纯 Ruby 代码书写配置清单
- 遍历多个项目
- 书写强大的条件语句
- 在 if 语句中使用正则表达式
- 使用选择器和 case 语句
- 检测字符串中是否包含指定的值
- 使用正则表达式替换
- 书写更优质的配置清单
- 使用资源的数组
- 使用 define 资源
- 指定资源的依赖关系
- 使用节点继承
- 使用类的继承和重载
- 给类传递参数
- 书写可重用的跨平台配置清单
- 获得系统的环境信息
- 导入动态信息
- 从 CSV 文件导入数据
- 给 Shell 命令传递参数
- 使用文件和软件包
- 为配置文件添加配置行
- 使用 Augeas 自动修改配置文件
- 使用配置片段构建配置文件
- 使用 ERB 模板
- 在模板中遍历数组
- 从第三方仓库安装软件包
- 配置 APT 软件仓库
- 配置 GEM 仓库
- 从源码包自动构建软件
- 比较软件包的版本
- 用户和虚拟资源
- 使用虚拟资源
- 使用虚拟资源管理用户
- 管理用户基于密钥的 SSH 访问
- 管理用户的自定义文件
- 有效地分发 cron 任务
- 当文件更新时运行命令
- 使用主机资源
- 为文件资源指定多个源
- 使用文件资源递归地分发整个目录树
- 清理过期的旧文件
- 使用日程表资源
- 资源的审计
- 临时禁用资源
- 管理时区
- 应用程序
- 管理 Apache 服务
- 创建 Apache 虚拟主机
- 创建 Nginx 虚拟主机
- 创建 MySQL 数据库及用户
- 管理 Drupal 站点
- 管理 Rails 应用程序
- 服务器和云基础设施
- 部署 Nagios 监控服务器
- 使用 Heartbeat 构建高可用服务
- 管理 NFS 服务和文件共享
- 使用 HAProxy 为多个 web 服务器实现负载均衡
- 使用 iptables 管理防火墙
- 管理 Amazon 的 EC2 实例
- 使用 Vagrant 管理虚拟机
- 外部工具和 Puppet 生态环境
- 创建 Facter 的自定义 fact
- 在运行 Puppet 之前和之后执行命令
- 从 Shell 会话生成 Puppet 配置清单
- 从运行的系统上生成 Puppet 配置清单
- 使用 Puppet Dashboard
- 使用 Foreman
- 使用 MCollective
- 使用公共模块
- 使用外部节点分类器
- 创建自定义的资源类型
- 创建自定义的提供者