Puppet 是一個(gè)用 Ruby 寫(xiě)的開(kāi)源 IT 管理工具,用于數(shù)據(jù)中心自動(dòng)化和服務(wù)器的管理,用戶包括 Google, Twitter, 紐約證券交易所以及很多其他機(jī)構(gòu)。Puppet 的主要維護(hù)者是 Puppet Labs,也就是 Puppet 項(xiàng)目的發(fā)起者。Puppet 可以管理從 2 臺(tái)到 5 萬(wàn)臺(tái)機(jī)器,管理員可以只有1個(gè)人或者是上百人。
Puppet 是一個(gè)用于配置和維護(hù)計(jì)算機(jī)的工具;通過(guò)使用 puppet 的簡(jiǎn)單的配置語(yǔ)言,你可以告訴 Puppet,你希望如何配置機(jī)器,然后 Puppet 就會(huì)按照你的指示來(lái)修改機(jī)器的配置。之后,如果你改變了需求,比如更新了軟件包,增加了新用戶,或是更新了配置,那么 Puppet 也會(huì)自動(dòng)地隨之更新你的機(jī)器。而如果這些機(jī)器本來(lái)就已經(jīng)配置好了,Puppet 就什么都不會(huì)動(dòng)。
總的講,Puppet 可以借助任何已有的系統(tǒng)特性來(lái)完成它的工作。比如,在 Red Hat 中,它會(huì)使用yum
?來(lái)進(jìn)行包管理,并修改?init.d
?來(lái)管理系統(tǒng)服務(wù);而在 OS X 中,Puppet 則使用 dmg 來(lái)管理軟件包,使用?launchd
?來(lái)管理系統(tǒng)服務(wù)。Puppet 的一個(gè)目標(biāo)就是讓你或者系統(tǒng)本身都可以通過(guò) Puppet 代碼來(lái)明白如何進(jìn)行工作,所以,必須要能夠遵從各個(gè)系統(tǒng)的規(guī)范。
Puppet 集成了很多已有工具的傳統(tǒng)。從開(kāi)源社區(qū)的角度講,對(duì) Puppet 影響最大的莫過(guò)于 CF-Engine 和 ISconf 了,CF-Engine 是第一個(gè)開(kāi)源通用配置管理工具,而 ISconf 使用了?make
?來(lái)完成所用工作,其靈感來(lái)源于顯式地處理系統(tǒng)中所有的依賴關(guān)系。在商業(yè)軟件中,Puppet 受到了 BladeLogic 和 Opsware (兩者都已經(jīng)被大公司收購(gòu)了)的影響,在 Puppet 項(xiàng)目開(kāi)始時(shí),這兩種工具都在市場(chǎng)中獲得了不小的成功,不過(guò)兩者都更加關(guān)注于向大公司的管理層來(lái)推銷,相反,對(duì)于直接為管理員提供一個(gè)強(qiáng)大的工具,沒(méi)有足夠的重視。Puppet 希望和這些工具解決差不多的問(wèn)題,但關(guān)注的用戶有很大不同。
這個(gè)簡(jiǎn)單的例子用于解釋如何使用 Puppet,例子中的這段代碼用來(lái)確保系統(tǒng)中安裝了 SSH 服務(wù),并配置正確:
class ssh {
package { ssh: ensure => installed }
file { "/etc/ssh/sshd_config":
source => 'puppet:///modules/ssh/sshd_config',
ensure => present,
require => Package[ssh]
}
service { sshd:
ensure => running,
require => [File["/etc/ssh/sshd_config"], Package[ssh]]
}
}
這個(gè)配置確保軟件包被安裝,文件就位,并且服務(wù)運(yùn)行。注意,我們指定了資源之間的依賴關(guān)系,這樣,我們就可以確保一定能夠按照正確順序工作。這個(gè)類 (class) 可以被關(guān)聯(lián)到任何一個(gè)需要這個(gè)配置的主機(jī)。Puppet 配置的基本組件是結(jié)構(gòu)化的對(duì)象,在這個(gè)例子里就是?package
,?file
?和service
。我們將這些對(duì)象稱為資源 (resource),Puppet 配置中的任何東西,最后都會(huì)分解為一些資源,以及資源間的依賴關(guān)系。
通常,一個(gè)使用 Puppet 的機(jī)構(gòu)可能擁有數(shù)十甚至上百個(gè)這樣的代碼段,我們稱之為類 (class),我們將存儲(chǔ)這些類的文件稱為貨單 (manifest
),這些被按照相關(guān)性分組,這些組稱為模塊 (module)。比如,你可能有個(gè)?ssh
?模塊,其中包含了這個(gè)?ssh
?類和一些其他相關(guān)類,同時(shí)還會(huì)有諸如?mysql
,apache
, 以及?sudo
?等模塊。
大部分的 Puppet 交互都通過(guò)命令行或是一直運(yùn)行著的 HTTP 服務(wù)進(jìn)行的,不過(guò)有些東西也有圖形界面,比如報(bào)告處理。Puppet Labs 還提供了一些 Puppet 的周邊商業(yè)產(chǎn)品,這些產(chǎn)品更傾向于使用基于 web 的圖形化界面。
Puppet 的第一個(gè)原型寫(xiě)于2004年夏天,從2005年2月開(kāi)始成為了一個(gè)有全職投入的項(xiàng)目。Puppet 最初由 Luke Kanies 設(shè)計(jì)并實(shí)現(xiàn),它是一位經(jīng)驗(yàn)豐富、寫(xiě)過(guò)很多不足萬(wàn)行的小工具的管理員。本質(zhì)上說(shuō),隨著 Puppet 的開(kāi)發(fā),Luke 學(xué)著稱為了一位程序員,從程序架構(gòu)上說(shuō),這具有正反兩面性。
Puppet 最初并最重要的目的就是成為一個(gè)管理員的工具,讓他們的工作更輕松、更快、更高效,且更不易犯錯(cuò)。第一個(gè)關(guān)鍵性的創(chuàng)新就是上面提到的資源,這是 Puppet 的基本元素,它們是跨操作系統(tǒng)可移植的,并且抽象的資源屏蔽了實(shí)現(xiàn)細(xì)節(jié),允許用戶關(guān)注配置的結(jié)果,而非具體如何實(shí)現(xiàn)這些配置。而這些基本元素本身由 Puppet 的資源抽象層來(lái)實(shí)現(xiàn)。
在一臺(tái)給定的主機(jī)上,Puppet 資源必須是唯一的。你只能有一個(gè)叫 "ssh" 的包,一個(gè)叫 "sshd" 的服務(wù),也只能有一個(gè)叫 "/etc/ssh/sshd_config" 的文件。這就避免了你的配置的不同部分之間的沖突,一旦發(fā)生沖突,你會(huì)在進(jìn)行配置的最初階段發(fā)現(xiàn)它。我們可以通過(guò)資源的名稱和類型來(lái)指定一個(gè)資源,比如?Package[ssh]
?和?Service[sshd]
。你可以有一個(gè)包和一個(gè)服務(wù)同名,因?yàn)樗鼈冾愋筒煌?,但不論如何,你都不可以有兩個(gè)同名的包或是同名的服務(wù)。
Puppet 的第二個(gè)重要?jiǎng)?chuàng)新是提供了一種方法,來(lái)直接指定資源之間的依賴關(guān)系。之前的各種工具的關(guān)注點(diǎn)都在于某個(gè)孤立的工作是否完成,而非它們之間的各種關(guān)聯(lián)性;Puppet 是第一種明確地將依賴關(guān)系作為配置中的一等元素的工具,而且,必須在建模中明確指出依賴型。Puppet 會(huì)根據(jù)資源及其依賴型構(gòu)建出一張圖,在 Puppet 的執(zhí)行過(guò)程中,每件事情都對(duì)應(yīng)于這張圖(稱為目錄, Catalog)和圖的頂點(diǎn)與邊。
Puppet 的最后一個(gè)重要組成部分是它的配置語(yǔ)言。這是一種聲明性的語(yǔ)言,其重點(diǎn)在于配置數(shù)據(jù),而非編程。很大程度上說(shuō),它沿襲了 Nagios 的配置格式,不過(guò)也受到了 CFEngine 和 Ruby 的很大影響。
除了功能性組件之外,在 Puppet 開(kāi)發(fā)過(guò)程中,還有兩個(gè)指導(dǎo)性原則:簡(jiǎn)單勝過(guò)一切,易用性勝于能力;先做框架,再做應(yīng)用,其他人可以在 Puppet 的基礎(chǔ)上開(kāi)發(fā)它們自己的應(yīng)用??梢赃@么理解,Puppet 框架需要一個(gè)殺手級(jí)的應(yīng)用(Puppet 本身)來(lái)讓自己獲得廣泛接受,但框架始終是關(guān)注的焦點(diǎn),而非應(yīng)用。當(dāng)然,大部分人開(kāi)始會(huì)將 Puppet 作為一個(gè)應(yīng)用來(lái)使用,而非其背后的框架。
當(dāng) Puppet 的原型剛剛搭建出來(lái)時(shí),Luke 還是一個(gè) Perl 程序員,也有不少 shell 經(jīng)驗(yàn)以及一些 C 的經(jīng)驗(yàn),主要使用 CFEngine 工作。不尋常的一點(diǎn)是,他擁有為簡(jiǎn)單語(yǔ)言寫(xiě)解析器的經(jīng)驗(yàn),曾經(jīng)為一些小工具寫(xiě)過(guò)解析器部分,也從頭重寫(xiě)過(guò) CFEngine 的解析器,來(lái)讓它更容易維護(hù)(這段代碼從未被提交到上游項(xiàng)目中去,因?yàn)橛行┬〉募嫒菪詥?wèn)題)。
對(duì)于 Puppet 的實(shí)現(xiàn),選擇一個(gè)動(dòng)態(tài)語(yǔ)言是沒(méi)什么爭(zhēng)議的,因?yàn)閯?dòng)態(tài)語(yǔ)言的開(kāi)發(fā)效率會(huì)更高,但是選擇一個(gè)合適的語(yǔ)言卻十分困難。最初的使用 Perl 的原型不是非常好用,所以 Luke 開(kāi)始考慮其他語(yǔ)言。Python 曾經(jīng)被考察過(guò),但 Luke 發(fā)現(xiàn)這種語(yǔ)言和他的世界觀不夠匹配。在朋友的關(guān)于語(yǔ)言易用性的言論影響下,Luke 嘗試了 Ruby,4小時(shí)之后,他就使用 Ruby 完成了一個(gè)可用的原型。在2005年,當(dāng) Puppet 成為 Luke 的全職項(xiàng)目時(shí),Ruby 還是一種默默無(wú)聞的語(yǔ)言,這個(gè)決定顯然有巨大的風(fēng)險(xiǎn),程序員的開(kāi)發(fā)效率是選擇 Ruby 的決定性因素。相對(duì)于 Perl,Ruby 的最顯著的特性是,非常容易構(gòu)建非層次式的(non-hierarchical)類間關(guān)系,這和 Luke 所想的非常匹配,這之后被證明是決定性的(critical)。
本章主要討論 Puppet 的實(shí)現(xiàn)架構(gòu)(也就是我們用來(lái)讓 Puppet 來(lái)完成我們想讓它進(jìn)行的工作的代碼),不過(guò),簡(jiǎn)要探討一下應(yīng)用架構(gòu)(也就是程序的各個(gè)部分之間如何通信)也會(huì)很有幫助,這會(huì)讓我們對(duì)實(shí)現(xiàn)有所感覺(jué)。
Puppet 支持兩種工作模式:客戶機(jī)/服務(wù)器模式,由一個(gè)中心服務(wù)器和部署到各個(gè)主機(jī)上的代理(agent)構(gòu)成;或無(wú)服務(wù)器模式(serverless),由一個(gè)單獨(dú)的進(jìn)程完成所有工作。為了確保這些模式之間的一致性,Puppet 內(nèi)部始終是對(duì)網(wǎng)絡(luò)透明的,這樣,兩種模式可以使用相同的代碼,只是是否走網(wǎng)絡(luò)有所不同。每個(gè)可執(zhí)行程序都可以根據(jù)需要配置使用本地或遠(yuǎn)程服務(wù),除此之外,它們的行為都是完全一致的。注意,你也可以在進(jìn)行客戶機(jī)/服務(wù)器使用的情況下使用無(wú)服務(wù)器模式,只要將所有配置文件推送到每個(gè)客戶端上,并讓它們直接解析這些文件即可。本節(jié)將集中在客戶機(jī)/服務(wù)器模式上,因?yàn)檫@樣更易于把各個(gè)功能理解為彼此獨(dú)立的組件,不過(guò)請(qǐng)各位明白,這些實(shí)際上在無(wú)服務(wù)器模式下也是同樣的。
Puppet 架構(gòu)上的一個(gè)設(shè)計(jì)決策是,認(rèn)為客戶端不應(yīng)該直接訪問(wèn)到 Puppet 模塊;相反,它們應(yīng)該得到專為它們編譯的配置。這樣做有很多好處:首先,這遵從了最小權(quán)限準(zhǔn)則,每臺(tái)主機(jī)只能得到它自己需要知道的(它該如何配置自己),不會(huì)知道其他服務(wù)器如何配置。其次,你可以將編譯配置的權(quán)限(需要訪問(wèn)中央數(shù)據(jù)存儲(chǔ))和實(shí)施配置的權(quán)限彼此分離。第三,當(dāng)主機(jī)之后每次應(yīng)用配置的時(shí)候,可以處于離線狀態(tài),無(wú)需與中央服務(wù)器保持連接,這意味著即使是服務(wù)器當(dāng)即了,或者兩者無(wú)法連接了(比如,移動(dòng)客戶端,或是客戶端位于DMZ中等),也可以重復(fù)應(yīng)用配置。
這樣,Puppet 的工作流就比較直接了:
這樣,代理?yè)碛性L問(wèn)它自己的系統(tǒng)信息、配置、以及它自己生成的報(bào)告的權(quán)限。服務(wù)器擁有這些數(shù)據(jù)的副本,還有訪問(wèn)所有 Puppet 模塊、后端數(shù)據(jù)庫(kù)和可能用于編譯配置信息的服務(wù)的權(quán)限。
這個(gè)工作流圖中的組件之外,我們后面還會(huì)用到很多 Puppet 用來(lái)進(jìn)行內(nèi)部通信的數(shù)據(jù)類型。這些數(shù)據(jù)類型非常重要,因?yàn)檫@些數(shù)據(jù)中有些是決定了各種通信如何進(jìn)行,有些公開(kāi)類型影響到其他工具如何產(chǎn)生或使用這些與 Puppet 交互的數(shù)據(jù)。
最重要的數(shù)據(jù)類型包括:
在 Facts, Manifests, Catalogs, 和 Reports 之外,Puppet 還支持 files, certificates (用于鑒權(quán))等服務(wù)類型。
更多建議: