Chef 是一个自动化工具,用 Opscode 开发, 使用 Ruby DSL 以一种可重复使用的格式表示配置服务器所需的命令
Chef 经常运行在服务器集群的枢纽,统筹安排其他服务器的配置
可以在单机模式下使用 Chef (Chef Solo)
在这种模式下,我们在本地开发平台上定义服务器的各种角色和设置,然后根据需要手动应用这些设置
如果项目不断扩大也不用担心,使用 Chef Solo 制定的自动化配置大多数都可以在 Chef 中使用
Knife 是一个命令行工具,为本地开发环境中的 Chef 仓库和远程服务器之间提供交互接口
一般情况下,远程服务器必须是主 Chef 服务器。 不过 Knife Solo 允许在单机模式下使用 Chef, 可以直接和需要配置的服务器交互
在 Chef 中,安装各组件所需的命令成为「配方」
Berkshelf 就像是配方的 Bundler
我们使用 Berkshelf 获取配置服务器所需的 Chef 配方(特定的版本)
定义安装单个组件(例如 Ruby, mysql-server, Monit 等)所需的命令
相关的配方集合,例如,mysql 食谱中包含 mysql-server 配方和 mysql-client 配方
要配置的远程服务器
一系列配方的组合,应用在节点上
例如,Postgres Server 角色可能会包含安装 postgres-server 的配方,安装和设置防火墙的操作, 以及安装合适的服务器监控工具的操作
配方所用的元数据,保存为 JSON 格式文件。 例如,要创建的用户列表,以及相应的公钥
一系列节点和角色定义
新建文件夹
mkdir chef_repo
cd chef_repo
安装工具
bundle init
source 'https://rubygems.org'
gem 'knife-solo', '0.3.0'
gem 'chef', '~> 11.10.0'
gem 'chef-zero', '1.7.2'
gem 'berkshelf', '~> 2.0.14'
bundle install
使用 bundle exec 确保使用的 Gemfile 中定义的 gem 版本来执行命令
bundle exec knife solo init .
生成若干文件,结构如下:
chef_repo ├── .chef │ └── knife.rb ├── .gitignore ├── Berksfile ├── Gemfile ├── Gemfile.lock ├── cookbooks │ └── .gitkeep ├── data_bags │ └── .gitkeep ├── environments │ └── .gitkeep ├── nodes │ └── .gitkeep ├── roles │ └── .gitkeep └── site-cookbooks └── .gitkeep
下面来说说各个文件及文件夹的作用
Knife 是个命令行工具,可以和远程服务器上的 Chef 交互
Knife Solo 添加了额外的命令,可以在本地开发设备上直接和要配置的服务器交互 (而不用通过 Chef 中央服务器中转)
knife.rb 中包含针对我们这个仓库的 Knife 设置。 这个文件在使用 Chef 中央服务器时更有用, 并不符合我们使用的单机模式,但却是 Knife 的主要设置(也是唯一的设置文件)
Knife 的全部设置选项可以在 http://docs.opscode.com/config_rb_knife.html 中查看
目前,我们要设置的重要选项如下:
cookbook_path
这个选项是个数组,包含很多相对于仓库根目录的路径, 指定角色中使用的食谱和节点定义的存储位置
node_path
相对仓库根目录的路径,指定节点定义存储的位置
role_path
相对仓库根目录的路径,指定角色定义存储的位置
data_bag_path
相对仓库根目录的路径,指定数据包的存储位置
一般情况下,都可以直接使用默认值
在 Berkfile 中定义 Chef 仓库要使用的食谱,以及各自的版本。 然后执行 bersk install
命令安装这些食谱。 如果食谱在 metadata.rb 文件用 depends 定义了依赖食谱,Berkshelf 会负责安装这些依赖食谱
和 Bundler 一样,Berkshelf 也会生成一个 Berksfile.lock 文件,写入食谱及相应的版本号
cookbooks 文件夹用来存放使用 Berkshelf 安装的他人编写的食谱
如想存放自己编写的食谱,应放在 site-cookbooks 文件夹
千万别在 cookbooks 文件夹中存放没有使用 Berkshel 来管理的食谱, 因为,每次运行 knife solo 后,cookbooks 文件夹中的内容都会被抹去重新写入
如果食谱中要用到大量数据,就可以将数据存放在这里
对应现实中的工作流,比如说生产环境,准备环境,测试环境,开发环境
存放节点文件
存放角色文件
用来存放自己编写的食谱
以 redis-tlq 食谱为例:https://github.com/TalkingQuickly/redis-tlq
将其作为自己编写的食谱放到 site-cookbooks
文件夹下
文件结构如下:
redis-tlq ├── attributes │ └── default.rb ├── metadata.rb ├── recipes │ └── default.rb └── templates └── default ├── redis-server.erb └── redis.conf.erb
下面是各个文件及文件夹的说明
元数据文件中详细说明了这个食谱的作用,编写人,依赖件以及版本号
metadata.rb:
# 食谱的名称 name "redis-tlq" maintainer "Ben Dixon" maintainer_email "ben@talkingquickly.co.uk" description "Installs redis from rwky's ppa" # 食谱的版本号 version "0.0.6" # 配方的名称 recipe "redis-tlq", "Installs redis" # 指定这个食谱支持的操作系统 # 这个设置很重要,因为我们这个简单的食谱只支持 Ubuntu, 会用到一些只有 Ubuntu 才支持的命令 supports "ubuntu"
使用 Berkshelf 时,version 和 recipe 这两行是关键的设置, Berkshelf 会查看 metadata.rb 文件,确认要使用的食谱中是否有匹配的配方
还有一个选项 depends 这里没提到,用来指定要依赖的其他食谱
Chef 食谱必须包含一个名为 default 的配方
如果在节点或角色定义中使用到了某个食谱,而没有指定要用哪个配方,就会使用这个默认配方
cookbooks/redis-tlq/recipes/default.rb:
# use redis from ppa rather than the one # available in the package manager. rwky # builds the stable version and is kept # consistently up to date. We need python-software-properties # for add-apt-repository to work # Chef 首先会使用操作系统的包管理工具检查是否安装了 python-software-properties 代码包 # 如果没有,那就安装 package 'python-software-properties' # 告诉 Chef, 其中包含的命令是在 bash 中执行的 # 随后的文本会在配方执行时显示出来,让用户知道配方正在做什么 bash 'adding stable redis ppa' do # 以 root 这个用户身份去执行 user 'root' code <<-EOC add-apt-repository ppa:chris-lea/redis-server apt-get update EOC end package 'redis-server' # 上述操作只是安装了 Redis, 我们还要对其进行一些自定义设置, # 再添加初始化脚本用于启动、停止 Redis 服务器,这就轮到 template 出场了 # # 这段代码的作用如下: # 1. 在 redis-tlq/template/default 文件夹中寻找文件 redis.conf.erb # 2. 解析这个文件中的所有 erb 代码,然后把文件复制到节点上,存放位置为 /etc/redis/redis.conf # 3. 把这个文件的拥有者设为 root 用户组的 root, 权限为 0644 template "/etc/redis/redis.conf" do owner "root" group "root" mode "0644" source "redis.conf.erb" notifies :run, "execute[restart-redis]", :immediately end # ...
templates 文件夹中的子文件夹对应的是服务器上所安装的操作系统
如果使用的是 Ubuntu 12.04, 上面的 template 代码块就会在下面的路径中按顺序寻找 redis.conf.erb 文件:
templates/ubuntu-12.04/redis.conf.erb
templates/ubuntu/redis.conf.erb
remplates/default/redis.conf.erb
如果要编写复杂的食谱,照应多种操作系统,这种处理方式的强大就体现出来了
目前,我们仅仅使用 default 文件夹
配方可以使用属性 (attribute) 进行定制。 属性可以在多个地方设定,包括:
一般情况下,在食谱中会为属性指定默认值,如果需要,可以覆盖默认值
在 templates/default/redis.conf.erb
文件中有这么一段代码:
<% unless node[:redis] && node[:redis][:dont_bind] %> bind 127.0.0.1 <% end %>
如果在节点中有如下代码:
{ "redis": { "dont_bind": true } }
那么就执行 bind 127.0.0.1
这段代码
在食谱中可以为属性定义默认值。 这往往也是推荐的做法,大多数用户只要做少许改动就可使用
属性的默认值在 attributes/default.rb
文件中定义:
# whethere to prevent redis from binding to 127.0.0.1 default[:redis][:dont_bind] = false
上面代码的作用是:
会把 false
应用到食谱 node[:redis][:dont_bind]
,除非默认值被覆盖了
关于属性的更多说明,请阅读 OpsCode 网站上的文档:
http://docs.opscode.com/essentials_cookbook_attribute_files.html
新建角色文件
touch roles/redis-server.json
写入如下内容:
{ "name": "redis-server", "description": "Redis server", "default_attributes": { "redis": { "dont_bind": false } }, "run_list": [ "recipe[redis-tlq]", "recipe[monit-tlq]", "recipe[monit_configs-tlq::redis-server]" ], "json_class": "Chef::Role" }
代码解释如下:
指定角色的名称
当 Chef 在运行列表中见到 rolo[redis-server]
时,就会寻找名为 redis-server 的角色。 寻找的范围是 knife.rb 中role_path
对应文件夹中所有的 JSON 文件
描述这个角色的作用
用来设置默认属性
是一个数组,Chef 会依次安装执行列出的配方和角色
角色使用如下格式:
role[role_name]
配方使用如下格式:
recipe[cookbook_name::recipe]
如果使用 JSON 格式,那么必须加上这一行
如果使用 Ruby 格式,则不用加
因为使用到了 2 个额外的食谱 monit-tlq 和 monit_configs-tlq
前者用于监控系统的各种参数,如果进程崩溃或者超出了预设的参数,Monit 会重启该进程
后者是针对系统组件的 Monit 设置
所以我们需要在仓库根目录的 Berksfile
文件中加入如下内容:
cookbook 'monit-tlq', github: 'TalkingQuickly/monit-tlq', branch: 'master' cookbook 'monit_configs-tlq', github: 'TalkingQuickly/monit_configs-tlq', branch: 'master'
把公钥复制到远程服务器
ssh-copy-id root@yourserverip
在远程服务器上安装 Chef, 在本地仓库根目录执行如下命令:
bundle exec knife solo prepare root@yourserverip
若使用 Vagrant 可以用 vagrant ssh-config
命令查看 ssh 配置,然后执行如下类似命令:
bundle exec knife solo prepare vagrant@127.0.0.1 -p 2222 -i /Users/mwum/.vagrant.d/insecure_private_key
安装时间稍长,耐心等待吧
上述命令的作用如下:
* 在 nodes 文件夹中新建文件 yourserverip.json * 通过 SSH 登入远程服务器 * 检测操作系统的类型 * 安装相应的 Chef 版本
如果不确定是什么问题,可以在安装 Chef 的命令加上 -VV
选项来查看 DEBUG 信息
远程服务器的网络有问题,需要设置代理
用 ssh 登录远程服务器
在 ~/.bashrc 中加入如下内容:
export http_proxy="http://your-proxy.company.org:80"
export https_proxy="http://your-proxy.company.org:80"
export HTTP_PROXY="http://your-proxy.company.org:80"
export HTTPS_PROXY="http://your-proxy.company.org:80"
配置节点文件 nodes/yourserverip.json
, 加入如下内容:
{
"redis": {
"dont_bind": false
},
"run_list": [
"role[redis-server]"
]
}
代码上半段是属性定义,run_list
的作用和角色文件中的一样
应用配方,在仓库根目录下执行如下命令:
bundle exec knife solo cook root@yourserverip
这个命令的作用如下:
* 根据 Berksfile 文件通过 Berkshelf 下载食谱(相当于此命令 `berks vendor cookbookss/) * 通过 SSH 登入远程服务器 * 把本地的配方文件复制到远程服务器 * 应用配方,并显示输出结果
如果要经常重用某个节点定义,可以将其另存为,例如 nodes/side_project_server.json, 然后执行如下命令:
bundle exec knife solo cook root@yourserverip nodes/side_project_server.json
参考图书:
《Rails 程序部署之道》