使用Chef

以Chef Server管理模式为例

我们刚才创建的cookbook的名字叫: apache-tutorial-1。它的目的就是要在指定的node上面安装apache,并且启动服务。

1 编写recipe

让我们编写第一个recipe。试想一下,如果手工来安装apache,需要下面三步动作。

  • 安装Apache
  • 启动Apache并且把它添加到开机启动
  • 配置home page

现在我们用recipe实现,打开cookbooks/apache-tutorial-1/recipes/default.rb文件,输入以下Ruby代码:

package 'apache2' do
  action :install
end

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

cookbook_file '/var/www/index.html' do
  source 'index.html'
  mode '0644'
end

我来解释下上面的代码:

在Chef中,package是一种资源类型,它告诉chef-client运行时候的「包」的名字,以及执行的动作,这段代码里,是告诉chef-client,要安装papache2. package在执行的时候,会自动的调用底层的provider来匹配相应的服务器平台。

service会告诉chef-client启动哪个服务。会调用底层的ohai组件来收集相关平台信息,从而正确启动相应的服务。这段代码里,是告诉chef-client,想要启动apache2.

cookbook_file会告诉chef-client来拷贝index.html文件到/var/www/index.html中,并且设置文件权限为0644.

这只是个简单的recipe,让我们继续。

把下面html代码添加到cookbook/apache-tutorial-1/files/default/index.html中:

<html>
<body>
  <h1>Hello, world!</h1>
</body>
</html>

2 上传Cookbook

我们写完了这个cookbook,就可以把它上传到我们之前搭建的Chef Server上面(非chef-solo模式)。在chef-repo目录中执行下面命令:

$ knife cookbook upload apache-tutorial-1

然后打开我们的Chef Server Webui: https://192.168.33.11/cookbooks

就可以看到我们上传的Cookbook了,如图:

cookbook

3 设置Run list

还是在Chef Server Webui上面,点击:https://192.168.33.11/nodes

选择你要安装的node, 点击编辑(edit),如图:

node-edit

在编辑界面,如图把apache-tutorial-1移动到右边,点击保存。

run_list

说明: Run list就是一个运行列表,包含了所有需要安装的role,以及按依赖顺序把recipe排列。

执行cookbook配置node

cookbook设置完毕,我们就执行下面命令来配置node:

$ knife ssh 192.168.33.12 'sudo chef-client' -m -x vagrant -P vagrant

这个命令会在ip为192.168.33.12的node上面执行sudo chef-client命令来配置节点。当然,你也可以登陆到那台虚拟机上面手工执行sudo chef-client命令。

命令执行成功之后,你登陆到192.168.33.12那台虚拟机上面,就会看到apatch2已经正常运行了。

apache-run

以OpsCode Chef为例

过程和自建Chef Server类似,可以自行练习。

以Chef Solo管理模式为例

当你对上面Chef Server模式有了一定了解,那么Chef Solo理解起来也不吃力了。

Chef Solo因为没有Server,所以我们直接在node机器上来执行。

我们继续拿上面用过的node2为例子。

注意: 以下操作都在node2虚拟机上面

$ mkdir -p /etc/chef/cookbooks/nginx/recipes

必须要在/etc/chef目录下面。

cd /etc/chef/cookbooks/nginx/recipes

sudo touch default.rb

sudo vi default.rb

写入下面Ruby代码:

package 'nginx'

然后回到/etc/chef 目录,创建node.json文件,然后编辑run list:

{ "run_list": ["recipe[nginx]"] }

然后在/etc/chef目录下,建立solo.rb文件:

cookbook_path File.expand_path("../cookbooks", __FILE__)
json_attribs File.expand_path("../node.json", __FILE__)

用来指定cookbooks和node.json的位置。

然后我们执行命令:

$ sudo chef-solo solo.rb

安装成功。

Chef Solo chef solo

启动服务

我们需要在nginx被安装完之后,可以自动启动。

再次打开 /etc/chef/cookbooks/nginx/recipes/default.rb修改代码为下面几行:

package 'nginx'

service 'nginx' do
  supports [:status, :restart, :reload]

  action :start
end

我们在chef server那节里介绍过service这个资源的含义。supports,用来告诉Chef,支持status、restart、reload这三个命令。最后用action来告诉Chef,当前动作是start。

然后在/etc/chef下执行:

$ sudo chef-solo solo.rb

就能看到nginx被正常启动了。 很酷。

增加用户

用户,是我们经常使用的,Chef也提供了User资源,来帮助你管理这些Chef使用者的用户。

比如,我们可以在/etc/chef/cookbooks下面再创建一个名为user的recipes,

$ sudo mkdir /etc/chef/cookbooks/user/recipes
$ cd /etc/chef/cookbooks/user/recipes
$ sudo touch default.rb

在default.rb中输入下面代码:

user 'blackanger' do
  password "$1$3YbJDvy2$JD2o6dEFjGvayRgmZWU030"
  gid "admin"
  home "/home/blackanger"
  supports  manage_home: true
end

说明: password,告诉Chef,此为用户的密码,是经过openssl加密的,使用此命令来加密:[openssl passwd -1 "passwd"]。 gid,告诉Chef,要把这个用户加到admin组里面,home,是指定用户的home目录, supports,指定管理其home的权限。

然后再打开/etc/chef/node.json, 加入recipes['user']:

{ "run_list": ["recipe[nginx]", "recipe[user]"] }

执行命令:

$ sudo chef-solo solo.rb

我们就可以看到执行结果了:

add_user add user

设定node.json

我们虽然创建好了用户,但是仔细想想,这种方式不太好,假如我们配置多台机器呢? user recipes里写的太死,代码无法重用了。 好在,我们Chef还可以允许我们把这种用户信息写到node.json里。

打开/etc/chef/node.json:


{
  "run_list": ["recipe[nginx]", "recipe[user]"],
  "user": {
    "name": "blackanger",
    "password": "$1$3YbJDvy2$JD2o6dEFjGvayRgmZWU030"
  }
}

然后回到user recipes的default.rb文件中修改为:

user node[:user][:name] do
  password node[:user][:password]
  gid "admin"
  home "/home/#{node[:user][:name]}"
  supports manage_home: true
end

然后执行:

$ sudo chef-solo solo.rb

成功!是不是很酷啊!

使用template

回到刚才nginx的例子, 我们还需要给nginx设置一个配置文件,这个时候,就要用到template资源了。

$ sudo mkdir  /etc/chef/cookbooks/nginx/templates/default
$ sudo touch /etc/chef/cookbooks/nginx/templates/default/nginx.conf.erb

注意,我们创建了一个nginx.conf.erb文件, 如果对Rails有了解的朋友,应该指定,erb是一个模板引擎,它可以支持你在这种模板里面变量运算、替换等操作。

打开nginx.conf.erb,输入下面代码:

server {
  server_name 192.168.33.12;
  root /home/<%= node[:user][:name] %>/demo;
}

注意:上面形如 <% ... %> 这样格式的代码,就是erb的语法,可以把需要替换的变量放到里面。

然后我们在回到nginx的recipe中告诉Chef应该使用这个template:

打开:/etc/chef/cookbooks/nginx/recipes/default.rb, 添加下面代码:

template "/etc/nginx/sites-enabled/nginx.conf" do
  source 'nginx.conf.erb'
  notifies :restart, 'service[nginx]', :immediately
end

说明:"/etc/nginx/sites-enabled/nginx.conf" 是告诉Chef,template文件要保存的路径。 source告诉Chef去哪找这个template, notifies是一个callback,告诉Chef要马上重启nginx服务。

然后我们分别使用directory和file资源来添加一个html文件,写法同上,下面给出完成的nginx recipe:

package 'nginx'

service 'nginx' do
  supports [:status, :restart, :reload]
  action :start
end

directory "/home/#{node[:user][:name]}/demo" do
  owner node[:user][:name]
end

file "/home/#{node[:user][:name]}/demo/index.html" do
  owner node[:user][:name]
  content "<h1>Hello blackanger!</h1>"
end

template "/etc/nginx/sites-enabled/nginx.conf" do
  source 'nginx.conf.erb'
  notifies :restart, 'service[nginx]', :immediately
end

然后执行我们的老命令: sudo chef-solo solo.rb, 愿望达成:

nginx_recipe run nginx recipe

验证:

$ curl http://127.0.0.1
<h1>Hello blackanger!</h1>

至此,我们就学会了使用chef-solo来安装「一台」机器。如果你想安装多台, 那么继续按照上面的步骤,安装chef-solo,然后复制cookbooks,一台一台的执行命令。

这样是不是还是很麻烦呢?

那当然了! 辛亏我们还有knife,这个超级助手。

chef-solo with knife

Knife是一套强大的命令行Chef管理工具。我们可以使用knife来帮助我们简化麻烦的工作,让我们不需要通过Chef Server就可以直接和需要配置的服务器交互。

因为我们使用的chef-solo方式,所以我们先安装一个gem:

$ gem install knife-solo

安装好之后执行命令:

$ knife solo init knife-solo-demo

就会帮助我们生成一个solo目录:

knife-solo-dir

注意: 在使用这个命令之前,要确保你的Ruby环境是否唯一,否则可能会出现找不到knife子命令solo的错误。

这个目录中,.chef/文件夹下面包含一个knife.rb文件。这个文件在我们讲过的Chef Server模式下也是一样存在的,具体的配置文档可以去官网查看。这里生成的knife.rb文件中包含下面代码:


cookbook_path    ["cookbooks", "site-cookbooks"]
node_path        "nodes"
role_path        "roles"
environment_path "environments"
data_bag_path    "data_bags"
#encrypted_data_bag_secret "data_bag_key"

knife[:berkshelf_path] = "cookbooks"

这里cookbook_path是相对于仓库根目录的路径,指定了角色中使用的Cookbook信息 node_path和role_path分别定义了节点和角色的存储位置,都是相对于根目录的路径。 这里有个berkshelf_path, berkshelf是一个第三方cookbook管理工具,我们的cookbooks目录,就是存放这些第三方cookbook,而site-cookbooks是用来存放我们自己编写的cookbook的地方。

然后我们使用命令:

$ knife solo bootstrap [email protected]

就可以在另一台vagrant机器(192.168.33.11)上配置chef-solo。它会帮我们安装chef-client, 创建node,创建cookbooks。

knife solo bootstrap实际上执行了两个命令:

  • knife solo prepare

    这个命令主要是初始化服务器,安装chef,配置node,上传cookbook

  • knife solo cook

    这个命令主要是上传cookbook,并且执行指令 chef-solo.

有了这个工具,就方便很多了。