卷2:第18章 Puppet part 1

2018-02-24 15:55 更新

18.1. 概述

Puppet 是一個用 Ruby 寫的開源 IT 管理工具,用于數(shù)據(jù)中心自動化和服務(wù)器的管理,用戶包括 Google, Twitter, 紐約證券交易所以及很多其他機(jī)構(gòu)。Puppet 的主要維護(hù)者是 Puppet Labs,也就是 Puppet 項目的發(fā)起者。Puppet 可以管理從 2 臺到 5 萬臺機(jī)器,管理員可以只有1個人或者是上百人。

Puppet 是一個用于配置和維護(hù)計算機(jī)的工具;通過使用 puppet 的簡單的配置語言,你可以告訴 Puppet,你希望如何配置機(jī)器,然后 Puppet 就會按照你的指示來修改機(jī)器的配置。之后,如果你改變了需求,比如更新了軟件包,增加了新用戶,或是更新了配置,那么 Puppet 也會自動地隨之更新你的機(jī)器。而如果這些機(jī)器本來就已經(jīng)配置好了,Puppet 就什么都不會動。

總的講,Puppet 可以借助任何已有的系統(tǒng)特性來完成它的工作。比如,在 Red Hat 中,它會使用yum?來進(jìn)行包管理,并修改?init.d?來管理系統(tǒng)服務(wù);而在 OS X 中,Puppet 則使用 dmg 來管理軟件包,使用?launchd?來管理系統(tǒng)服務(wù)。Puppet 的一個目標(biāo)就是讓你或者系統(tǒng)本身都可以通過 Puppet 代碼來明白如何進(jìn)行工作,所以,必須要能夠遵從各個系統(tǒng)的規(guī)范。

Puppet 集成了很多已有工具的傳統(tǒng)。從開源社區(qū)的角度講,對 Puppet 影響最大的莫過于 CF-Engine 和 ISconf 了,CF-Engine 是第一個開源通用配置管理工具,而 ISconf 使用了?make?來完成所用工作,其靈感來源于顯式地處理系統(tǒng)中所有的依賴關(guān)系。在商業(yè)軟件中,Puppet 受到了 BladeLogic 和 Opsware (兩者都已經(jīng)被大公司收購了)的影響,在 Puppet 項目開始時,這兩種工具都在市場中獲得了不小的成功,不過兩者都更加關(guān)注于向大公司的管理層來推銷,相反,對于直接為管理員提供一個強(qiáng)大的工具,沒有足夠的重視。Puppet 希望和這些工具解決差不多的問題,但關(guān)注的用戶有很大不同。

這個簡單的例子用于解釋如何使用 Puppet,例子中的這段代碼用來確保系統(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]]
    }
 }

這個配置確保軟件包被安裝,文件就位,并且服務(wù)運行。注意,我們指定了資源之間的依賴關(guān)系,這樣,我們就可以確保一定能夠按照正確順序工作。這個類 (class) 可以被關(guān)聯(lián)到任何一個需要這個配置的主機(jī)。Puppet 配置的基本組件是結(jié)構(gòu)化的對象,在這個例子里就是?package,?file?和service。我們將這些對象稱為資源 (resource),Puppet 配置中的任何東西,最后都會分解為一些資源,以及資源間的依賴關(guān)系。

通常,一個使用 Puppet 的機(jī)構(gòu)可能擁有數(shù)十甚至上百個這樣的代碼段,我們稱之為類 (class),我們將存儲這些類的文件稱為貨單 (manifest),這些被按照相關(guān)性分組,這些組稱為模塊 (module)。比如,你可能有個?ssh?模塊,其中包含了這個?ssh?類和一些其他相關(guān)類,同時還會有諸如?mysql,apache, 以及?sudo?等模塊。

大部分的 Puppet 交互都通過命令行或是一直運行著的 HTTP 服務(wù)進(jìn)行的,不過有些東西也有圖形界面,比如報告處理。Puppet Labs 還提供了一些 Puppet 的周邊商業(yè)產(chǎn)品,這些產(chǎn)品更傾向于使用基于 web 的圖形化界面。

Puppet 的第一個原型寫于2004年夏天,從2005年2月開始成為了一個有全職投入的項目。Puppet 最初由 Luke Kanies 設(shè)計并實現(xiàn),它是一位經(jīng)驗豐富、寫過很多不足萬行的小工具的管理員。本質(zhì)上說,隨著 Puppet 的開發(fā),Luke 學(xué)著稱為了一位程序員,從程序架構(gòu)上說,這具有正反兩面性。

Puppet 最初并最重要的目的就是成為一個管理員的工具,讓他們的工作更輕松、更快、更高效,且更不易犯錯。第一個關(guān)鍵性的創(chuàng)新就是上面提到的資源,這是 Puppet 的基本元素,它們是跨操作系統(tǒng)可移植的,并且抽象的資源屏蔽了實現(xiàn)細(xì)節(jié),允許用戶關(guān)注配置的結(jié)果,而非具體如何實現(xiàn)這些配置。而這些基本元素本身由 Puppet 的資源抽象層來實現(xiàn)。

在一臺給定的主機(jī)上,Puppet 資源必須是唯一的。你只能有一個叫 "ssh" 的包,一個叫 "sshd" 的服務(wù),也只能有一個叫 "/etc/ssh/sshd_config" 的文件。這就避免了你的配置的不同部分之間的沖突,一旦發(fā)生沖突,你會在進(jìn)行配置的最初階段發(fā)現(xiàn)它。我們可以通過資源的名稱和類型來指定一個資源,比如?Package[ssh]?和?Service[sshd]。你可以有一個包和一個服務(wù)同名,因為它們類型不同,但不論如何,你都不可以有兩個同名的包或是同名的服務(wù)。

Puppet 的第二個重要創(chuàng)新是提供了一種方法,來直接指定資源之間的依賴關(guān)系。之前的各種工具的關(guān)注點都在于某個孤立的工作是否完成,而非它們之間的各種關(guān)聯(lián)性;Puppet 是第一種明確地將依賴關(guān)系作為配置中的一等元素的工具,而且,必須在建模中明確指出依賴型。Puppet 會根據(jù)資源及其依賴型構(gòu)建出一張圖,在 Puppet 的執(zhí)行過程中,每件事情都對應(yīng)于這張圖(稱為目錄, Catalog)和圖的頂點與邊。

Puppet 的最后一個重要組成部分是它的配置語言。這是一種聲明性的語言,其重點在于配置數(shù)據(jù),而非編程。很大程度上說,它沿襲了 Nagios 的配置格式,不過也受到了 CFEngine 和 Ruby 的很大影響。

除了功能性組件之外,在 Puppet 開發(fā)過程中,還有兩個指導(dǎo)性原則:簡單勝過一切,易用性勝于能力;先做框架,再做應(yīng)用,其他人可以在 Puppet 的基礎(chǔ)上開發(fā)它們自己的應(yīng)用??梢赃@么理解,Puppet 框架需要一個殺手級的應(yīng)用(Puppet 本身)來讓自己獲得廣泛接受,但框架始終是關(guān)注的焦點,而非應(yīng)用。當(dāng)然,大部分人開始會將 Puppet 作為一個應(yīng)用來使用,而非其背后的框架。

當(dāng) Puppet 的原型剛剛搭建出來時,Luke 還是一個 Perl 程序員,也有不少 shell 經(jīng)驗以及一些 C 的經(jīng)驗,主要使用 CFEngine 工作。不尋常的一點是,他擁有為簡單語言寫解析器的經(jīng)驗,曾經(jīng)為一些小工具寫過解析器部分,也從頭重寫過 CFEngine 的解析器,來讓它更容易維護(hù)(這段代碼從未被提交到上游項目中去,因為有些小的兼容性問題)。

對于 Puppet 的實現(xiàn),選擇一個動態(tài)語言是沒什么爭議的,因為動態(tài)語言的開發(fā)效率會更高,但是選擇一個合適的語言卻十分困難。最初的使用 Perl 的原型不是非常好用,所以 Luke 開始考慮其他語言。Python 曾經(jīng)被考察過,但 Luke 發(fā)現(xiàn)這種語言和他的世界觀不夠匹配。在朋友的關(guān)于語言易用性的言論影響下,Luke 嘗試了 Ruby,4小時之后,他就使用 Ruby 完成了一個可用的原型。在2005年,當(dāng) Puppet 成為 Luke 的全職項目時,Ruby 還是一種默默無聞的語言,這個決定顯然有巨大的風(fēng)險,程序員的開發(fā)效率是選擇 Ruby 的決定性因素。相對于 Perl,Ruby 的最顯著的特性是,非常容易構(gòu)建非層次式的(non-hierarchical)類間關(guān)系,這和 Luke 所想的非常匹配,這之后被證明是決定性的(critical)。

18.2. 架構(gòu)概覽

本章主要討論 Puppet 的實現(xiàn)架構(gòu)(也就是我們用來讓 Puppet 來完成我們想讓它進(jìn)行的工作的代碼),不過,簡要探討一下應(yīng)用架構(gòu)(也就是程序的各個部分之間如何通信)也會很有幫助,這會讓我們對實現(xiàn)有所感覺。

Puppet 支持兩種工作模式:客戶機(jī)/服務(wù)器模式,由一個中心服務(wù)器和部署到各個主機(jī)上的代理(agent)構(gòu)成;或無服務(wù)器模式(serverless),由一個單獨的進(jìn)程完成所有工作。為了確保這些模式之間的一致性,Puppet 內(nèi)部始終是對網(wǎng)絡(luò)透明的,這樣,兩種模式可以使用相同的代碼,只是是否走網(wǎng)絡(luò)有所不同。每個可執(zhí)行程序都可以根據(jù)需要配置使用本地或遠(yuǎn)程服務(wù),除此之外,它們的行為都是完全一致的。注意,你也可以在進(jìn)行客戶機(jī)/服務(wù)器使用的情況下使用無服務(wù)器模式,只要將所有配置文件推送到每個客戶端上,并讓它們直接解析這些文件即可。本節(jié)將集中在客戶機(jī)/服務(wù)器模式上,因為這樣更易于把各個功能理解為彼此獨立的組件,不過請各位明白,這些實際上在無服務(wù)器模式下也是同樣的。

Puppet 架構(gòu)上的一個設(shè)計決策是,認(rèn)為客戶端不應(yīng)該直接訪問到 Puppet 模塊;相反,它們應(yīng)該得到專為它們編譯的配置。這樣做有很多好處:首先,這遵從了最小權(quán)限準(zhǔn)則,每臺主機(jī)只能得到它自己需要知道的(它該如何配置自己),不會知道其他服務(wù)器如何配置。其次,你可以將編譯配置的權(quán)限(需要訪問中央數(shù)據(jù)存儲)和實施配置的權(quán)限彼此分離。第三,當(dāng)主機(jī)之后每次應(yīng)用配置的時候,可以處于離線狀態(tài),無需與中央服務(wù)器保持連接,這意味著即使是服務(wù)器當(dāng)即了,或者兩者無法連接了(比如,移動客戶端,或是客戶端位于DMZ中等),也可以重復(fù)應(yīng)用配置。

這樣,Puppet 的工作流就比較直接了:

  1. Puppet 代理進(jìn)程收集當(dāng)前主機(jī)的信息,并交給服務(wù)器。
  2. 解析器利用系統(tǒng)信息和磁盤上存儲的模塊信息,編譯為對這臺機(jī)器的一個配置信息,并將這些配置信息返回給代理。
  3. 代理將配置應(yīng)用到本地主機(jī),這將影響主機(jī)的本地狀態(tài),之后,將結(jié)果狀態(tài)匯報給服務(wù)器。

Puppet 數(shù)據(jù)流

Puppet 組件間與進(jìn)程間數(shù)據(jù)流匯編

這樣,代理擁有訪問它自己的系統(tǒng)信息、配置、以及它自己生成的報告的權(quán)限。服務(wù)器擁有這些數(shù)據(jù)的副本,還有訪問所有 Puppet 模塊、后端數(shù)據(jù)庫和可能用于編譯配置信息的服務(wù)的權(quán)限。

這個工作流圖中的組件之外,我們后面還會用到很多 Puppet 用來進(jìn)行內(nèi)部通信的數(shù)據(jù)類型。這些數(shù)據(jù)類型非常重要,因為這些數(shù)據(jù)中有些是決定了各種通信如何進(jìn)行,有些公開類型影響到其他工具如何產(chǎn)生或使用這些與 Puppet 交互的數(shù)據(jù)。

最重要的數(shù)據(jù)類型包括:

  • Facts: 從每臺機(jī)器上收集到的系統(tǒng)數(shù)據(jù),用于編譯為配置。
  • Manifest: 包含 Puppet 代碼的文件,通常被組織為一些稱為“模塊 (modules)”的集合中。
  • Catalog: 一張包含主機(jī)上可管理資源及其依賴關(guān)系的圖。
  • Report: 對于一個 Catalog,在其應(yīng)用過程中產(chǎn)生的所有事件的集合。

在 Facts, Manifests, Catalogs, 和 Reports 之外,Puppet 還支持 files, certificates (用于鑒權(quán))等服務(wù)類型。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號