SVN自助更新:運維利器Puppet實例講解(一)
原創(chuàng)【51CTO獨家特稿】一直關(guān)注51CTO系統(tǒng)頻道的讀者們可能已經(jīng)都知道了puppet這個工具。Puppet用于實現(xiàn)配置管理工作的自動化(詳見2010年系統(tǒng)管理員日當(dāng)天的外電頭條),既可以減輕系統(tǒng)管理員的工作量,更主要的是減少人為造成的失誤。在開始閱讀本文有關(guān)puppet的實例講解之前,推薦大家先閱讀stone的這篇puppet入門教程。
作者簡介:劉晗昭,網(wǎng)名蚊子(博客),某通信業(yè)國企系統(tǒng)工程師,熟悉各種主流開源軟件的使用,部署和組合應(yīng)用,以及主流網(wǎng)站架構(gòu)。目前關(guān)注puppet線上應(yīng)用與分布式緩存清除系統(tǒng)。
一直想寫點關(guān)于puppet的文章,但通過學(xué)習(xí)發(fā)現(xiàn),puppet更多的是參數(shù)配置上的東西,寫理論性的內(nèi)容無非就是翻譯一下官方文檔,不利于新人對于puppet的理解上手。于是覺得,還是應(yīng)該結(jié)合實際應(yīng)用寫些關(guān)于puppet使用方面的東西更貼近大眾。
首先簡單介紹一下puppet。puppet是一種Linux、Unix平臺的集中配置管理系統(tǒng),使用自有的puppet描述語言,可管理配置文件、用戶、cron任務(wù)、軟件包、系統(tǒng)服務(wù)等。puppet把這些系統(tǒng)實體稱之為資源,其設(shè)計目標(biāo)是簡化對這些資源的管理以及妥善處理資源間的依賴關(guān)系。
puppet采用C/S星狀的結(jié)構(gòu),所有的客戶端和一個或幾個服務(wù)器交互。每個puppet客戶端每半小時(可以設(shè)置)連接一次服務(wù)器端,下載最新的配置文件,并且嚴格按照配置文件來配置服務(wù)器,保證和該配置信息同步。配置完成以后,puppet客戶端可以反饋給服務(wù)器端一個消息。如果出錯,也會給服務(wù)器端反饋一個消息。
情景描述
在開始介紹實現(xiàn)方法之前,先介紹一下我們的業(yè)務(wù)情況。我們企業(yè)有不少項目是交給外包做的,相關(guān)的項目負責(zé)人或開發(fā)者有新的或更改過的項目文件會上傳到我們的SVN服務(wù)器上,再由我們的系統(tǒng)管理員執(zhí)行SVN update更新頁面。一直以來我們的做法都是,項目負責(zé)人或開發(fā)者上傳了新文件之后,去找到SA,SA再登錄服務(wù)器手動執(zhí)行svn up。每次都要SA動手實在很麻煩,所以前些日子看到puppet這個東西的時候,覺得這就是能夠?qū)㈨椖控撠?zé)人、開發(fā)者和SA從這個工作中解放出來的利器~
這個SVN自助更新系統(tǒng)的實現(xiàn)思路如下:
一、開發(fā)平臺
- apache+perl-cgi
- puppet
二、功能介紹
系統(tǒng)管理員/項目執(zhí)行者/開發(fā)人員通過web的get對應(yīng)的url,然后觸發(fā)更新puppet-master中的一個文件,puppet-client在同步時間到來的時候(默認半小時,可改),判斷master上對應(yīng)的項目文件的md5值是否有變化,如果有變化,觸發(fā)puppet配置中對應(yīng)的svn更新的程序,完成此項目的更新。
三、系統(tǒng)架構(gòu)
四、實施步驟及相關(guān)說明解釋
1、puppet配置
此處puppet的安裝方法我就不寫了,有需要的自行去網(wǎng)上查找。我這邊是CentOS 5.4(服務(wù)器端)和CentOS 5.5(客戶端),采用yum安裝。
#p#
A、puppet-master配置
a) 首先是創(chuàng)建autosign.conf文件,此文件用于自動驗證。
*.wenzizone.cn
這樣所有這個域名過來的請求會自動驗證。
b) 修改puppet.conf文件。如果是通過rpm或yum安裝,此文件內(nèi)容可以基本保持不變
[main]
logdir = /var/log/puppet
rundir = /var/run/puppet
ssldir = $vardir/ssl
bindaddress = 192.168.192.199
[puppetd]
classfile = $vardir/classes.txt
localconfig = $vardir/localconfig
此文件主要是定義了一些文件路徑,我在這里添加了bindaddress = 192.168.192.199這條,綁定在了內(nèi)網(wǎng)的ip上,因為我并不想讓我的puppet-master被外網(wǎng)訪問到,這個可以因個人環(huán)境而定。如果需要看詳細的puppet.conf內(nèi)容可以執(zhí)行puppet --genconfig。
c) 修改fileserver.conf,增加如下內(nèi)容
[system] path /etc/puppet/modules/system/files allow *.wenzizone.cn allow 192.168.192.0/24 [svnup] path /etc/puppet/modules/svn/files allow *.wenzizone.cn allow 192.168.192.0/24
此文件可以創(chuàng)建一個文件系統(tǒng),有點類似rsync的配置,后面我會繼續(xù)介紹。這個意思就是所有wenzizone.cn或者192.168.192.0網(wǎng)段的機器可以訪問/etc/puppet/modules/svn/files下的文件。
注:以上三個文件都是放至在/etc/puppet目錄下的
d) puppet功能配置
首先看下puppet的目錄結(jié)構(gòu),
/etc/puppet/ |-- auth.conf |-- autosign.conf |-- fileserver.conf |-- manifests | |-- huodong_web.pp | `-- site.pp |-- modules | |-- svn | | |-- files | | | |-- hd_zf_up_file | | `-- manifests | | |-- hd_zf_up.pp | | |-- init.pp | `-- system | |-- files | | |-- puppet.client.conf | `-- manifests | |-- init.pp | |-- puppet_client.pp `-- puppet.conf
根下的manifests目錄放置主配置文件,modules下面是各種的模塊,在這里我設(shè)置了兩個模塊,system和svn,其中system用來給我的puppet-client同步puppet.conf文件,svn就是我這次介紹的重點了。
這里插個題外話:puppet的模塊都是遵從
| |-- svn | | |-- files | | `-- manifests | | |-- init.pp
這種結(jié)構(gòu)的,包含模塊名字:svn目錄,files目錄,manifests目錄,此目錄下包含init.pp文件。
下面先看svn的這個模塊
files目錄:用來存放觸發(fā)svn更新的文件的,我們可以在此目錄下touch任何一個名字的文件,更新的工作由perl-cgi來控制,我這里使用的名字是:hd_zf_up_file
manifests目錄:用來存放puppet的腳本文件的,必須包含init.pp文件,通常情況下可以把腳本都寫入到這個一個文件中,但為了便于管理,最好是按照功能或者項目分開存放。我這里的hd_zf_up.pp就是我為公司線上的一個項目建立的。內(nèi)容如下:
1class hd_zf_up 2{ 3 file { 4 "hd_zf_up": 5 group => 'root', 6 mode => '600', 7 owner => 'root', 8 path => "/tmp/hd_zf_up_file", 9 source => "puppet:///svnup/hd_zf_up_file", 10 } 11 12 exec { 13 "svn up": 14 cwd => "/var/www/html/www.scjtxx.cn/zf", 15 path => "/usr/bin:/usr/sbin:/bin", 16 subscribe => File["hd_zf_up"], 17 refreshonly => true, 18 } 19}
下面詳細解釋一下:
1行定義了一個類,類似php里的類,用于將相應(yīng)的方法整合。
3行是puppet的file方法,網(wǎng)上的介紹file是一種資源,我這里認為當(dāng)作方法比較合適,這樣就可以跟php的類相似了,file后面大括號里的都是file這個方法的屬性。屬性用來賦值,方法用來調(diào)用。當(dāng)然怎樣理解因人而異。
4行給這個file方法定義了一個方便使用的別名
5行定義此文件的屬組是root
6行定義此文件的訪問模式是只有屬主用戶可讀可寫
7行定義文件的屬主也是root
8行定義此文件在puppet-client端的放置位置及文件名
9行定義了從puppet-master的什么文件拿到那個文件。這里就用到了前fileserver.conf定義的內(nèi)容,可以看到svnup是預(yù)定義的別名,它實際對應(yīng)的路徑是/etc/puppet/modules/svn/files,這樣后面跟的文件就會到這個路徑下去取。整個svn這部分的配置理解就是:puppet-client要從source定義的路徑拿到hd_zf_up_file文件放到client的/tmp目錄下并將文件所以權(quán)給root用戶和組,訪問模式是600。
12行定義了puppet的exec方法,這個方法是使puppet執(zhí)行系統(tǒng)命令或腳本用的。
13行是定義了exec要執(zhí)行的命令,在這里是要求puppet執(zhí)行svn up這個命令。也就是更新項目的命令
14行定義了上面的svn up命令要在什么目錄下執(zhí)行
15行定義了path的變量,用于系統(tǒng)可以找到svn對應(yīng)的命令。
16行定義了一個依存關(guān)系,我們這里和17行聯(lián)合起來解釋,當(dāng)file方法定義里的那個文件的md5值發(fā)生變化的時候,此exec方法觸發(fā),即當(dāng)上面source里面定義的文件md5值發(fā)生改變了,就執(zhí)行svn up這個命令。
題外話:起先我這里并沒有想到要和一個文件進行聯(lián)立,但結(jié)果發(fā)現(xiàn),puppet會在每次觸發(fā)的時候都執(zhí)行exec這個方法,這會造成網(wǎng)絡(luò)資源的消耗,因為svn里的數(shù)據(jù)并不是每次都有更新的,所以沒必要每次都執(zhí)行。
到此svn up這部分的配置就完成了。接下來看看init.pp里面的內(nèi)容
class svn { import "hd_zf_up.pp" }
可以看到,init.pp的內(nèi)容還是很簡單的,只是引入了我們定義好的pp文件。
下面來介紹system那個模塊的內(nèi)容,這部分內(nèi)容我主要講同步puppet-client端配置文件的這個功能,這樣方便我們一次性配置好client端的puppet。
files目錄下:放置的是puppet.client.conf文件,主要內(nèi)容如下
[main] logdir = /var/log/puppet rundir = /var/run/puppet ssldir = $vardir/ssl [puppetd] classfile = $vardir/classes.txt localconfig = $vardir/localconfig server = app-21-199.wenzizone.cn runinterval = 300 show_diff=true
從內(nèi)容上看,基本上和master上一樣,主要區(qū)別是后三行,server用于指明master的名字,可以是ip可以是對應(yīng)的主機名(前提是你已經(jīng)有了對應(yīng)的解析)。runinterval用于指定puppet-client每次執(zhí)行的間隔,單位是秒,最后一行是當(dāng)文件被替換的時候是否顯示不一樣的地方。
manifests目錄下同樣放置了init.pp文件,同時我還自定義了一個puppet_client.pp,內(nèi)容如下:
1 class puppet_client 2 { 3 file 4 {
5 "puppet_conf":
6 path => "/etc/puppet/puppet.conf",
7 source => "puppet:///system/puppet.client.conf",
8 }
9 exec
10 {
11 "reload-puppet-client":
12 command => "/etc/init.d/puppet force-reload",
13 require => Service["puppet_client"],
14 refreshonly => true,
15 }
16 service 17 { 18 "puppet_client": 19 name => "puppet", 20 enable => true, 21 ensure => running, 22 hasrestart => true, 23 hasstatus => true, 24 subscribe =>File["puppet_conf"], 25 } 26 }
相同的內(nèi)容就不重復(fù)介紹了。這里exec部分的11行并不是直接寫的要執(zhí)行的命令,而是定義了富有含義的名字,比較直觀,然后在12行通過command定義了要執(zhí)行的命令。
13行表明exec能不能執(zhí)行是依賴于service這個方法的,后面詳細介紹。
16行開始定義了一個新的方法service。顧名思義就是服務(wù)類的方法。
18行同樣定義了一個富有含義的名稱。
19行定義這個服務(wù)的名字,這里的名字必須和/etc/init.d下對應(yīng)的名字一樣
20行表示此服務(wù)在開機時是否啟動,true是啟動
21行表示是否運行此服務(wù),running表示運行。
22行指出管理腳本是否支持restart參數(shù),如果不支持,就用stop和start實現(xiàn)restart效果. 可以設(shè)置的值是true 或 false
23行指出管理腳本是否支持status參數(shù),puppet用status參數(shù)來判斷服務(wù)是否已經(jīng)在運行了,如果不支持status參數(shù),puppet利用查找運行進程列表里面是否有服務(wù)名來判斷服務(wù)是否在運行. 可以設(shè)置的值是true或false
24行表示,此服務(wù)運行依賴file這個方法,同時exec又require了service,這樣當(dāng)file里定義的配置文件有變化及文件md5值不一樣的時候,exec就執(zhí)行force-reload的命令。
再來看init.pp內(nèi)容
1 class system 2 { 3 import "puppet_client.pp" 4 }
此內(nèi)容很簡單,主要是定義了一個system的類,然后導(dǎo)入puppet_client.pp的內(nèi)容。
到此puppet上自定義的兩大功能就介紹完成了,下面看看puppet如何加載。
回到/etc/puppet/manifests目錄下,主要文件就兩個,site.pp和huodong_web.pp。site.pp是主文件,huodong_web.pp是我為我需要svn更新的web服務(wù)器做的。內(nèi)容如下
1 node "app198-vhost-192-55" { 2 #系統(tǒng)初始化工具 3 include system 4 include puppet_client 5 #祝?;顒禹撁娓? 6 include svn 7 include hd_zf_up 8 }
1行定義了一個主機名,此處可以是主機名可以是ip地址
3加載system類,這個類是在system模塊下的init.pp中定義的
4在system類加載后就來加載puppet_client的類,這個累是在system模塊下的puppet_client.pp定義的。
6,7行同樣是加載svn模塊中定義好的類。
接下來看site.pp的內(nèi)容
1 node default 2 { 3 import "huodong_web.pp" 4 }
這個主文件的內(nèi)容也很簡單,首先定義了一個默認node,然后加載了huodong_web.pp文件。
到此master上puppte部分的配置就全部完畢了。接下來看client端上的配置
#p#
B、puppet-client上的配置
a) 登錄到app198-vhost-192-55這臺主機上,yum安裝puppet,然后在命令行執(zhí)行
puppetd --server app-21-199.wenzizone.cn –test
由于我們是做的自動簽名,并且在服務(wù)器上配置了puppet-client的配置文件,所以執(zhí)行完過后puppet自動會以守護進程的方式啟動
b) 配置svn更新主目錄,及web頁面項目的主目錄,在我這個案例中的主目錄是/var/www/html/www.scjtxx.cn/zf,進入到這里使用svn co svn_source ./將初始的項目導(dǎo)入出來。這樣就為了svn up命令執(zhí)行做好了對應(yīng)的環(huán)境。
通過簡單的兩步,就已經(jīng)把puppet-client上的準(zhǔn)備工作都完成了,是不是很簡單。
那么下面就是perl-cgi部分了。
C、部署svn自助更新web腳本
這里可以將腳本部署在和puppet-master同一臺主機上,當(dāng)然也可以考慮分布式的,那樣就需要調(diào)整這個腳本?,F(xiàn)在先以同一臺機器為例。
a)安裝apache,配置cgi目錄
因為我們的訪問量不會很大,我直接用yum安裝了。所以cgi目錄使用的是默認的cgi-bin目錄。
b)編寫對應(yīng)的腳本pjupdate.cgi
#! /bin/env perl use CGI; my $query = CGI->new(); #初始化cgi實例 my $file_name = $query->param('pjname'); #將url中pjname的值賦給$file_name變量 my $up_time = `date +%s`; #獲得從1970-01-01 00:00:00 UTC到現(xiàn)在的秒數(shù)
my $dst_dir = "/etc/puppet/modules/svn/files/"; #目標(biāo)文件的目錄
my $success = open FH,">".$dst_dir.$file_name; #開的目標(biāo)文件,即觸發(fā)svn的文件
if(!$success) {
print "Content-type:text/html\n\n";
print "不能更新此項目,請聯(lián)系管理員!"; #如果打開不成功進行提示,通常是權(quán)限問題,文件屬主改成apache執(zhí)行用戶 } else { print FH"$up_time"; #更新文件內(nèi)容,為了達到變更此文件md5值的效果 print "Content-type:text/html\n\n"; print "更新已經(jīng)開始,請5~10分鐘后查看頁面"; } close(FH);
#p#
五、測試
使用方法:通過
http://test.wenzizone.cn/cgi-bin/pjupdate.cgi?pjname=hd_zf_up_file
觸發(fā)更新。
可以看到,pjname的值實際上就是磁盤上我定義的那個文件的名字。這樣只要使用不同的文件,再配置不同的puppet的pp文件,就能實現(xiàn)多個項目自助更新了。同樣,因為puppet是分布式的c/s模式,所以在同一時間,也可以實現(xiàn)對多臺服務(wù)器的更新。
到此,這個自助svn更新系統(tǒng)就介紹完畢了。有幾點需要注意的:
- 請確認部署環(huán)境中有對應(yīng)的主機名到ip地址的解析環(huán)境,本文所在環(huán)境已存在內(nèi)部dns,所以全部使用主機名。
- 所有puppet主機時間要保持一致。
- 注意防火墻對puppet端口的限制,如果非必要,可以關(guān)閉防火墻。
心得總結(jié)
puppet確實是一個功能很強大的統(tǒng)一管理系統(tǒng)。在學(xué)習(xí)初期,對于文件模塊之間的關(guān)系著實有些混亂,不過通過自己的摸索和嘗試,在參考了網(wǎng)上的一些資料后,大概了解了puppet結(jié)構(gòu)之間的聯(lián)系,逐漸的實現(xiàn)了自己的一些想法,同時也為了給新學(xué)puppet的人理清各文件間關(guān)系吧。此文只為拋磚,因為這套系統(tǒng)目前來看還很簡陋,還有很多需要完善的地方。如何更合理的利用puppet以及如何能更簡化puppet的認為干預(yù)配置,值得我去思考并逐步去實現(xiàn)的。
【51CTO.com獨家特稿,轉(zhuǎn)載請注明原文作者和出處?!?/p>
【編輯推薦】