使用 Vagrant 構建開發環境
摘要:本文描述了如使用 Vagrant 構建統一的開發環境。
問題
作為開發人員,我們通常面臨的問題有:
- 開發環境需要手工安裝配置,這包括操作系統(CentOS、Ubuntu)、PHP/HHVM、Python、Node.js、MySQL、Apache/Nginx等的版本和配置。
- 無法重現問題。
甲:你說的問題,怎么在我的機器上沒事兒啊?
乙:可問題的確存在,不信你到我的機器上來看。
甲:那我的機器和你的環境哪里不同呢?
因為環境不同,比如開發環境和生產環境不同,和測試環境也不完全相同。 - 團隊中沒有統一的方法配置開發環境,保持相同的環境,好的可能會有一個文檔,告訴大家要下載、安裝的東西,缺乏文檔的可能就要到處問了。
- 在同一台機器上,要為參與的不同項目配置不同的環境,因為要求的軟件、版本不同,有時候這根本就不可能。
- 團隊中不同的成員使用的機器、操作系統就不同,就很難保證完全相同的環境。比如很多開源項目,團隊成員來自五湖四海,有人用Windows,有人用Mac,系統不一樣,配置就可能不同,導致不同的結果。
解決方法 - Vagrant之道
用虛擬機構建一致的環境,並且把安裝和配置的過程自動化,這就是Vagrant所做的事情。按照Vagrant的流程:
- 系統工程師只需要准備Vagrant配置以及相應的腳本,來配置虛擬機。
- 團隊成員只需要從源碼控制中簽出代碼,運行vagrant up,就可以有一個完整的開發環境了。開發人員還是可以繼續在自己的機器上使用自己熟悉的編輯器、瀏覽器和其它工具,而代碼及數據庫、web服務器則是運行在Vagrant的虛擬機中。
- 如果把虛擬機搞亂了,只需要用vagrant destroy把虛擬機刪除,再運行vagrant up就又可以得到事先配置好的虛擬機了。
- 用完之后,只需要使用vagrant halt或者vagrant suspend把虛擬機關機或者休眠,第二天用vagrant up就把虛擬機重新啟動,恢復到昨天的狀態了。
- 這種對虛擬機的管理方式,不單在一個項目的團隊中可以使用,而且可以跨多個項目使用。使用相同的流程和環境,提高了生產力,再也不會有“在我的機器上明明沒有這個問題”的問題了。
這就是Vagrant之道(參看[5]第4頁)。
Vagrant可以做下面這些事情:
- 通過SSH登錄虛擬機
- 關掉虛擬機
- 刪除虛擬機,完全刪除虛擬硬盤和配置信息
- 暫停和恢復虛擬機
- 把虛擬機打包,從而可以分發給其他開發人員
Vagrant涉及的概念:
- Vagrant本身並不是虛擬機,它通過其供應商(provider)來使用虛擬機,支持的虛擬機有Oracle的VirtualBox、VMWare的VMWare Fusion和VMWare Workstation和微軟的Hyper-V,以及象Docker這樣的容器,還有Amazone的AWS、Rackspace和DigitalOcean等公有雲。缺省的是使用VirtualBox,因為這是免費的,也是最容易配置的。
- 虛擬機只是提供了一個虛擬的機器,其中的各種軟件的安裝和配置還是要靠provision,支持的配置工具有最基本的shell腳本、以及Puppet、Chef和Ansible等等。
- 為了便於虛擬機的分發和共享,虛擬機本身的虛擬硬盤和配置加上Vagrant的設置文件可以打包在一起,這在Vagrant中叫box,這是可被Vagrant直接使用的虛擬機鏡像文件。眾多廠商和用戶在Atlas(以 前叫Vagrant Cloud)上提供了各種box,對應你所使用的provider。你也可以在其它box的基礎上,進一步配置、發布自己的box,共享給自己的團隊或者公眾。
- 如果上述的功能還不能滿足你對環境的要求,Vagrant還提供插件,對基本的功能進行擴展,甚至你也可以按照其規范開發自己的插件,滿足特定的要求。
下面我們就用幾個例子來說明Vagrant的使用。
請先下載、安裝VirtualBox和Vagrant。因為Vagrant是用ruby開發的,你還要下載、安裝Ruby。不論你的機器是Windows、Mac或者各種Linux發行版本,這幾個軟件都有相應的版本。
實例一 最簡單的Vagrant環境
創建一個新目錄,比如叫example。然后運行:
vagrant init hashicorp/precise64
在上述命令中指定了hashicorp/precise64為使用的box,這是Ubuntu 12.04 LTS,更多的信息可見https://atlas.hashicorp.com/hashicorp/boxes/precise64。第一次需要一個box時(即在運行vagrant up時),Vagrant會自動下載該box到你的機器上,這通常位於<homedir>\.vagrant.d\boxes(例如,在Windows 7上,這就是C:\Users\myusername\.vagrant.d\boxes),以后就不必再次下載了。
上述會生成一個基本的Vagrant配置文件Vagrantfile,最簡單的情況可以只有這一個文件。基本內容如下:
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "hashicorp/precise64" # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. config.vm.network "forwarded_port", guest: 80, host: 8080 end
這個文件指定了下面這些基本的配置:
- 在上述生成的配置文件中,指定了如下box:
config.vm.box = "hashicorp/precise64"
- 其次,指定虛擬機和主機之間的映射目錄,通常共享的是源文件目錄。這樣,你就可以在主機上繼續使用自己熟悉的編輯器寫代碼,而使用虛擬機環境來運行、調試。
上述配置文件沒有指定任何映射目錄,但是Vagrant缺省會把主機Vagrantfile配置文件所在的目錄映射為虛擬機上的/vagrant目錄。 - 還有,就是配置虛擬機的網絡,否則,你從主機上無法訪問虛擬機。這有三種模式:forwarded ports、host-only networking和bridged networking。
- Forwarded Ports,缺省值,在主機上選擇一個端口,轉發給虛擬機的一個端口,這樣就不必給虛擬機一個IP,就可以從主機訪問虛擬機了。
上述配置文件中,使用的是Forwarded Ports:
config.vm.network "forwarded_port", guest: 80, host: 8080
這會把虛擬機的80端口映射到主機的8080端口,在主機上通過localhost:8080就可以訪問虛擬機了。同時,缺省會有另外一個映射,把虛擬機的22端口映射到主機的2222端口,這是為了允許從主機上通過SSH登錄到虛擬機。
- Host-Only Networking,這會在主機上創建一個僅對主機和虛擬機可見的私有網絡,這樣虛擬機得到一個指定的靜態IP地址,就可以從主機通過該靜態IP地址來訪問虛擬機了,而虛擬機也可以通過*.*.*.1的IP地址來訪問主機。這種情況下,主機所在的網絡上的其他機器是無法“看到”這個私有網絡的,也就無法訪問虛擬機。
- Bridged Networking,橋接虛擬機到主機上的一個設備(應該指網卡),這樣虛擬機就如同主機所在網絡上的另外一台物理機器一樣,這意味着虛擬機可以訪問網絡資源,網絡上的其他機器也可以訪問虛擬機。
- Forwarded Ports,缺省值,在主機上選擇一個端口,轉發給虛擬機的一個端口,這樣就不必給虛擬機一個IP,就可以從主機訪問虛擬機了。
有了這個Vagrantfile配置文件,就可以啟動虛擬機了。在命令行中,在Vagrantfile所在的目錄中,運行如下命令:
vagrant up
小竅門:在Windows 7(及以上版本?)的Windows Explorer中,可以按住Shift鍵,再用鼠標右擊某個目錄,直接在跳出的上下文菜單中點擊"Open command window here",就直接進入命令行並進入該目錄了。
輸出如下:
從上面的輸出中,我們可以看到指定使用的box、端口的映射和共享目錄的映射。
前面提到虛擬機22端口對主機2222端口的映射是用於SSH的,我們現在就可以用SSH登錄虛擬機了。運行如下命令:
vagrant ssh
小竅門:如果你的命令行沒有對ssh的支持,就無法登錄。在Windows上,可以在安裝git的時候,有一個選項,選擇添加相應的目錄到系統路徑中,就支持在命令行使用SSH了。
上述命令相應的輸出為:
這就登錄進入了虛擬機,在$提示符下可以使用Linux命令操縱虛擬機了。
實例二 Python Sphinx文檔環境
第二個例子中,我們用VirtualBox和shell腳本來構建一個最基本的虛擬環境,用於使用Sphinx來生成文檔。先創建一個新目錄,比如叫docs,在其中創建一個新文件Vagrantfile,完整的配置為:
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| # Every Vagrant virtual environment requires a box to build off of. config.vm.box = "puphpet/ubuntu1404-x64" # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder "../data", "/vagrant_data" config.vm.synced_folder ".", "/docs" config.vm.provider "virtualbox" do |v| v.name = "cakephp_docs" v.memory = 384 end config.vm.provision :shell, path: "provision.sh" end
最常用的Linux版本之一是Ubuntu 14.04,我們就以此為基礎,在配置中指定使用puppet/ubuntu1404-x64 box:
config.vm.box = "puphpet/ubuntu1404-x64"
映射主機的當前目錄(即Vagrantfile配置文件所在的目錄)為虛擬機的/docs目錄,這里會放置源代碼控制下的文檔源碼*.rst文件:
config.vm.synced_folder "./", "/docs"
另外,因為不需要從主機訪問虛擬機的web服務器,所以沒有配置網絡,即使用的是缺省的Forwarded Ports模式。
再指定使用一個shell腳本,安裝、配置sphinx:
config.vm.provision :shell, path: "provision.sh"
在同一目錄下,再創建shell腳本文件povision.sh,其內容為:
#!/usr/bin/env bash echo "update apt repository..." apt-get update >/dev/null 2>&1 echo "Installing python-setuptools..." sudo apt-get install -y python-setuptools >/dev/null 2>&1 echo "Installing easy_install..." sudo apt-get install -y easy_install >/dev/null 2>&1 echo "Installing sphinx..." sudo easy_install sphinx==1.2 >/dev/null 2>&1 echo "Installing sphinxcontrib-phpdomain..." sudo easy_install sphinxcontrib-phpdomain >/dev/null 2>&1
因為Python是Linux自帶的,不需要再安裝了。該腳本使用apt-get安裝兩個軟件包python-setuptools和easy_install,然后再用easy_install安裝sphinx 1.2和sphinxcontrib-phpdomain。
這樣就配置好了,在命令行中,在Vagrantfile所在的目錄中運行
vagrant up vagrant ssh
之后,就通過SSH登錄到虛擬機,可以在其中用sphinx從源代碼構建html文檔了。
實例三 LAMP開發環境
在第三個例子中,我們使用PuPHPet為PHP配置一個LAMP開發環境。PuPHPet是一個網頁的向導式界面,讓你更容易地生成使用Puppet的Vagrant配置文件。
用瀏覽器打開https://puphpet.com。
第一步,選擇部署目標,缺省為本地,使用VirtualBox。我們選擇操作系統為Ubuntu 14.04 64位,如下圖所示:
然后,設置虛擬機IP地址、內存、端口,以及目錄映射,注意這里的目錄是用來作為網站應用根目錄的,如下圖所示:
第二步,選擇要在虛擬機上安裝的軟件包。我們選擇Ubuntu的htop和vim,如下圖所示:
第三步,防火牆規則,不需要做任何設置,略過:
第四步,選擇web服務器,我們選擇使用Apache,要安裝rewrite模塊,如下圖所示:
再設置域名、網站根目錄,允許設置多個VHOST,如下圖所示:
注意上面的Document Root路徑和在第一步中設置的目錄映射有關。
第五步,選擇語言PHP,以及相關的設置和需要的模塊,如下圖所示:
還可以選擇需要的PHP庫,如下圖所示:
第六步,選擇數據庫MySQL,並且設置管理員密碼,如下圖所示:
然后創建數據庫,允許創建多個數據庫,如下圖所示:
其中,/var/www/database/backup/2014-10-19_cakephp_blog.sql是在虛擬機中要恢復的數據庫備份,這個路徑也和你在第一步中設置的目錄映射有關。
第七步,選擇其它工具,包括郵件工具Mailcatcher、隊列工具Beanstalkd及RabbitMQ、搜索工具Elastic Search及Solr,如下圖所示:
我們不使用任何額外工具,所以略過這一步。
第八步,也就是最后一步,完成,如下圖所示:
點擊那個大大的藍色按鈕“GO AHEAD THEN, MAKE IT!”,就可以下載一個將近3MB的puphpet.zip。打開這個.zip文件,可以看到按照我們前面第一至八步設置的Vagrantfile配置以及相應的Puppet模塊,如下圖所示:
把它解壓到一個目錄中,這些文件可以和PHP項目的源代碼一起放入源碼控制中,供項目團隊的其他成員使用。
在命令行中,在Vagrantfile所在的目錄中運行vagrant up,就可以得到一個運行的LAMP虛擬機了。
在主機的hosts文件中,按照第四步的設置加入下面這行:
192.168.56.102 www.cakephp3.dev # CakePHP 3
就可以在主機的瀏覽器上通過www.cakephp3.dev訪問虛擬機上的網站了。
Vagrant的常用命令
vagrant up # 啟動、配置虛擬機
vagrant suspend # 休眠虛擬機
vagrant halt # 關閉虛擬機
vagrant destroy # 刪除虛擬機
vagrant status # 當前目錄下Vagrantfile配置對應的Vagrant虛擬機的狀態,以及在此狀態下可以使用的命令
vagrant global-status # 本機上所有Vagrant虛擬機的狀態
更多的命令可以參考[3]中的Command-Line Interface。
進一步的思考
- 打包、分發box,這是Vagrant通過box以及Atlas提供的功能。
- 使用Docker的provider,可以節省資源,極大地縮短虛擬機的啟動時間,也利於生產環境的部署。
- 是否可以使用Vagrant來配置Windows虛擬機?應該使用什么provision?是否可以使用PowerShell?
- 是否可以使用Vagrant來配置Mac虛擬機?可能不行,至少在Atlas上沒有找到Mac的box。而且,恐怕也沒必要。
參考資料
- Vagrant官網
https://www.vagrantup.com/ - Vagrant Getting Started
https://docs.vagrantup.com/v2/getting-started/ - Vagrant Documentation
https://docs.vagrantup.com/v2/ - Atlas (之前叫Vagrant Cloud)
https://atlas.hashicorp.com - Vagrant: up and running, ISBN 978-1-449-33583-0
http://shop.oreilly.com/product/0636920026358.do - Hello Vagrant - 黃博文
http://www.cnblogs.com/huang0925/p/3349841.html - Docker與Vagrant之間的特點比較
http://www.cnblogs.com/vikings-blog/p/3973265.html