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
广告