如何在Ubuntu上创建简单的Chef Cookbook来管理基础架构

Chef是自动化系统配置的一大利器。在以前的导游,我们讨论了如何建立一个Chef服务器,工作站和节点。在本指南中,我们将介绍如何创建简单的Recipe到您的节点上自动执行的程序。

介绍


Chef是一个配置管理系统,旨在允许您以自动化,可靠和可扩展的方式自动化和控制大量的计算机。 在前面的教程中,我们已经看了一些常见的Chef术语 ,并讨论了如何安装Chef服务器,工作站和节点(与Chef12Chef11 )。在本指南中,我们将使用这些指南作为跳转点,开始谈论如何自动化您的环境。 在本文中,我们将讨论创建Chef cookbook的基础知识。 Cookbook是配置单元,允许我们在远程节点上配置和执行Chef中的特定任务。我们构建Recipe,然后告诉Chef我们想要运行菜单中列出的步骤的节点。 在本指南中,我们将假定你已经开始与我们结束了三机最后一节课用。您应该有一个服务器,一个工作站和至少一个节点来推送配置更改。

基本Cookbook概念


Cookbook是Chef用于使节点进入特定状态的配置和策略详细信息的基本单元。这只是意味着Chef使用烹饪书来执行工作,并确保事情是他们应该在节点上。 Cookbook通常用于处理一个特定的服务,应用程序或功能。例如,可以创建菜单以使用NTP设置和同步节点的时间与特定服务器。它可以安装和配置数据库应用程序。 Cookbook基本上是用于基础设施选择的软件包。 在工作站上创建Cookbook,然后上传到Chef服务器。从那里,Recipe中描述的Recipe和策略可以被分配给节点作为节点的“运行列表”的一部分。运行列表是由chef-client在节点上运行的配方和角色的顺序列表,以便使节点符合为其设置的策略。 这样,您在Recipe中编写的配置详细信息将应用于您希望遵守Recipe中描述的方案的节点。 Cookbook是一个完全独立的目录结构。有许多不同的目录和文件用于不同的目的。让我们现在谈谈一些更重要的。

Recipe


Recipe是Recipe的主要主力。菜谱可以包含多个Recipe,或者依赖于外部Recipe。配方用于声明不同资源的状态。 Chef资源描述了系统的一部分及其期望的状态。例如,资源可以说“应该安装包x”。另一个资源可能会说“x服务应该运行”。 一个Recipe是一个相关资源的列表,告诉Chef如果实现了配方,系统应该如何看待。当Chef运行配方时,它会检查每个资源是否符合声明的状态。如果系统匹配,则它移动到下一资源,否则,它尝试将资源移动到给定状态。 资源可以有许多不同类型。一些常见的是:
  • 包装 :用于在节点上管理软件包
  • 服务 :用于在节点上管理服务
  • 用户 :管理用户的节点上
  • :管理组
  • 模板 :管理与嵌入的Ruby模板文件
  • cookbook_file:从Recipefiles目录的某个位置的节点上传输文件
  • 文件 :管理节点的文件内容
  • 目录 :管理节点目录
  • 执行 :在节点上执行命令
  • cron的 :编辑节点上现有的cron文件

属性


Chef中的属性基本上是设置。将它们视为简单的键值对,以便您可以在菜谱中使用它们。 有几种不同类型的属性可以应用,每种属性的优先级都不同于节点操作的最终设置。在Recipe级别,我们通常定义我们正在配置的服务或系统的默认属性。这些可以稍后通过特定节点的更具体的值来覆盖。 创建Recipe时,我们可以在Recipe的attributes子目录中为我们的服务设置属性。然后我们可以在我们Recipe的其他部分引用这些值。

文件


cookbook中的files子目录包含我们将放置在使用cookbook的节点上的任何静态文件。 例如,我们不太可能修改的任何简单配置文件可以整体放置在files子目录中。然后,配方可以声明将文件从该目录移动到其在节点上的最终位置的资源。

模板


模板与文件类似,但它们不是静态的。 模板文件结束与.erb扩展,这意味着它们含有嵌入的Ruby。 这些主要用于将属性值替换为文件以创建将放置在节点上的最终文件版本。 例如,如果我们有一个属性定义服务的默认端口,模板文件可以调用来在文件中声明端口的位置插入属性。使用这种技术,您可以轻松创建配置文件,同时保持您希望在其他位置更改的实际变量。

Metadata.rb


metadata.rb文件用于管理关于包的元数据,这并不奇怪。这包括包名称,说明等。 它还包括依赖性信息等内容,您可以在其中指定此菜谱需要操作的Recipe。这将允许Chef服务器正确地构建节点的运行列表,并确保所有片段都正确传送。

创建一个简单的Recipe


为了演示与烹饪书的使用有关的一些工作流程,我们将创建一个我们自己的菜谱。这将是一个非常简单的Recipe,在我们的节点上安装和配置Nginx Web服务器。 首先,我们需要去我们的~/chef-repo我们的工作站上的目录:
cd ~/chef-repo
一旦有了,我们可以用刀制作一本Recipe。正如我们在前面的指南中提到的,刀是用于配置与Chef系统的大多数交互的工具。我们可以使用它来在我们的工作站上执行工作,也可以连接Chef服务器或单个节点。 创建Recipe的一般语法是:
knife cookbook create cookbook_name
由于我们的Recipe将处理安装和配置Nginx,我们将适当地命名我们的Recipe:
knife cookbook create nginx

** Creating cookbook nginx
** Creating README for cookbook: nginx
** Creating CHANGELOG for cookbook: nginx
** Creating metadata for cookbook: nginx
这里的刀是在我们的Recipe目录中为我们的新Recipe建立一个简单的结构。我们可以看到我们的Recipe结构通过导航到cookbooks目录,并进入目录与cookbook名称。
cd cookbooks/nginx
ls

attributes  CHANGELOG.md  definitions  files  libraries  metadata.rb  providers  README.md  recipes  resources  templates
正如你可以看到的,这创建了一个文件夹和文件结构,我们可以用来构建我们的Recipe。让我们从配置的最大块,配方开始。

创建简单配方


如果我们进入recipes子目录中,我们可以看到,已经有一个名为default.rb里面:
cd recipes
ls

default.rb
这是将引导“nginx”Recipe将运行的Recipe。这是我们将添加我们的代码。 使用文本编辑器打开文件:
nano default.rb

#
# Cookbook Name:: nginx
# Recipe:: default
#
# Copyright 2014, YOUR_COMPANY_NAME
#
# All rights reserved - Do Not Redistribute
#
这个文件当前唯一的是一个注释头。 我们可以开始规划需要为我们的Nginx Web服务器发生的事情,以启动和运行我们想要的方式。我们通过配置“资源”来做到这一点。资源没有描述如何做;它们只是描述了系统的一部分在完成时应该是什么样子。 首先,我们显然需要确保软件已安装。我们可以通过首先创建一个“包”资源来实现。
package 'nginx' do
  action :install
end
这小块代码定义了Nginx的包资源。第一行以资源(包)的类型和资源的名称('nginx')开头。其余的是一组动作和参数,声明我们想要与资源发生的事情。 在这个资源,我们看到action :install 。这一行告诉Chef我们要描述的资源应该被安装。运行此配方的节点将检查Nginx是否已安装。如果是,它会检查的事情列表做的事情。如果没有,它将使用客户端系统上可用的方法安装程序,然后检查它。 在我们安装服务后,我们可能想要调整它在节点上的当前状态。默认情况下,Ubuntu不会启动Nginx安装后,所以我们要改变:
service 'nginx' do
  action [ :enable, :start ]
end
在这里,我们看到一个“服务”类型的资源。这声明,对于Nginx服务组件(允许我们使用init或upstart管理服务器的部分),我们现在要启动服务,并且还使它能够在计算机重新启动时自动启动。 我们将要声明的最终资源是我们将要提供的实际文件。因为这只是一个简单的文件,我们不会修改,我们可以简单地声明我们想要的文件的位置,并告诉它在Recipe在哪里得到文件:
cookbook_file "/usr/share/nginx/www/index.html" do
  source "index.html"
  mode "0644"
end
我们使用“cookbook_file”资源类型告诉Chef这个文件在cookbook本身内可用,并且可以按原样传输到该位置。在我们的示例中,我们将文件传输到Nginx的文档根。 在我们的例子中,我们指定我们试图在第一行创建的文件名。在“源”行中,我们告诉它在cookbook中要查找的文件的名称。 Chef在cookbook中的“files / default”子目录中查找此文件。 “mode”行设置我们正在创建的文件的权限。在这种情况下,我们允许root用户读写权限和所有其他人的读取权限。 保存并在完成后关闭此文件。

创建索引文件


如上所述,我们定义了一个“cookbook_file”资源,它应该将一个名为“index.html”的文件移动到节点上的文档根目录中。我们需要创建这个文件。 我们应该把这个文件放在我们菜谱的“files / default”子目录中。现在通过键入:
cd ~/chef-repo/cookbooks/nginx/files/default
在这个目录中,我们将创建我们引用的文件:
nano index.html
这个文件将只是一个非常简单的HTML文档,意在证明我们的资源操作我们想要的方式。 将其粘贴到文件中:
<html>
  <head>
    <title>Hello there</title>
  </head>
  <body>
    <h1>This is a test</h1>
    <p>Please work!</p>
  </body>
</html>
保存并在完成后关闭文件。

创建助手Recipe


在我们再进一步之前,让我们先行解决一个小问题。当我们的节点试图运行我们创建的cookbook,因为它现在,机会是,它会失败。 这是因为它将尝试从Ubuntu存储库安装Nginx,并且我们的节点上的包数据库很可能已过期。通常,我们在运行包命令之前运行“sudo apt-get update”。 为了解决这个问题,我们可以创建一个简单的Recipe,其唯一的目的是确保包数据库更新。 我们可以使用我们之前使用的相同的刀语法来做到这一点。让我们把这本Recipe叫做“apt”:
knife cookbook create apt
这将创建与我们第一次开始使用NginxRecipe时相同的目录结构。 让我们直截了当地追逐并编辑我们的新Recipe的默认Recipe。
nano ~/chef-repo/cookbooks/apt/recipes/default.rb
在这个文件中,我们将声明一个“执行”资源。这只是一种定义我们想要在节点上运行的命令的方法。 我们的资源如下所示:
execute "apt-get update" do
  command "apt-get update"
end
第一行给出了我们的资源的名称。在我们的例子中,为了简单起见,我们调用这个资源。如果定义了“command”属性(如我们所做的),那么这是被执行的实际命令。 因为这些都是完全相同的,它丝毫没有关系。 保存并关闭文件。 现在我们有了新的Recipe,有很多方法可以确保我们在NginxRecipe之前执行。我们可以在NginxRecipe之前将其添加到节点的运行列表,但是我们也可以将其绑定到NginxRecipe本身。 这可能是更好的选择,因为我们不必记得在“nginx”Recipe之前添加“apt”Recipe在我们要为Nginx配置的每个节点上。 我们需要调整NginxRecipe中的一些东西,使这种情况发生。首先,让我们再次打开Nginx配方文件:
nano ~/chef-repo/cookbooks/nginx/recipes/default.rb
在这本Recipe的顶部,在我们定义的其他资源之前,我们可以在“apt”默认配方中输入:
include_recipe "apt"

package 'nginx' do
  action :install
end

service 'nginx' do
  action [ :enable, :start ]
end

cookbook_file "/usr/share/nginx/www/index.html" do
  source "index.html"
  mode "0644"
end
保存并关闭文件。 我们需要编辑另一个文件是metadata.rb文件。当Chef服务器将运行列表发送到节点时,将检查此文件,以查看应将哪些其他配方添加到运行列表。 现在打开文件:
nano ~/chef-repo/cookbooks/nginx/metadata.rb
在文件的底部,您可以添加以下行:
name             'nginx'
maintainer       'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures nginx'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'

depends "apt"
完成后,我们的Nginx cookbook现在依靠我们的apt cookbook来处理包数据库更新。

将Cookbook添加到节点


现在我们的基本Recipe已经完成,我们可以将它们上传到我们的Chef服务器。 我们可以单独通过键入:
knife cookbook upload apt
knife cookbook upload nginx
或者,我们可以通过键入以下内容来上传所有内容:
knife cookbook upload -a
无论哪种方式,我们的Recipe都将上传到Chef服务器。 现在,我们可以修改节点的运行列表。我们可以轻松地通过键入:
knife node edit name_of_node
如果需要查找可用节点的名称,可以键入:
knife node list

client1
为了我们的目的,当我们键入这个,我们得到一个文件,看起来像这样:
knife node edit client1

{
  "name": "client1",
  "chef_environment": "_default",
  "normal": {
    "tags": [

    ]
  },
  "run_list": [

  ]
}
您可能需要在此工作之前设置您的EDITOR环境变量。您可以输入以下命令:
export EDITOR=name_of_editor
如你所见,这是一个简单的JSON文档,描述了我们的节点的一些方面。我们可以看到一个“run_list”数组,它当前是空的。 我们可以使用以下格式将我们的Nginx cookbook添加到该数组:
"recipe[name_of_recipe]"
当我们完成后,我们的文件应该看起来像这样:
{
  "name": "client1",
  "chef_environment": "_default",
  "normal": {
    "tags": [

    ]
  },
  "run_list": [
    "recipe[nginx]"
  ]
}
保存并关闭文件以实现新设置。 现在,我们可以SSH到我们的节点并运行Chef客户端软件。这将导致客户端检入Chef服务器。一旦它这样做,它将看到已分配它的新的运行列表。 SSH到你的节点,然后运行这个:
sudo chef-client

Starting Chef Client, version 11.8.2
resolving cookbooks for run list: ["nginx"]
Synchronizing Cookbooks:
  - apt
  - nginx
Compiling Cookbooks...
Converging 4 resources
Recipe: apt::default
  * execute[apt-get update] action run
    - execute apt-get update

Recipe: nginx::default
  * package[nginx] action install (up to date)
  * service[nginx] action enable
    - enable service service[nginx]

  * service[nginx] action start (up to date)
  * cookbook_file[/usr/share/nginx/www/index.html] action create (up to date)
Chef Client finished, 2 resources updated
正如你所看到的,我们的apt手册被发送并运行,即使它不在我们创建的运行列表。这是因为Chef在节点上执行之前智能地解析了依赖性并修改了实际的运行列表。 注意 :有保证一个Recipe或配方之前另一个运行的各种方法。添加依赖性仅是一个选择,并且可以优选其他方法。 我们可以通过转到我们节点的IP地址或域名来验证这是否有效:
http://node_domain_or_IP
你应该看到这样的东西: Chef节点Nginx 恭喜,您已使用Chef烹饪书配置了第一个节点!

结论


虽然这是一个非常简单的例子,可能没有节省你很多时间手动配置服务器,希望你可以开始看到这种建设基础设施的方法的可能性。 它不仅允许快速部署和配置不同类型的服务器,它确保您知道所有机器的确切配置。这允许您验证和测试您的基础架构,并且为您提供您需要快速重新部署基础架构的框架。
作者:Justin Ellingwood