Puppet - 即時專案



為了執行在 Puppet 節點上應用配置和清單的即時測試,我們將使用一個即時工作演示。這可以直接複製和貼上以測試配置的工作方式。如果使用者希望使用同一組程式碼,則需要使用程式碼片段中所示的相同命名約定。

讓我們從建立新模組開始。

建立新模組

測試和應用 httpd 配置的第一步是建立模組。為此,使用者需要將其工作目錄更改為 Puppet 模組目錄並建立基本的模組結構。結構建立可以手動完成,也可以使用 Puppet 為模組建立樣板。

# cd /etc/puppet/modules 
# puppet module generate Live-module

注意 - Puppet 模組生成命令要求模組名稱採用 [使用者名稱]-[模組] 的格式,以符合 Puppet Forge 規範。

新模組包含一些基本檔案,包括一個清單目錄。該目錄已包含一個名為 init.pp 的清單,它是模組的主清單檔案。這是模組的空類宣告。

class live-module { 
} 

該模組還包含一個測試目錄,其中包含一個名為init.pp的清單。此測試清單包含對清單/init.pp 中的 live-module 類的引用。

include live-module

Puppet 將使用此測試模組來測試清單。現在我們準備向模組新增配置。

安裝 HTTP 伺服器

Puppet 模組將安裝執行 http 伺服器所需的軟體包。這需要一個資源定義來定義 httpd 軟體包的配置。

在模組的清單目錄中,建立一個名為 httpd.pp 的新清單檔案。

# touch test-module/manifests/httpd.pp

此清單將包含我們模組的所有 HTTP 配置。出於分離目的,我們將 httpd.pp 檔案與 init.pp 清單檔案分開。

我們需要將以下程式碼放入 httpd.pp 清單檔案中。

class test-module::httpd { 
   package { 'httpd': 
      ensure => installed, 
   } 
}

此程式碼定義了名為 httpd 的 test-module 的子類,然後為 httpd 軟體包定義了軟體包資源宣告。ensure => installed 屬性檢查是否安裝了所需的軟體包。如果未安裝,Puppet 使用 yum 實用程式安裝它。接下來,是將此子類包含在我們的主清單檔案中。我們需要編輯 init.pp 清單。

class test-module { 
   include test-module::httpd 
}

現在,是時候測試模組了,可以按如下方式完成。

# puppet apply test-module/tests/init.pp --noop

puppet apply 命令將清單檔案中存在的配置應用於目標系統。在這裡,我們使用 test init.pp,它引用主 init.pp。–noop 執行配置的預執行,它只顯示輸出,但實際上什麼也不做。

以下是輸出。

Notice: Compiled catalog for puppet.example.com in environment 
production in 0.59 seconds 

Notice: /Stage[main]/test-module::Httpd/Package[httpd]/ensure: 
current_value absent, should be present (noop) 

Notice: Class[test-module::Httpd]: Would have triggered 'refresh' from 1 
events 

Notice: Stage[main]: Would have triggered 'refresh' from 1 events 
Notice: Finished catalog run in 0.67 seconds 

突出顯示的行是 ensure => installed 屬性的結果。current_value absent 意味著 Puppet 已檢測到 httpd 軟體包已安裝。如果沒有 –noop 選項,Puppet 將安裝 httpd 軟體包。

執行 httpd 伺服器

安裝 httpd 伺服器後,我們需要使用其他資源宣告:Service 啟動服務。

我們需要編輯 httpd.pp 清單檔案並編輯以下內容。

class test-module::httpd { 
   package { 'httpd': 
      ensure => installed, 
   } 
   service { 'httpd': 
      ensure => running, 
      enable => true, 
      require => Package["httpd"], 
   } 
}

以下是我們從以上程式碼中實現的目標列表。

  • ensure => running 狀態檢查服務是否正在執行,如果不是,則啟用它。

  • enable => true 屬性將服務設定為在系統啟動時執行。

  • require => Package["httpd"] 屬性定義了一個資源宣告與另一個資源宣告之間的排序關係。在上述情況下,它確保 httpd 服務在 http 軟體包安裝後啟動。這在服務和相應軟體包之間建立了依賴關係。

執行 puppet apply 命令再次測試更改。

# puppet apply test-module/tests/init.pp --noop 
Notice: Compiled catalog for puppet.example.com in environment 
production in 0.56 seconds 

Notice: /Stage[main]/test-module::Httpd/Package[httpd]/ensure: 
current_value absent, should be present (noop) 

Notice: /Stage[main]/test-module::Httpd/Service[httpd]/ensure: 
current_value stopped, should be running (noop) 

Notice: Class[test-module::Httpd]: Would have triggered 'refresh' from 2 
events 

Notice: Stage[main]: Would have triggered 'refresh' from 1 events 
Notice: Finished catalog run in 0.41 seconds 

配置 httpd 伺服器

完成以上步驟後,我們將安裝並啟用 HTTP 伺服器。下一步是為伺服器提供一些配置。預設情況下,httpd 在 /etc/httpd/conf/httpd.conf 中提供一些預設配置,這些配置提供了一個 webhost 埠 80。我們將新增一些其他主機以向 web-host 提供一些使用者特定的功能。

模板將用於提供其他埠,因為它需要可變輸入。我們將建立一個名為 template 的目錄,並在新目錄中新增一個名為 test-server.config.erb 的檔案,並新增以下內容。

Listen <%= @httpd_port %> 
NameVirtualHost *:<% = @httpd_port %> 

<VirtualHost *:<% = @httpd_port %>> 
   DocumentRoot /var/www/testserver/ 
   ServerName <% = @fqdn %> 
   
   <Directory "/var/www/testserver/"> 
      Options All Indexes FollowSymLinks 
      Order allow,deny 
      Allow from all 
   </Directory> 
</VirtualHost>

以上模板遵循標準的 apache-tomcat 伺服器配置格式。唯一的區別是使用 Ruby 跳脫字元從模組注入變數。我們有 FQDN,它儲存系統的完全限定域名。這被稱為系統事實

在生成每個相應系統的 Puppet 目錄之前,從每個系統收集系統事實。Puppet 使用 facter 命令獲取此資訊,並且可以使用 facter 獲取有關係統的其他詳細資訊。我們需要在 httpd.pp 清單檔案中新增突出顯示的行。

class test-module::httpd { 
   package { 'httpd': 
      ensure => installed, 
   } 
   service { 'httpd': 
      ensure => running, 
      enable => true, 
      require => Package["httpd"], 
   } 
   file {'/etc/httpd/conf.d/testserver.conf': 
      notify => Service["httpd"], 
      ensure => file, 
      require => Package["httpd"], 
      content => template("test-module/testserver.conf.erb"), 
   } 
   file { "/var/www/myserver": 
      ensure => "directory", 
   } 
}

這有助於實現以下內容 -

  • 這為伺服器配置檔案(/etc/httpd/conf.d/test-server.conf)添加了一個檔案資源宣告。此檔案的內容是之前建立的 test-serverconf.erb 模板。我們還在新增此檔案之前檢查 httpd 軟體包是否已安裝。

  • 這添加了第二個檔案資源宣告,它為 Web 伺服器建立了一個目錄(/var/www/test-server)。

  • 接下來,我們使用notify => Service["httpd"]attribute新增配置檔案和 https 服務之間的關係。這會檢查是否存在任何配置檔案更改。如果有,則 Puppet 會重新啟動服務。

接下來是在主清單檔案中包含 httpd_port。為此,我們需要結束主 init.pp 清單檔案幷包含以下內容。

class test-module ( 
   $http_port = 80 
) { 
   include test-module::httpd 
}

這將 httpd 埠設定為預設值 80。接下來是執行 Puppet apply 命令。

以下是輸出。

# puppet apply test-module/tests/init.pp --noop 
Warning: Config file /etc/puppet/hiera.yaml not found, using Hiera 
defaults 

Notice: Compiled catalog for puppet.example.com in environment 
production in 0.84 seconds 

Notice: /Stage[main]/test-module::Httpd/File[/var/www/myserver]/ensure: 
current_value absent, should be directory (noop) 

Notice: /Stage[main]/test-module::Httpd/Package[httpd]/ensure: 
current_value absent, should be present (noop) 

Notice: 
/Stage[main]/test-module::Httpd/File[/etc/httpd/conf.d/myserver.conf]/ensure: 
current_value absent, should be file (noop) 

Notice: /Stage[main]/test-module::Httpd/Service[httpd]/ensure: 
current_value stopped, should be running (noop) 

Notice: Class[test-module::Httpd]: Would have triggered 'refresh' from 4 
events 

Notice: Stage[main]: Would have triggered 'refresh' from 1 events 
Notice: Finished catalog run in 0.51 seconds 

配置防火牆

為了與伺服器通訊,需要開啟埠。這裡的問題是不同型別的作業系統使用不同的防火牆控制方法。在 Linux 的情況下,6 版以下的版本使用 iptables,7 版及以上版本使用 firewalld。

使用適當服務的此決策在某種程度上由 Puppet 使用系統事實及其邏輯來處理。為此,我們需要首先檢查作業系統,然後執行相應的防火牆命令。

為了實現這一點,我們需要在 testmodule::http 類中新增以下程式碼片段。

if $operatingsystemmajrelease <= 6 { 
   exec { 'iptables': 
      command => "iptables -I INPUT 1 -p tcp -m multiport --ports 
      ${httpd_port} -m comment --comment 'Custom HTTP Web Host' -j ACCEPT && 
      iptables-save > /etc/sysconfig/iptables", 
      path => "/sbin", 
      refreshonly => true, 
      subscribe => Package['httpd'], 
   } 
   service { 'iptables': 
      ensure => running, 
      enable => true, 
      hasrestart => true, 
      subscribe => Exec['iptables'], 
   } 
}  elsif $operatingsystemmajrelease == 7 { 
   exec { 'firewall-cmd': 
      command => "firewall-cmd --zone=public --addport = $ { 
      httpd_port}/tcp --permanent", 
      path => "/usr/bin/", 
      refreshonly => true, 
      subscribe => Package['httpd'], 
   } 
   service { 'firewalld': 
      ensure => running, 
      enable => true, 
      hasrestart => true, 
      subscribe => Exec['firewall-cmd'], 
   } 
} 

以上程式碼執行以下操作 -

  • 使用operatingsystemmajrelease確定使用的 OS 是版本 6 還是 7。

  • 如果版本為 6,則它執行所有配置 Linux 6 版本所需的配置命令。

  • 如果 OS 版本為 7,則它執行配置防火牆所需的所有命令。

  • 兩個 OS 的程式碼片段都包含一個邏輯,該邏輯確保配置僅在 http 軟體包安裝後才執行。

最後,執行 Puppet apply 命令。

# puppet apply test-module/tests/init.pp --noop 
Warning: Config file /etc/puppet/hiera.yaml not found, using Hiera 
defaults 

Notice: Compiled catalog for puppet.example.com in environment 
production in 0.82 seconds 

Notice: /Stage[main]/test-module::Httpd/Exec[iptables]/returns: 
current_value notrun, should be 0 (noop) 

Notice: /Stage[main]/test-module::Httpd/Service[iptables]: Would have 
triggered 'refresh' from 1 events 

配置 SELinux

由於我們正在使用版本 7 及更高版本的 Linux 計算機,因此我們需要對其進行配置以進行 http 通訊。預設情況下,SELinux 限制對 HTTP 伺服器的非標準訪問。如果我們定義自定義埠,則需要配置 SELinux 以提供對該埠的訪問。

Puppet 包含一些資源型別來管理 SELinux 函式,例如布林值和模組。在這裡,我們需要執行 semanage 命令來管理埠設定。此工具是 policycoreutils-python 軟體包的一部分,預設情況下未安裝在 Red Hat 伺服器上。為了實現上述目標,我們需要在 test-module::http 類中新增以下程式碼。

exec { 'semanage-port': 
   command => "semanage port -a -t http_port_t -p tcp ${httpd_port}", 
   path => "/usr/sbin", 
   require => Package['policycoreutils-python'], 
   before => Service ['httpd'], 
   subscribe => Package['httpd'], 
   refreshonly => true, 
} 

package { 'policycoreutils-python': 
   ensure => installed, 
} 

以上程式碼執行以下操作 -

  • require => Package['policycoreutils-python'] 確保我們已安裝所需的 Python 模組。

  • Puppet 使用 semanage 使用 httpd_port 作為變數開啟埠。

  • before => service 確保在 httpd 服務啟動之前執行此命令。如果 HTTPD 在 SELinux 命令之前啟動,則 SELinux 服務請求和服務請求失敗。

最後,執行 Puppet apply 命令

# puppet apply test-module/tests/init.pp --noop 
... 
Notice: /Stage[main]/test-module::Httpd/Package[policycoreutilspython]/ 
ensure: current_value absent, should be present (noop) 
...
Notice: /Stage[main]/test-module::Httpd/Exec[semanage-port]/returns: 
current_value notrun, should be 0 (noop) 
... 
Notice: /Stage[main]/test-module::Httpd/Service[httpd]/ensure: 
current_value stopped, should be running (noop) 

Puppet 首先安裝 Python 模組,然後配置埠訪問,最後啟動 httpd 服務。

在 Web 主機中複製 HTML 檔案

透過以上步驟,我們完成了 http 伺服器配置。現在,我們擁有一個平臺,可以安裝基於 Web 的應用程式,Puppet 也可以配置它。為了測試,我們將一些示例 html index 網頁複製到伺服器。

在 files 目錄中建立 index.html 檔案。

<html> 
   <head> 
      <title>Congratulations</title> 
   <head> 
   
   <body> 
      <h1>Congratulations</h1> 
      <p>Your puppet module has correctly applied your configuration.</p> 
   </body> 
</html> 

在 manifest 目錄中建立一個名為 app.pp 的清單,並新增以下內容。

class test-module::app { 
   file { "/var/www/test-server/index.html": 
      ensure => file, 
      mode => 755, 
      owner => root, 
      group => root, 
      source => "puppet:///modules/test-module/index.html", 
      require => Class["test-module::httpd"], 
   } 
}

此新類包含單個資源宣告。它將檔案從模組的檔案目錄複製到 Web 伺服器並設定其許可權。required 屬性確保 test-module::http 類在應用 test-module::app 之前成功完成配置。

最後,我們需要在我們的主 init.pp 清單中包含一個新清單。

class test-module ( 
   $http_port = 80 
) { 
   include test-module::httpd 
   include test-module::app 
} 

現在,執行 apply 命令來實際測試正在發生的事情。以下是輸出。

# puppet apply test-module/tests/init.pp --noop
Warning: Config file /etc/puppet/hiera.yaml not found, using Hiera 
defaults 

Notice: Compiled catalog for brcelprod001.brcle.com in environment 
production in 0.66 seconds 

Notice: /Stage[main]/Test-module::Httpd/Exec[iptables]/returns: 
current_value notrun, should be 0 (noop) 

Notice: /Stage[main]/Test-module::Httpd/Package[policycoreutilspython]/ 
ensure: current_value absent, should be present (noop) 

Notice: /Stage[main]/Test-module::Httpd/Service[iptables]: Would have 
triggered 'refresh' from 1 events 

Notice: /Stage[main]/Test-module::Httpd/File[/var/www/myserver]/ensure: 
current_value absent, should be directory (noop) 

Notice: /Stage[main]/Test-module::Httpd/Package[httpd]/ensure: 
current_value absent, should be present (noop) 

Notice: 
/Stage[main]/Test-module::Httpd/File[/etc/httpd/conf.d/myserver.conf]/ensur 
e: current_value absent, should be file (noop) 

Notice: /Stage[main]/Test-module::Httpd/Exec[semanage-port]/returns: 
current_value notrun, should be 0 (noop) 

Notice: /Stage[main]/Test-module::Httpd/Service[httpd]/ensure: 
current_value stopped, should be running (noop) 

Notice: Class[test-module::Httpd]: Would have triggered 'refresh' from 8 
Notice: 
/Stage[main]/test-module::App/File[/var/www/myserver/index.html]/ensur: 
current_value absent, should be file (noop) 

Notice: Class[test-module::App]: Would have triggered 'refresh' from 1 
Notice: Stage[main]: Would have triggered 'refresh' from 2 events Notice: 
Finished catalog run in 0.74 seconds

突出顯示的行顯示了將 index.html 檔案複製到 Web 主機的結果。

完成模組

完成以上所有步驟後,我們建立的新模組就可以使用了。如果我們想建立模組的存檔,可以使用以下命令完成。

# puppet module build test-module
廣告