### 使用 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
- 使用公共模塊
- 使用外部節點分類器
- 創建自定義的資源類型
- 創建自定義的提供者