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