Chef的基本概念及结构
Chef是实践DevOps和持续集成(Continuous Integration)思想的重要工具,它可以把服务器的运行环境(包括服务器软件、依赖包、网络配置等)进行抽象,以特有的配置语法对其进行管理,可自动地进行服务器环境的初始化工作。由于Chef是基于Ruby语言进行开发的框架,得益于Ruby在元编程及DSL(Domain Specific Language)开发方面的优势,Chef的开发具有简洁清晰扩展性强易于维护等特点,因此广泛地被应用于在云计算环境的搭建及维护等场景中。
想象一下在一个基本的云计算环境中,随着用户的需求,提供业务支撑的服务器,也就是云计算节点会被接二连三地申请并开通。每一台服务器从创建到投入使用,都需要经历一个初始化及配置的过程,如果在安装第一个节点的时候把配置参数、依赖包及执行的命令等写成脚本,在安装配置余下节点的时候只要运行一下脚本即可自动完成,这样的环境部署即节约时间而且不容易出错。Chef就起到了这样的一个脚本框架的作用,但功能要强大得多,可定制性和可扩展性都很强。Chef将脚本命令代码化,配置流程都体现在代码逻辑当中,定制时只需要修改代码,安装的过程就是执行代码的过程。Chef就像一个大厨,脚本的开发就像是创造一个新的菜谱,把各种食材送进厨房交给大厨,选择一个菜谱,大厨就会烹饪出美味佳肴。服务器的配置也是这样,在Chef里为一台裸机指定一个菜谱(role或recipe),Chef就会把它配置成用户所需要的云计算节点。
Chef使用Server/Client模式进行IT配置管理,在最常见的基本环境下,使用Chef涉及至少三台机器:一台Chef服务器(Chef-server),管理所有要配置的Chef客户端及各种开发出来的配置脚本,发起配置脚本的运行给客户端下发配置信息,可以形象地理解为既管理着食客又管理着菜谱的大厨;一台开发机器(Chef-Workstation),在上面编写配置脚本并传给Chef-Server,就像是大厨的助手,切菜配菜写菜谱,告诉大厨要做哪些菜;Chef客户端(Chef-Client),那就是等待品尝美味的食客,由Chef-server按照菜谱(Chef-Workstation传上来的脚本集也就是Recipe),利用各种食材(软件安装包、依赖包、配置文件),做成美味佳肴端给食客,食客吃饱了这个Chef-Client也就配置完成可以使用了。
本文介绍了一种基于Chef开发的云计算节点配置管理方案的案例,在讲解了Chef开发的一些思路及方法的同时,介绍了利用Chef提供的引导工具knife bootstrap来进行远程运维的模式,以chef-server和chef-workstation相集成的主控机来推送控制命令,使目标节点自动执行指定运维操作,实现了Chef在云计算应用场景下开发部署效率优化的尝试。
通过本文,读者可以比较深入地了解如何利用Chef系统进行开发,如何将基于Chef开发的自动化运维工具集成在实际应用场景之中,以及如何规划部署方案从而提升系统运转效率。对于Chef开发社区比较常见的如开发方法入门、应用进阶以及实际部署等问题本文都将有所涉及,相信能够为已经或将要利用Chef进行开发的朋友提供一些有用的参考。
图1.Chef官网关于Chef各组件之间关系的示意图
Chef在云计算平台的一种应用方案介绍
Chef作为配置管理工具,其一种常规的开发及应用流程是这样的:
- 在Chef-Workstation上创建一个cookbook,并在其中添加recipe
- 在recipe中进行开发,编写配置脚本的业务逻辑
- 上传cookbook到Chef-Server
- 在node上安装Chef-Client,并在Chef-Server上注册
- 在Chef-Server上配置node的run list
- 在目标node上运行chef-client,执行cookbook中定义的操作。
上一章曾提到,Chef具有很强的灵活性和可扩展性,可以根据实际应用场景的需要调整Chef的部署方案及配置流程触发方式。这里介绍一种用来支撑云计算平台管理的Chef应用方案:前台用户接口收集到用户提交的节点创建参数,包括机器硬件性能需求,OS类型,服务类别,预订时间,是否备份等等,这些信息在后台参数生成器中进行整合并生成配置清单,调用vSphere接口生成节点裸机。Chef位于云计算节点创建流程的中间,负责所有节点裸机生成后的定制配置。最后由业务验证模块对配置好的节点进行状态检查,如果通过即可交付用户使用。为提高系统的配置管理效率,在这样一个应用场景中,对Chef的开发和部署可以采用以下三点优化调整方案:
表1.Chef优化调整方案
部署集中化 |
系统架构决定了后台模块需要尽可能精简,减少管理模块的节点数量,可以将Chef-Server和Chef-Workstation合并集中部署; |
推送式主动管理 |
由于在这个应用场景中Chef始终处在一个等待响应的位置,从用户开始提交订单直至节点裸机生成,Chef并不知道Chef-Client的具体信息。这就需要Chef-Server对这些节点主机进行推送式的控制和管理,主要包括两个步骤,首先是在节点生成之后,Chef-Server通过推送Chef-Client安装包到节点主机进行安装,引导节点成为被Chef-Server管理的客户端之一,然后Chef-Server再推送配置脚本集(即RUN_LIST)到Chef-Client,并触发安装配置过程。以上功能都可以通过Chef提供的Knife bootstrap工具实现。 |
JSON传参 |
对于Recipe中涉及到的安装配置参数的传递,为提高执行效率,使用Knife bootstrap的-j参数代替通常使用的data bag来传递json-attributes。 |
关于Knife bootstrap工具的信息,可以参考Chef的官方文档: https://docs.chef.io/knife_bootstrap.html,在本文的后续章节将为读者展示一下一个具体的Cookbook的编写实例,并通过knife bootstrap由Chef-Server推送至Chef-Client节点实现软件包的自动安装部署。 下面我们将通过一个实例来了解Chef Cookbook的开发、部署及执行。
Chef Cookbook的开发
用Chef开发的部署工具是以Chef Cookbook为单元存储于Chef Server的存储系统中。每一个Chef Cookbook即一个用于操作设置和策略部署的套件,提供针对目标机器在某一场景(状态)下所要实现的操作及操作所需要的配置信息和参数。而所有的具体操作需要实现在一个或多个Chef Recipe中。
Chef Recipe主要用于根据操作系统状态对Chef-client进行操作流程的自动化配置。所以, Chef Recipe可以被认作是为实现某一目的所做的某一系列配置操作的集合体。 根据Chef Recipe的定义,我们可以大致了解到Recipe的开发过程。对每一个Recipe,我们需要确定目标机器在该Recipe执行之后需要实现什么状态,达到什么目标,完成什么配置。在这一部分内容我们将以云计算平台中常用的终端管理工具IEM Agent的安装配置卸载为例,展示Chef Cookbook的实现流程。
图2.IEM Agent的install操作流程图
表2.开发过程描述
开发步骤 |
具体描述 |
创建Cookbook |
需要创建一个Cookbook,我们可以使用Knife命令来主动创建一个Cookbook:# knife cookbook create <mycookbook-name>
该命令将在执行命令的workstation机器上默认Cookbooks库目录下创建一个以<mycookbook-name>命名的Cookbook文件结构目录,目录中包括Attributes、Recipes等文件目录结构以及CHANGELOG.md、metadata.rb和README.md文件。文件metadata.rb定义了该cookbook的版本信息和依赖关系,用来管理该cookbook。 |
规划Recipe实现Cookbook的目标 |
要确认该Cookbook要实现的目标,如安装软件,运行软件,检查软件是否正常安装配置,卸载该软件。根据此目标,可以确定至少需要4个Recipe来实现上述相应的4个目标。那么需要在创建的Cookbook结构的recipes目录下创建相应的<recipe-name>.rb文件。每一个recipe文件要实现一个目标,例如定义install.rb文件,目标是要求在目标机器上成功安装终端管理工具IEM Agent。当然,如果使用default.rb来命名某个recipe,那么如果在使用该cookbook时没有指定某个recipe,那么默认执行default.rb这个recipe。所以建议使用default.rb执行通用常见的操作和配置。 |
确定Recipe的功能逻辑及资源 |
确定要实现每一个recipe目标所需要的操作命令、参数配置、操作流程及所需要的相关文件。所有操作配置所需要预定义的参数、属性和变量信息将定义在指定的后缀为rb的ruby文件,并存放在目录Attributes下。如此参数变量与具体操作流程分离,在参数变量的值需要改变调整时,可以直接在固定的attribute文件中修改,并不需要修改recipe,从而保证代码质量。例如用于安装某软件的install.rb将需要提供软件名称、软件安装目录、软件日志目录及名称、所需硬盘空间大小等信息,这些信息都可以以变量参数的形式预定义在某个attribute文件中。 |
细化操作流程 |
Chef可以用于实现运维中脚本程序部署的自动化,代替运维人员手动的部署维护系统,实现运维人员所有的手动操作,包括运维人员设置参数,配置环境,运行命令,等待执行,查看操作结果等等所有的操作步骤。但是运维人员的手动操作涉及极多精细的操作,甚至与当前的机器运行环境有关,与之前步骤的操作结果有关,这就使得部署自动化变得比较困难复杂。所以就需要细化操作流程,将每一个流程都细化到一个简单的操作,比如创建某个目录、拷贝某个文件、执行某条命令,同时考虑当前机器与该操作有关的环境如何。同样以安装终端管理工具IEM Agent为例,首先需要检查系统硬盘空闲空间是否足够,然后从软件包服务器下载软件,从IEM server下载认证文件,再配置代理软件所需的配置文件,创建安装目录,安装该代理软件,最后清理所有下载的临时文件。通过细化流程,可以细化分解为步骤:检查硬盘空闲空间,从服务器下载软件包到临时目录,验证有效的IEM Server地址,下载认证文件,创建认证文件指定目录,将认证文件拷贝到指定目录,创建配置文件指定的目录,设置配置文件,创建安装目录,备份旧日志(如果以前安装过该软件),清空日志目录(如果存在旧日志或者旧日志目录),创建日志目录,使用安装命令安装IEM Agent,清空临时下载文件。 |
使用Chef Resource实现细化后的步骤 |
每一个步骤使用一个Chef Resource实现,从而像串起一串珍珠项链一样将所有步骤按照顺序衔接起来。Chef Resource是Chef提供的用于实现配置的操作名称定义。每个Resource提供固定的几种操作。例如细化流程中的检查硬盘空闲空间,可以使用Resource Ruby_block来实现。Ruby本身提供对chef client 机器的机器检查,能得到当前的硬盘空闲空间,使用Resource Ruby_block类型可以将Ruby语句封装为一个Resource对象,在Chef运行时执行。
available_space = node['filesystem']['C:']['kb_available'].to_i #for windows
ruby_block "raise_Not_Enough_Space" do
block do
Chef::Log.fatal("Software required #{node['iemagent']['disk_capacity'].to_i * 1024} KB, but the free space of file system is #{available_space} KB")
raise "Not_Enough_Space_Exception"
end
only_if {available_space < node['iemagent']['disk_capacity'].to_i * 1024}
end
在下载IEM Agent安装包时,直接使用Resource Remote_file类型替代Ruby语句远程下载文件。
remote_file "#{node['iemagent']['download_path']}/#{node['iemagent']['package']}" do
source "#{node['iemagent']['packageServer']}/#{node['iemagent']['package']}"
owner node['iemagent']['root_user']
group node['iemagent']['root_group']
mode 00755
end
在安装IEM Agent安装包时,尽量使用已有的Resource实现软件安装,而不是使用命令行安装方式。
windows_package 'IBM Endpoint Manager Client' do
source "#{node['iemagent']['download_path']}/#{node['iemagent']['package']}"
options '/s /v/qn'
installer_type :installshield
action :install
end |
同样的,关于Chef最佳实践,在实现recipe时尽量使用Resource,而不是直接在Recipe中使用Ruby代码。除了上述提到的使用Ruby_block类型外,可以使用自定义Resource和对应的Provider来封装所需要的Ruby代码。Chef Resource是对某种类型的定义,定义需要哪些参数,可以提供哪些操作等。而Provider与Resource对应,为Resource类型提供变量参数的使用以及操作的具体功能实现。 |
Chef Cookbook的部署方法
在Chef Cookbook/Recipe完成后,需要将该Cookbook上传到Chef Server,使得该Cookbook被注册进Server并被使用。使用下面的Knife命令上传新版本的Cookbook。
#knife cookbook upload <mycookbook-name> -o <directory to the parent of cookbook> 上述Knife命令将返回上传成功失败信息及上传cookbook的版本信息。这样,一个新的cookbook就部署到了Chef Server中。但这也只是部署到Chef Server。如果准备在Chef client上执行我们定义的cookbook中的recipe,还需要设置run-list来说明部署时需要执行哪几个recipe以及执行顺序。这里就有两种部署方式:chef 客户端本地部署执行和chef 工作站端远程部署。
1.chef客户端本地部署执行
如果需要客户端本地执行部署操作,就需要预先定义好执行顺序,并将执行顺序赋予给该客户端。
使用knife node run_list 命令可以对某个节点或者chef 客户端添加删减run_list。例如,设置安装代理软件IEM Agent的recipe文件install.rb。每一个run_list中的单元需要根据格式recipe[cookbookname::recipe-name]来添加。
# knife node run_list add chef-client-1 "recipe[iemagent::install]" |
上述命令将会为chef 节点chef-client-1添加一个执行recipe,并将该执行节点按照添加顺序依次列入执行顺序列表中。如果要删除某个执行节点,可以执行"knife node run_list delete <client name> "recipe[recipe name]" "来删除相应的执行节点。当部署需要一次性执行多个recipe时,可以使用"knife node run_list add <client name> "recipe[recipe name]" "按照recipe执行顺序依次添加,也可以将所有待执行recipe定义在一个role对象中,再将该role对象添加到节点上。
#vi ubuntu_servers.rb
name"ubuntu_servers"
description"The base role applied to all nodes."
run_list(
"recipe[iemagent::install]",
"recipe[iemagent::start]",
"recipe[iemagent::verify]"
)
# knife role from file ubuntu_servers.rb
#knife node run_list add chef-client-1 " role[ubuntu_servers]" |
上述命令将创建一个role对象,并在role中设置了执行列表,然后将该role上传到Chef Server使之生效,然后将这个role类型赋给节点chef-client-1。 当上述所有的预备工作完成后,进入chef 节点chef-client-1,以超级用户权限执行chef-client命令,该chef客户端将自动与chef 服务器同步相关的cookbook,并安装预先定义的执行列表执行所有的recipe。
2.chef 工作站端远程部署
使用knife bootstrap命令可以在chef工作站远程执行部署命令。只需要明白目标客户机的IP地址、用户名和密码以及ssh端口,那么就直接在chef工作站直接执行以下命令。
# knife bootstrap 192.168.10.130 -x root -P 'Ve22test' -r 'role[iem_install]' |
上述命令要求IP地址为192.168.10.130的目标机器,执行role[iem_install]中执行列表,按照执行列表中的recipe顺序执行。这样优点是不需要在登陆到chef客户端,将所有执行操作都在chef工作站上完成,甚至可以对多台客户端机器进行部署。如果上述命令需要执行一些必要的传参,那么可以设置data_bag来传递数据。或者直接在knife bootstrap命令中使用json数据结构来传递需要的传参,knife bootstrap命令支持在命令中使用参数-j来携带json数据。
Knife bootstrap的优点并不只是远程执行部署命令。对于一台还未成为chef client的目标机器,knife bootstrap将会在第一次运行时强制安装chef client,并将他注册成为一个有效的chef客户机。如此,使用knife bootstrap命令就可以避免手动安装chef client并注册client的操作,从而为运维人员提供更高的效率。
Knife bootstrap并不是单单只是用来部署Chef cookbook和执行Recipe,同样可以对目标机器进行特定的配置操作。Knife bootstrap会预先指定一个脚本模版,当knife bootstrap命令通过ssh连接到目标机器时,会自动编译执行脚本模版内容。Knife bootstrap默认的脚本模版以erb为后缀,并根据不同操作系统设定不同脚本模版。默认模版首先会检查目标机器上是否已安装Chef,如果没有安装就从Chef源将客户端安装包下载并安装到默认目录,然后设置脚本(successhandler和errorhandler)接收并处理chef客户端执行的结果,最后启动chef客户端并执行赋予的Recipe。
我们可以以默认脚本模版为基础,添加额外的部署操作,就可以让目标机器默认执行这些额外的部署操作。例如我们在安装chef client之后添加ntpdate操作,强制目标机器与chef server进行ntpdate同步;我们也可以设置有效的yum源,修改模版,使目标机器从指定的有效的yum源下载安装我们需要的软件。当脚本模版修改完毕,上传到chef server默认的bootstrap目录下,就可以直接使用命令指定该脚本模版。
# knife bootstrap windows ssh 192.168.10.139 -x Administrator -P 'Ve22test' --distro windows-chef-client-msi.mine -r role[iem] |
上述knife bootstrap命令以ssh方式将脚本模版windows-chef-client-msi.mime内容发送到操作系统为windows的目标机器192.168.10.139,同时将该脚本模版转化为windows识别的bat脚本并存在临时目录下,然后在目标机器中以dos命令行方式执行生成的bat脚本。
Chef Cookbook的编译与执行
所有的Cookbook在同步到chef client准备执行时,会有一个编译操作和执行操作。编译操作会将Recipe里面使用的未封装到Resource中的所有Ruby语句进行编译,如果Ruby语句有问题,那么将会直接阻断编译操作。Recipe文件中的所有Resource代码段也将在编译阶段被编译成一个个Resource对象,但编译阶段并不涉及Resource内的具体执行。在编译Recipe完成后,所有的Resource对象进入运行阶段按照串珠顺序,一个一个执行Resource对象,直到所有Resource对象都被执行。如果有任何Resource在执行阶段因为机器状态与Resource要求不匹配,将阻断执行操作并返回失败。例如使用Chef Resource中remote_file类型去下载拷贝文件,如果远程目录中的文件不存在,即表明机器状态与该Resource要求的不符合,下载操作将失败并阻断后续的执行操作。
[root@sitechef1 zhyiqun]# knife bootstrap 9.2.139.103 -x root -P 'Ve22test' -r 'role[iem_install]' -j '{"iemagent":{"packageServer": "http://9.111.44.122/package/9.0.787.0", "version":"9.0.787.0", "redhat_x86_64":{ "package":"BESAgent-9.0.787.0-rhe5.x86_64.rpm", "disk_capacity":"100"}, "redhat_i386":{ "package":"BESAgent-9.0.787.0-rhe5.i686.rpm", "disk_capacity":"100"}, "win":{"package": "BigFix-BES-Client-9.0.787.0.exe", "disk_capacity": "100"}}, "affiliationgroup": "affiliationgroup", "list_relayServers":[ "9.2.139.53","9.2.139.63", "relay3", "relay4", "relay5", "relay6", "relay7"]}' |
Connecting to 9.2.139.103
9.2.139.103 Starting first Chef Client run...
9.2.139.103 Starting Chef Client, version 11.4.0
9.2.139.103 resolving cookbooks for run list: ["iemagent::default"]
9.2.139.103 Synchronizing Cookbooks:
9.2.139.103 - chef_handler
9.2.139.103 - windows
9.2.139.103 - iemagent
9.2.139.103 Compiling Cookbooks...
......
9.2.139.103 Converging 23 resources
9.2.139.103 Recipe: iemagent::install
......
9.2.139.103 Recipe: iemagent::start
......
9.2.139.103 Recipe: iemagent::verify
......
9.2.139.103
9.2.139.103 Chef Client finished, 20 resources updated <-----------------means the chef client run successfully |
结束语
通过以上实例,读者可以快速地对Chef Cookbook在云计算平台中的作用及开发部署有一个了解,并可以通过实例中的分析获得一些提高Chef工具部署性能的经验。本文中所展示的Chef开发技术及用到的功能特性还仅仅是冰山一角,希望能够起到一些抛砖引玉的作用,为读者在云计算和虚拟化等领域的自动化运维工作中带来一些启发。 |