配置管理101:编写厨师食谱

来自菜鸟教程
跳转至:导航、​搜索

简而言之,服务器配置管理(也通常称为 IT 自动化)是一种将您的基础架构管理转变为代码库的解决方案,它在一组可版本化和易于重用的配置脚本中描述部署服务器所需的所有过程。 随着时间的推移,它可以极大地提高任何服务器基础架构的完整性。

previous guide 中,我们讨论了为服务器基础架构实施配置管理策略的主要好处、配置管理工具的工作原理以及这些工具通常具有的共同点。

本系列的这一部分将引导您完成使用 Chef 自动化服务器配置的过程,Chef 是一种强大的配置管理工具,它利用 Ruby 编程语言来自动化基础设施管理和配置。 我们将专注于创建简化示例所需的语言术语、语法和功能,以使用 Apache 完全自动化部署 Ubuntu 18.04 Web 服务器。

这是我们需要自动化以实现目标的步骤列表:

  1. 更新 apt 缓存
  2. 安装 Apache
  3. 创建自定义文档根目录
  4. 在自定义文档根目录下放置一个 index.html 文件
  5. 应用模板来设置我们的自定义虚拟主机
  6. 重启阿帕奇

我们将首先了解 Chef 使用的术语,然后概述可用于编写食谱的主要语言功能。 在本指南的最后,我们将分享完整的示例,以便您自己尝试。

注意: 本指南旨在向您介绍 Chef 语言以及如何编写食谱以自动化您的服务器配置。 有关 Chef 的更多介绍性视图,包括安装和开始使用此工具所需的步骤,请参阅 Chef 的官方文档


    1. Getting Started 在我们更深入地了解 Chef 之前,我们必须熟悉此工具引入的重要术语和概念。 ###厨师条款
  • Chef Server:存储信息和管理节点供应的中央服务器
  • Chef 节点:由 Chef Server 管理的单个服务器
  • Chef Workstation:在其中创建配置并将其上传到 Chef 服务器的控制器机器
  • Recipe:包含一组要执行的指令(资源)的文件。 食谱必须包含在 Cookbook
  • Resource:声明系统元素和应该执行什么动作的代码部分。 例如,要安装一个包,我们使用操作 install 声明一个 package 资源
  • Cookbook:以预定义方式组织的食谱和其他相关文件的集合,以促进共享和重用部分配置
  • Attributes:特定节点的详细信息。 属性可以是自动的(参见下一个定义),也可以在配方中定义
  • Automatic Attributes:包含系统信息的全局变量,如网络接口和操作系统(在其他工具中称为 facts)。 这些自动属性由一个名为 Ohai 的工具收集
  • Services:用于触发服务状态变化,如重启或停止服务
      1. Recipe 格式厨师食谱是使用 Ruby 编写的。 配方基本上是资源定义的集合,这些定义将创建由节点执行的逐步指令集。 这些资源定义可以与 Ruby 代码混合使用,以获得更大的灵活性和模块化。

您可以在下面找到一个简单的配方示例,该配方将运行 apt-get update 并在之后安装 vim

execute "apt-get update" do
 command "apt-get update"
end

apt_package "vim" do
 action :install
end
    1. Writing Recipes ###Working with Variables 局部变量可以在recipes 中定义为常规的Ruby 局部变量。 下面的示例显示了如何创建稍后在资源定义中使用的局部变量:
package  = "vim"

apt_package package do
 action :install
end

但是,这些变量的范围有限,仅在定义它们的文件内有效。 如果您想创建一个变量并使其全局可用,以便您可以从任何食谱或食谱中使用它,您需要定义一个 自定义属性

        1. Using Attributes 属性表示节点的详细信息。 Chef 具有自动属性,这些属性由名为 Ohai 的工具收集并包含有关系统的信息(例如平台、主机名和默认 IP 地址),但它也允许您定义自己的自定义属性。

属性具有不同的优先级,由您创建的属性类型定义。 default 属性是最常见的选择,因为它们仍然可以在需要时被其他属性类型覆盖。

以下示例显示了使用 default 节点属性而不是局部变量的前一个示例的外观:

node.default['main']['package'] = "vim"

apt_package node['main']['package'] do
 action :install
end

在这个例子中有两个细节需要观察:

定义节点变量时的推荐做法是使用当前使用的说明书作为键将它们组织为散列。 在本例中,我们使用了 main,因为我们有一本同名的食谱。 如果您正在使用可能具有相似命名属性的多个说明书,这可以避免混淆。 请注意,我们在定义属性时使用了 node.default,但是在稍后访问其值时,我们直接使用了 nodenode.default 用法定义我们正在创建一个类型为 default 的属性。 此属性的值可能会被具有更高优先级的其他类型覆盖,例如 normaloverride 属性。

属性的优先级一开始可能会有点混乱,但经过一些练习后你会习惯的。 为了说明该行为,请考虑以下示例:

node.normal['main']['package']  = "vim"

node.override['main']['package'] = "git"

node.default['main']['package'] = "curl"

apt_package node['main']['package'] do
 action :install
end

你知道在这种情况下会安装哪个包吗? 如果你猜到了 git,那么你猜对了。 无论定义属性的顺序如何,override 类型的更高优先级将使 node['main']['package'] be evaluated to git`。 ###Using Loops 循环通常用于使用不同的输入值重复任务。 例如,不是为安装 10 个不同的包创建 10 个任务,您可以创建一个任务并使用循环对要安装的所有不同包重复该任务。

Chef 支持所有 Ruby 循环结构,用于在配方中创建循环。 为了简单的使用,each 是一个常见的选择:

['vim', 'git', 'curl'].each do |package|
 apt_package package do
   action :install
 end
end

除了使用内联数组,您还可以创建一个变量或属性来定义要在循环内使用的参数。 这将使事情更有条理,更容易阅读。 下面,同样的例子现在使用一个局部变量来定义应该安装的包:

packages = ['vim', 'git', 'curl']

packages.each do |package|
 apt_package package do
   action :install
 end
end
      1. Using Conditionals 条件可以用于动态决定是否应该执行代码块,例如,基于变量或命令的输出。

Chef 支持所有 Ruby 条件语句,用于在配方中创建条件语句。 此外,所有资源类型都支持两个特殊属性,它们将在决定是否执行任务之前评估表达式:if_onlynot_if

下面的示例将在尝试安装扩展 php-pear 之前检查 php 的存在。 它将使用命令 which 来验证当前系统上是否安装了 php 可执行文件。 如果命令 which php 返回 false,则不会执行此任务:

apt_package "php-pear" do
 action :install
 only_if "which php"
end

如果我们想做相反的事情,当条件被评估为真时,始终执行命令 except,我们使用 not_if 代替。 此示例将安装 php5,除非系统是 CentOS:

apt_package "php5" do
 action :install
 not_if { node['platform'] == 'centos' }
end

为了执行更复杂的评估,如果您想在特定条件下执行多个任务,您可以使用任何标准的 Ruby 条件。 以下示例仅在系统为 Debian Ubuntu 时执行 apt-get update

if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
 execute "apt-get update" do
   command "apt-get update"
 end
end

属性 node['platform'] 是 Chef 的自动属性。 最后一个例子只是为了演示一个更复杂的条件构造,但是它可以用一个使用自动属性的简单测试来代替node['platform_family'] ,这将为 Debian 和 Ubuntu 系统返回“debian”。<###Working with Templates 模板通常用于设置配置文件,允许使用旨在使这些文件更加通用和可重用的变量和其他功能。


Chef 使用 Embedded Ruby (ERB) 模板,这与 Puppet 使用的格式相同。 它们支持条件、循环和其他 Ruby 特性。

下面是一个用于设置 Apache 虚拟主机的 ERB 模板示例,使用变量来定义该主机的文档根目录:

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    <Directory <%= @doc_root %>>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

为了应用模板,我们需要创建一个 template 资源。 这是应用此模板替换默认 Apache 虚拟主机的方式:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
end 

Chef 在处理本地文件时做了一些假设,以加强组织和模块化。 在这种情况下,Chef 将在 templates 文件夹中查找 vhost.erb 模板文件,该文件夹应位于此食谱所在的同一本食谱中。

与迄今为止我们看到的其他配置管理工具不同,Chef 对变量有更严格的范围。 这意味着在定义 template 资源时,您必须明确提供您计划在模板中使用的任何变量。 在这个例子中,我们使用了 variables 方法来传递我们在虚拟主机模板中需要的 doc_root 属性。 ###Defining 和触发服务 服务资源用于确保服务已初始化和启用。 它们还用于触发服务重启。

在 Chef 中,需要先声明服务资源,然后再尝试通知服务资源,否则会报错。

让我们考虑一下我们之前的模板使用示例,我们在其中设置了一个 Apache 虚拟主机。 如果您想确保 Apache 在虚拟主机更改后重新启动,您首先需要为 Apache 服务创建一个 service 资源。 这是在 Chef 中定义此类资源的方式:

service "apache2" do
  action [ :enable, :start ]
end

现在,在定义 template 资源时,您需要包含 notify 选项以触发重启:

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end
    1. Example Recipe 现在让我们看一下在 Ubuntu 14.04 系统中自动安装 Apache Web 服务器的方法,如本指南的介绍中所述。

完整的示例,包括用于设置 Apache 的模板文件和由 Web 服务器提供的 HTML 文件,可以在 Github 上找到 。 该文件夹还包含一个 Vagrantfile,可让您使用由 Vagrant 管理的虚拟机在简化的设置中测试配方。

您可以在下面找到完整的食谱:

node.default['main']['doc_root'] = "/vagrant/web"

execute "apt-get update" do
 command "apt-get update"
end

apt_package "apache2" do
 action :install
end

service "apache2" do
 action [ :enable, :start ]
end

directory node['main']['doc_root'] do
 owner 'www-data'
 group 'www-data'
 mode '0644'
 action :create
end

cookbook_file "#{node['main']['doc_root']}/index.html" do
 source 'index.html'
 owner 'www-data'
 group 'www-data'
 action :create
end

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

      1. 食谱解释
        1. line 1 配方以 属性 定义 node['main']['doc_root'] 开始。 我们可以在这里使用一个简单的局部变量,但是在大多数用例场景中,配方需要定义将从包含的配方或其他文件中使用的全局变量。 对于这些情况,有必要创建属性而不是局部变量,因为后者的范围有限。
        1. lines 3-5 这个 execute 资源运行 apt-get update
        1. lines 7-10 这个 apt_package 资源安装包 apache2
        1. lines 12-15 这个 service 资源启用并启动服务 apache2。 稍后,我们将需要通知此资源以重新启动服务。 重要的是,服务定义位于任何尝试通知服务的资源之前,否则您将收到错误消息。
        1. lines 17-22 这个 directory 资源使用自定义属性 node['main']['doc_root'] 定义的值来创建一个目录,该目录将用作我们的 文档根
        1. lines 24-29 cookbook_file 资源用于将本地文件复制到远程服务器。 该资源将复制我们的 index.html 文件并将其放置在我们在之前的任务中创建的文档根目录中。
        1. lines 31-36 最后,这个 template 资源应用我们的 Apache 虚拟主机模板并通知服务 apache2 重新启动。
    1. Conclusion Chef 是一个强大的配置管理工具,它利用 Ruby 语言来自动化服务器配置和部署。 它使您可以自由使用标准语言功能以获得最大的灵活性,同时还为某些资源提供自定义 DSL。