使用 Chef 自动化部署一个 Web 服务器

随着 DevOps 的流行,越来越多的工作被自动化处理。在搭建大规模的 IT 架构时,需要系统管理员夜以继日地安装配置服务器、调整各种参数等工作,直到Chef 的出现,将系统管理员从这种水深火热的工作中解脱了出来,他们只需要编写 Chef 脚本,描述出服务器所需要保持的状态,然后运行脚本,服务器就配置好了。本文以配置一个 Web 服务器为例,对 Chef 的概念和工作流程做一简单介绍。

王 群锋, 软件工程师,  IBM

2015 年 6 月 23 日

  • expand内容

在 IBM Bluemix 云平台上开发并部署您的下一个应用。

“这是一个最好的时代,也是一个最坏的时代。他们都在直奔天堂,而我们都在直奔相反的方向。”

90 后霸道总裁” 的超级课程表融资千万美元、WhatsApp 被 Facebook 以 190 亿美元收购……这个时代仿佛到处都充满了机会。现在假设我们也决定放弃朝九晚五的工作,要开发出一款 Web 应用改变这个世界,顺便当上总经理、出任 CEO、赢取白富美、走向人生巅峰。七拼八凑,我们的应用做出来了。它的架构非常简单,如果非要描述的话,它的架构如图 1 所示:

图 1. 应用架构

应用架构

这么简单的应用,我们上网浏览一下资料,随便租个服务器,安装一个 Web 服务器,配置一下,应用顺利上线。

幸福总是来得太快,很快我们的应用就火了。随着访问量的增大,我们需要单独的数据库服务器,一个都不够,得来俩;应用服务器也不够用了,再多添几台,上一个负载均衡;对数据库的访问又成了性能瓶颈,增加些数据库缓存吧,最终,应用的架构变成了如下的样子:

图 2.    演进的应用架构

演进的应用架构

现在问题来了,面对如此复杂的架构,怎么安装和配置这些服务呢?Chef 就是用来解决这个问题的。

第一份“菜谱”(recipe)

让我们暂且就此打住,先来看看怎么使用 Chef。首先需要在一台 Linux 机器上安装Chef Development Kit。如果您实在找不到一台 Linux 机器也没有关系,可使用一个用于教学用途的在线虚拟机,该虚拟机上已经预装了 Chef Development Kit,可以直接使用。

Recipe 是 Chef 中主要执行任务的地方,翻译成中文是“菜谱”的意思。我们的第一份“菜谱”的主要功能是使用 Chef 生成一个文本文件,其内容为:Hello Chef。让我们先新建一个 chef-repo 目录,用来存放“菜谱”,然后在该目录下创建第一个“菜谱”:hello.rb,其内容如下:

清单 1. hello.rb
file 'motd' do
content 'Hello Chef’
end

在命令行中执行:chef-appy hello.rb,输出如下:

图 3. 输出

输出

可 以看到,命令执行后生成 motd 文件,该文件的内容为字符串:Hello Chef。这就是我们的第一份“菜谱”,虽然简单,但是却概括了 Chef 的基本工作原理:使用一个 Ruby 文件,即“菜谱”描述服务器应有的状态,然后执行 Chef 命令配置服务器。

您可尝试再次执行 chef-appy hello.rb,Chef 会检测到 motd 文件已经存在,且文件内容和“菜谱”中所描述的一致,因此不进行任何操作;您还可尝试手动删除 motd 文件,再次执行 chef-appy hello.rb 后,又重新生成了 motd 文件。这正是配置服务器所需要的,每次配置都能保证状态一致。

当然,我们的第一份“菜谱”只是一道开胃小菜,下面我们看看如何使用 Chef 部署一个 Web 服务器。

部署 Web 服务器

部署一个 Web 服务器比生成一个文件复杂,但道理却是相同的,让我们先来看看代码:

清单 2. webserver.rb
package 'httpd'
service 'httpd' do
    action [:start, :enable]
end

file '/var/www/html/index.html' do
  content '<html>
  <body>
    <h1>hello world</h1>
  </body>
</html>'
end

service 'iptables' do
  action :stop
end

这段代码总共分成四部分:第一部分安装 Apache HTTP Server;第二部分启动 HTTP 服务;第三部分生成主页面;第四部分停用 iptables 服务,这一步主要是因为有些 Linux 安装后,默认只打开 22 端口,其他端口是被禁止的,停用 iptables 服务后,就可以顺利访问 80 端口了,即 HTTP 协议所使用的端口。聪明的您朋友们,您能将这四部分和代码对应起来吗?

这里要注意的是,这四部分的顺序非常重要,必须先安装 Apache HTTP Server,然后启动它,这一点也不难想象,我们手动配置服务器时不也如此吗?

将 文件保存后,让我们再来运行 sudo chef-appy webserver.rb,因为脚本里包含安装软件包的操作,所以需要 root 权限,如果您不是以 root 账号登录(相信您不会真的这样做吧?),务必在命令行前加 sudo,否则,Chef 会报错。如果得到类似下面的输出,就证明服务器配置成功,打开浏览器,输入http://localhost,可以看到刚才定制的主页了吧?

图 4. 输出

输出

然 而,作为有“洁癖”的程序员,不难发现“菜谱”的第二部分好像混入了什么奇怪的东西:一段 HTML 代码。这段 HTML 代码明显和其他部分不协调,如果网页再变得复杂点,这份“菜谱”会变得很难管理。因此,我们得想点什么办法,管理“菜谱”。方法就是“烹饪手册” (cookbook)。

“烹饪手册”(cookbook)

和真实的烹饪一样,“烹饪手册”是用来组织“菜谱”的,在“烹饪手册”里,不光可以定义各种“菜谱”,也可以定义一些属性文件或模板,这些属性文件或模板可以在“菜谱”里直接引用。在实际工作中,我们往往使用的也是“烹饪手册”,而不是一个个单独的“菜谱”。

让我们在当前目录下新建一个文件夹 cookbooks,然后切换到该目录,调用 chef generate cookbook learn_chef_httpd 会自动为我们生成一个“烹饪手册”。“烹饪手册”的目录结构如下:

图 5. “烹饪手册”目录结构

“烹饪手册”目录结构

其中 recipes 目录下的 default.rb 是默认的“菜谱”,让我们将其中内容替换为之前编写的“菜谱”。

现 在我们要将原来“菜谱”中的 HTML 代码移到一个外部文件中,使用 chef generate template learn_chef_httpd index.html 命令生成模板文件 index.html.erb,该文件被放置在 learn_chef_httpd/templates/default 目录下。然后将该文件内容替换为之前的 HTML,修改 default.rb,引用该模板,最终的“菜谱”变成了下面这个样子:

清单 3. default.rb
package 'httpd'

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

template '/var/www/html/index.html' do
  source 'index.html.erb'
end

service 'iptables' do
  action :stop
end

在命令中执行 sudo chef-client --local-mode –runlist ‘recipe[learn_chef_httpd]’ ,打开浏览器,访问http://localhost ,如果能正常访问,那么恭喜您完成了自己的第一个“烹饪手册”!

真实环境下的 Chef

上 面的例子只是为了展示如何编写“菜谱”和“烹饪手册”,真实环境下的 Chef 却不是这样工作的。在真实环境下,系统管理员在一台电脑上编写 Chef 脚本,然后使用上述方式调试,调试成功后,将脚本上传至 Chef 服务器,我们从控制台向 Chef 服务器发命令,Chef 服务器会将配置下发到各个待配置服务器,在每个服务器上运行 Chef,完成对服务器的配置。

图 6.    Chef 原理

Chef 原理

为此,我们需做三点准备:一台用于编写 Chef 脚本的电脑、一台 Chef 服务器、很多待配置的服务器。我们已经有了一台可以编写 Chef 脚本的电脑,为了方便学习,Chef 服务器可以选用Chef 官网提供的托管服务,另外需要几台待配置的服务器,记得不要在服务器上安装 Chef,当我们配置这些服务器时,Chef 会自动在上面安装所需的工具。

注册成功 Chef 的托管服务后,先创建一个组织,然后下载与之对应的 Starter Kit,解压到当前目录,该工具是用来做认证的,有了它,才可以从本地连接 Chef    服务器。现在让我们删除以前创建的“烹饪手册”,转而从 Chef 超市上 下载一个现成的手册。Chef 超市是一个开发者交流“烹饪手册”的地方,因为配置服务器的很多操作都是通用的,所以人们把这些配置做成手册,放在一个地方,大家都能使用。我们编写 Chef 脚本,往往也是先上 Chef 超市去看看有没有可用的手册,如果有,直接拿过来,或者在此基础上修改一下就能用,如果没有,再考虑编写自己的手册。使用如下命令下载前面配置 Web 服务器的手册:

knife cookbook site download learn_chef_httpd

将下载后的手册解压到 cookbooks 目录,删除压缩包:

tar -zxvf learn_chef_httpd-0.1.0.tar.gz -C cookbooks
rm learn_chef_httpd*.tar.gz

接下来将该手册上传至 Chef 服务器,即我们刚才注册的 Chef 托管服务:

knife cookbook upload learn_chef_httpd

打 开托管服务控制台,在 Policy 选项卡下就能看见刚刚上传成功的“烹饪手册”。接下来我们要做的工作是告诉 Chef 服务器来帮我们让服务器自举,这一步会通过 SSH 登录到待配置的服务器,下载并安装 Chef,然后下载执行刚刚上传到 Chef 服务器上的“烹饪手册”。该操作只在第一次配置服务器时需要,自举成功后,以后就再不需要自举了:

knife bootstrap `address` --ssh-user `user` --ssh-password '`password`' \
--sudo --use-sudo-password --node-name node1 \
--run-list 'recipe[learn_chef_httpd]'

将其中的`address`、`user`、`password`替换为待配置服务器的真实地址、用户名和密码。打开浏览器,输入服务器地址,看看是否能访问定制的主页?

获取服务器信息

Chef 不光可以管理服务器,同时服务器将自己的信息上传至 Chef 服务器。使用如下命令查看当前组织里被管理的服务器:

knife node list

使用如下命令查看服务器信息,包括服务器的 IP 地址、机器名、操作系统等信息:

knife node show node1

有了这些信息后,我们可以重新修改模板,让其显示给定服务器的信息:

清单 4. index.html.erb
<html>
<body>
<h1>hello from <%= node['fqdn'] %></h1>
</body>
</html>

再将“烹饪手册”上传至 Chef 服务器,然后使用如下命令配置服务器:

knife ssh `address` 'sudo chef-client' --manual-list \
--ssh-user `user` --ssh-password '`password`'

同理,将`address`、`user`、`password`替换为待配置服务器的真实地址、用户名和密码。打开浏览器,输入服务器地址,看看改动是否生效?

只要一台服务器配置成功,我们便可以用同样的方法配置几十台、上百台。而且一旦配置发生变化,我们只需修改脚本,所有服务器便可以获得相同的更新,这个时候,Chef 的威力就显示出来了。

chef 还是 knife?

细 心的您可能会注意到,上面的命令,一些是 chef *****,一些却是 knife *****。初次接触 Chef,很容易被这些命令搞混。这里有一个简单的规则:本地执行的命令以 chef 打头,需要远程连接到 Chef 服务器或待配置服务器的命令以 knife 打头。

最后,让我们再复习一遍本文中所使用到的命令:

  1. 运行“菜谱”

    chef-appy hello.rb
  2. 使用 Chef 生成“烹饪手册”

    chef generate cookbook learn_chef_httpd
  3. 使用 Chef 生成模板

    chef generate template learn_chef_httpd index.html
  4. 使用 Chef 运行“烹饪手册”

    chef-client --local-mode –runlist ‘recipe[learn_chef_httpd]’
  5. 从 Chef 超市下载“烹饪手册”

    knife cookbook site download learn_chef_httpd
  6. 向 Chef 服务器上传“烹饪手册”

    knife cookbook upload learn_chef_httpd
  7. 服务器自举

    knife bootstrap `address` --ssh-user `user` --ssh-password '`password`' \
    --sudo --use-sudo-password --node-name node1 \
    --run-list 'recipe[learn_chef_httpd]'
  8. 获取当前组织下的服务器列表

    knife node list
  9. 显示服务器信息

    knife node show node1
  10. 使用 Chef 远程运行“烹饪手册”,配置服务器

    knife ssh `address` 'sudo chef-client' --manual-list \
     --ssh-user `user` --ssh-password '`password`'

结束语

随 着云计算和 DevOps 技术的发展,有人断言系统管理员和 DBA 会面临失业,未来的云计算公司和数据库公司只会雇佣少数系统管理员和 DBA 管理他们的 IT 基础设施和数据库。虽然作者不大赞成“机器替代人工”这一观点,但提早下手,学点东西总不是坏事,所谓技多不压身嘛。

Chef 能够实现服务器配置的自动化,在 DevOps 运动中占有重要的位置。本文通过一个配置 Web 服务器的例子,一步步引导大家如何使用 Chef。希望您读完本文,能编写出自己的第一个“烹饪手册”。