天天看點

puppet簡介作為工具的 puppet穩定性puppet的細節和原理底層支撐工具 Providers修改系統配置資源之間的關系exec 資源puppet 語言資源避免重複配置類 classInheritance 繼承一個複雜的真實的例子語言的其他特性puppet 語言進階特性典型的puppet使用方法總結

系統管理者都喜歡自己寫點小工具來讓自己的工作完成的更快或者更好, 不管是在大企業管理大量的伺服器還是隻管理兩三台機器. 但是很少人會把他們的工具釋出出來. 也就是是說極少有工具能被重用,或者說很多工具就隻能在所在的組織内部有用.拷貝給别的組織,他們也用不上. 也就是說,每個系統管理者,在一個新的公司,都會另起爐竈開發一套基于ssh,for循環的"系統"來幫助自己完成系統管理任務.

開發puppet是為了讓系統管理者社群可以互相交流和共享成熟的工具,避免重複的勞動. 通過以下兩個特性來實作這一目标:

  1. 提供一個簡潔的但是強大的架構來完成系統管理任務
  2. 系統管理任務可以描述成puppet語言,是以可以互相分享代碼,就像分享其他語言的代碼一樣,比如python, c等

是以,作為系統管理者的你可以更快的完成工作,因為你可以用puppet來處理所有的管理細節. 甚至你還可以下載下傳其他管理者的puppet代碼來讓你的工作完成的更快.

作為工具的 puppet

puppet是一個配置管理工具, 典型的, puppet是一個C/S結構, 當然,這裡的C可以有很多,是以,也可以說是一個星型結構. 所有的puppet用戶端同一個伺服器端的puppet通訊. 每個puppet用戶端每半小時(可以設定)連接配接一次伺服器端, 下載下傳最新的配置檔案,并且嚴格按照配置檔案來配置伺服器. 配置完成以後,puppet用戶端可以回報給伺服器端一個消息. 如果出錯,也會給伺服器端回報一個消息. 下圖展示了一個典型的puppet配置的資料流動情況.

puppet簡介作為工具的 puppet穩定性puppet的細節和原理底層支撐工具 Providers修改系統配置資源之間的關系exec 資源puppet 語言資源避免重複配置類 classInheritance 繼承一個複雜的真實的例子語言的其他特性puppet 語言進階特性典型的puppet使用方法總結

穩定性

puppet與其他手工操作工具有一個最大的差別就是 puppet的配置具有穩定性,是以你可以多次執行puppet, 一旦你更新了你的配置檔案,puppet就會根據配置檔案來更改你的機器配置,通常每30分鐘檢查一次. puppet會讓你的系統狀态同配置檔案所要求的狀态保持一緻. 比如你配置檔案裡面要求ssh服務必須開啟. 假如不小心ssh服務被關閉了,那麼下一次執行puppet的時候,puppet會發現這個異常,然後會開啟 ssh 服務. 以使系統狀态和配置檔案保持一緻.puppet就象一個魔術師,會讓你的混亂的系統收斂到puppet配置檔案所想要的狀态.

可以使用puppet管理伺服器的整個生命周期,從初始化到退役.不同于傳統的例如sun的Jumpstart或者redhat的Kickstart, puppet可以長年讓伺服器保持最新狀态.隻要一開始就正确的配置他們,然後再也不用去管他們.通常puppet使用者隻需要給機器安裝好puppet并讓他們運作,然後剩餘的工作都由puppet來完成.

puppet的細節和原理

puppet的目的是讓你隻集中于你要管理的目标,而忽略實作的細節,例如指令名,參數或者檔案格式. puppet把系統裡面的使用者,軟體包,服務 看作是"資源", puppet的作用就是管理這些資源以及資源之間的互相聯系.

底層支撐工具 Providers

puppet有很多的資源類型,例如檔案,使用者,軟體包,服務, 不同的作業系統上對資源的管理指令是不一樣的,例如debian下面用apt-get安裝軟體,redhat下面用yum安裝軟體.

是以 puppet 對同一資源的管理可以有多個實作,配置資源的時候,可以明确的指定用什麼provider. 例如在redhat上配置一個package資源的時候,可以指定provide是yum.

修改系統配置

puppet 通過管理資源的方式來管理系統, 例如管理某個軟體是否要安裝,是安裝最新的還是安裝了就行. 管理某個服務是否開啟, 管理某個檔案的屬性,内容等等. 所有的資源都有對應的幾個屬性可以設定. 通過設定屬性的方式來管理資源. 有一種特殊的屬性可以用在所有的資源上面,這種屬性叫做 metaparams ( 元參數或者元屬性).

資源之間的關系

支援資源之間的關系配置是puppet的關鍵特性之一. 一個資源的變更可以對另一個資源産生一個動作.例如 /etc/apache.conf這個資源有改動,可以讓/etc/init.d/apache 這個資源 reload一下.

假如一個資源依賴另一個資源,那麼puppet會優先配置被依賴的資源,是以如果你的配置檔案沒有準備好,對應的 服務是不會先啟動的.

exec 資源

有時候,沒有合适的資源來管理伺服器上的配置, 為了處理這個情況,puppet 提供一個叫做 exec的資源類型. 利用這個資源,你可以執行外部指令. 例如你可以用svnadmin指令來建立一個svn庫.

puppet 語言

資源

puppet的全部就是管理資源,是以puppet語言的焦點就是處理這些資源,下面是一個基本的管理單個資源的例子.

file {"/etc/hosts":

    owner = root,

    group = root,

    mode = 644

}

上面的列子給出了定義一個資源所需要的所有元件,類型,名字和屬性. 定義了一個 file 資源, 資源的title(标題)是 "/etc/hosts", 資源的屬性裡面設定了該檔案屬于那個使用者群組,以及檔案的權限.

也可以在一個大括号裡面定義多個資源,通過分号來區分.

file {

  "/etc/sudoers":

    owner = "root",

    group = "root",

    mode  = 644;

  "/usr/sbin/sudo":

    mode  = 4111

避免重複配置

puppet的編譯器會避免在不同的代碼段裡面管理同一個資源, 如果在不同的代碼段對同一個資源進行配置,執行puppet的時候你會得到一個文法錯誤.

puppet探測這種沖突的情況是通過判斷資源類型和資源的title(标題 ); 如果兩個資源有相同的資源類型和title; 那麼就認為這兩個資源是表示同一個資源.

類 class

下面讨論如何組合各種資源, 把多個相關的資源定義在一起,組成一個類. 例如下面的代碼.

class sudo {

  package { sudo: ensure = installed }

  file { 

    "/etc/sudoers":

      owner = "root",

      group = "root",

      mode  = 644;

    "/usr/sbin/sudo":

      mode  = 4111

  }

你在别的代碼段 include sudo 這個類,就會把sudo這個軟體包(package 那裡定義)安裝好,以及兩個配置檔案設定好.

Inheritance 繼承

puppet 支援有限制的類的繼承, 但是它隻有一個唯一的作用就是: 子類裡面的屬性可以覆寫父類裡面的屬性. 下面是一個勉強正确的例子.

class base {

  file { "/my/file": content = template("base.erb") }

class sub inherits base {

  # override the content

  File["/my/file"] { content = template("other.erb") }

注意,在子類裡面的資源類型的定義是用的大寫的 File ;表示對這個資源重新定義,如果用小寫的 file;就會引起前面說的資源的重複配置的情況.得到一個文法錯誤.

一個複雜的真實的例子

生活總是不容易阿, 真實環境中,一個包經常關聯到幾個服務,同時又關聯到不同的配置檔案. 幾乎所有的類unix系統裡面都有ssh服務. 通常,你不隻是想安裝ssh包,而且你還想啟動ssh 服務.看看下面的例子

class ssh {

  package { ssh: ensure = installed }

  file { sshd_config:

    name = $operatingsystem ? {

      Darwin  = "/etc/sshd_config",

      Solaris = "/opt/csw/etc/ssh/sshd_config",

      default = "/etc/ssh/sshd_config"

    },

    source = "puppet://server.domain.com/files/ssh/sshd_config"

  service { ssh:

      Solaris = openssh,

      default = ssh

    ensure    = running,

    subscribe = [Package[ssh], File[sshd_config]]

上面的代碼安裝好ssh包,并開啟ssh服務,因為在不同的作業系統上面,ssh的配置檔案名字不一樣,是以還可以通過判斷作業系統的類型來指定資源的title(标題). 那麼作業系統的類型是怎麼判斷的呢? 下面就會解釋這個問題.

Facter Variables facter 變量

在上面的ssh 代碼裡面,我們引入了一些新的東西,首先是 $operatingsystem 這個變量, 這個變量被引用,在puppet分析代碼的時候,會把從 facter 傳送過來的對應的值指派給這個變量. 你可以單獨手工執行facter這個指令,這個指令會列印出它所收集到的關于主機的資訊,例如ip位址等等. facter把收集到值發送個puppet伺服器端,伺服器端就可以根據不同的條件來對不同的機器生成不同的puppet配置檔案. 最重要的一個就是伺服器的主機名.

selectors 選擇器

另一個新東西就是 ? { … } 這個文法, 通過對 ? 前面的變量與括号裡面的選擇項進行對比,然後把相應的值指派給資源,例如上面的例子, $operatingsystem 如果是solaris ,那麼ssh這個資源的 name 屬性就是 "openssh" ;如果不比對,就指派成defualt的指, 比對将區分大小寫.

title vs name (标題和名字)

如果你足夠細心,你會發現我們資源指定了第 2個名字 ,例如上面的 service 資源 ssh. 注意,冒号前面的名字叫做 title (标題), 标題的作用讓作者辨別不同的資源,是寫給人以及puppet文法分析器看的. 是以配置資源互相關系的時候,也是用資源的title. name是指定這個資源的具體路徑,是寫給計算機看的. 通常,name 會預設和title的值一樣. 是以,你可以省略name. 隻有情況特殊的時候才設定name屬性.

最後,我們來分析所有資源直接的關系,配置檔案,包,服務.最後一行的 File[sshd_config] 文法指定了一個資源參考,注意這裡是用的資源的title ,這樣你就不用指定資源的全路徑.

subscribe = [Package[ssh], File[sshd_config]] 這個語句表示,如果package "ssh" 或者 檔案" sshd_config"有修改, service ssh需要重新開機.

語言的其他特性

真相

幾乎所有的東西和符号在puppet裡面都被看作是字元串,包括數字和布爾值. 但是如果你用引号把true和false引起來,他們會被當做字元串,例如你想指派給某個資性"yes"的 字元串.

變量

我們已經看過什麼是變量了,當然,你還可以直接給他指派,例如

$myvar = value

puppet 不允許你在同一個類裡面對一個變量進行兩次指派.

更多的條件語句

我們已經在前面介紹過了選擇器(selectors),在為變量選擇特定的值的時候非常有用,Puppet同時也支援條件語句,使得你能根據不同的條件導入不同的資源定義(resource specifications):

case $operatingsystem {

Darwin: { file { "/some/file": ensure => present } }

default: { file { "/other/file": ensure => present } }

與選擇器(selectors)配合, case 語句可以進行 case-insensitive 比對。

這裡還有一個簡單的if/else結構:

if $should {

file { "/some/file": ensure => present }

} else {

file { "/other/file": ensure => present }

另外,Puppet從版本0.24.6開始支援比較運算符。

數組

puppet 非常有限的支援數組這種類型,你可以建立數組,并且給他們指派,但是你不能删除它們.數組用的最多的情況就是上面ssh例子裡面,資源依賴哪種情況. 或者是一次管理多個相同類型的資源.例如:

user { [bin, adm]: ensure = present }

函數

puppet 支援簡單的函數文法,例如

notice("This is a log message")

puppet提供一些有用的函數,例如template利用erb模闆來生成檔案内容,這樣就可以根據不同主機的情況,生成不同的配置檔案.例如配置squid的記憶體緩存大小,可以利用facter傳回的記憶體值做一個簡單的數學計算,然後寫入到squid的配置檔案,就是通過template來完成的. 另外一個函數include 可以讀入另外的puppet配置檔案或者類.這樣可以把puppet的檔案分割的更有規律.

puppet 語言進階特性

定義

puppet裡面有一個非常有用的文法結構,叫做"definitions", 通過 definitions 可以把多個資源包裝成一個資源,或者把一個資源包裝成一個模型,便于使用.例如,在debian裡面管理一個apache虛拟機非常簡單,把一個虛拟主機的配置檔案放到/etc/sites-available/裡面,然後做一個符号連結到/etc/sites-enabled目錄. 你可以為你每個虛拟主機複制同樣的配置代碼,但是如果你使用下面的代碼就會更好和更簡單.

define virtual_host($docroot, $ip, $order = 500, $ensure = "enabled") {

   $file = "/etc/sites-available/$name.conf"

   # The template fills in the docroot, ip, and name.

   file { $file:

       content => template("virtual_host.erb"),

       notify  => Service[apache]

   }

   file { "/etc/sites-enabled/$order-$name.conf":

       ensure => $ensure ? {

           enabled  => $file,

           disabled => absent

       }

然後,你就可以使用這個定義來管理一個apache虛拟主機,如下面代碼所示

virtual_host { "reductivelabs.com":

    order   => 100,

    ip      => "192.168.0.100",

    docroot => "/var/www/reductivelabs.com/htdocs"

你可以在其他地方重用這個定義, 另一個定義的用法就是包裝一組exec資源,讓使用者更加清晰思路.例如下面的代碼實作了一個svn庫的建立的定義.

# Create a new subversion repository.

define svnrepo($path) {

    exec { "create-svn-$name":

        command => "/usr/bin/svnadmin create $path/$name",

        creates => "$path/$name" # only run if this file does not exist

    }

然後,你可以在其他地方用下面的代碼來建立一個svn庫

svnrepo { puppet: path => "/var/lib/svn" }

nodes 節點

最後一個關于puppet語言的文法是 節點定義(node definition), 節點定義很象類定義,也支援繼承特性. 當一個節點(puppet用戶端)連接配接到puppet伺服器端,puppet解析器會查找這個節點的node代碼片斷,然後利用這個代碼片斷來生成該用戶端的配置代碼. puppet裡面主機名來标明一個主機,是以主機名在puppet裡面相當重要. 如果puppet找不到比對該主機名的node定義,就會用預設的節點定義來配置該主機. 在node裡面使用主機名,需要用單引号把主機名括起來.

node 'www.example.com' {

        include publickey_auth

        }

在上面的代碼中,如果www.example.com這個主機連接配接到puppet伺服器,puppet伺服器就會按照上面的代碼來配置www.example.com這個機器.

典型的puppet使用方法

puppet既可以在單機上使用,也可以以c/s結構使用.在大規模使用puppet的情況下,通常使用c/s結構.在這種結構中puppet用戶端隻是指運作puppet的伺服器,puppet伺服器端是隻運作puppetmaster的伺服器.

puppet用戶端首先會連接配接到puppet伺服器端,并且通過facter工具把用戶端的配置資訊發送給伺服器端. 伺服器端通過分析用戶端的主機名,通過node 定義,找到該主機的配置代碼,然後編譯配置代碼,把編譯好的配置代碼發回用戶端. 用戶端執行代碼完成配置.并且把代碼執行情況回報給puppet伺服器端.

總結

以上列舉了許多非常有用的用法,但所有的這些隻是Puppet功能的一個大概介紹。這裡有一份全面的[

文檔

],裡面附帶了許多例子:為了讓你能過更加深入的了解Puppet。我們會一直維護這個文檔,是以如果你有什麼具體的要求,請通過

puppetlabs.com

與我們聯系。