结合源码,简单分析下 OpenStack puppet 安装。
puppet 安装
- 每台机器都要设置好 hostname,因为 ssl 证书需要。
- NTP 保持时间一致
- client 端安装 puppet 包
- master 端安装 puppetmaster 包
puppet 注意点
- 是 C/S 架构
- client 会定期 30 分钟和 master 通信,如果配置信息被修改,则执行。间隔修改的方法: /etc/puppet/puppet.conf 中的[agent]中设置 runinterval = 60
- 也可以人工强制执行: puppet agent -t
client 与 master 的交互过程
- 客户端 puppet 调用 facter,facter 会探测出这台主机的一些变量如主机名、内存大小、IP 地址等。然后 puppet 把这些信息发送到服务器端。
- 服务器端的 puppetmaster 检测到客户端的主机名,然后会到 manifest 里面对应的 node 配置,然后对这段内容进行解析,facter 送过来的信息可以作为变量进行处理的,node 牵涉到的代码才解析,其它的代码不解析,解析分几个过程:语法检查、然后会生成一个中间的伪代码,然后再把伪代码发给客户机。
- 客户端接收到伪代码之后就会执行,客户端再把执行结果发送给服务器。
- 服务器再把客户端的执行结果写入日志。
语法
-
变量
- 声明格式:$变量名=“值”
- 引用格式:${变量名}
- 如果要取 facts 中的值,可以使用 ${::fact-name} ,这种写法告诉人们是 top-scope variable,而不是用户自己定义的 local-scope variable
-
字符串
- ‘不包含变量的字符串用单引号’
- “包含变量的字符串需要用双引号 ${::operatingsystem} ,同时变量要用花括号包裹起来”
- 对变量本身的引用不需要单引号或双引号。 例如 ${::operatingsystem}
-
数组
- [ “apache2” , " httpd " , " ssh " ]
-
资源:
type { "title ":
attribute =>"value",
...
attribute => "value",
}
注意:
- type 不能乱写,puppet 已定义了很多 type,例如:
- file
- package
- service
- cron
- user
- group
- exec
- notify
- attribute =>“value"写法
- 属性间“,”分割
-
引用
首字母大写是引用,小写是声明
-
资源之间的关系
-
class:资源的集合
class 类名 {
type { "title ":
attribute => "value",
...
attribute => "value",
}
type { "title ":
attribute => "value",
...
attribute => "value",
}
}
-
class 继承
class 类名(新建)inherits 父类名(已存在){
Type ["title"] {attribute => "value",}
}
-
函数定义
define 函数名(变量名1,...,变量名n) { #格式:$var
type { "title ":
attribute => "变量名", #格式:${var},下同
...
attribute => "变量名",
}
type { "title ":
attribute => "变量名",
...
attribute => "变量名",
}
}
-
引用 define
函数名 {
变量名 => "值",
...
变量名 => "值",
}
类名::函数名 {
变量名 => "值",
...
变量名 => "值",
}
-
模块
up-testmodule --模块名
├── files --pp中需要用到的文件
├── manifests --所有pp文件
│ └── init.pp --入口,在其中引用其他pp
├── Modulefile
├── templates --xxx.erb
-
模块中的 namespace
例如 mysql::server
-
模板 template
- puppet 通过 erb(embedded Ruby)支持模板,模板的文件名必须以 erb 结尾
- 检查模板:
erb -x -T '-' xxx.erb | ruby -c
- 可以使用数组、条件语句、变量作用域
-
好的命名规范
- 模块名就是软件名字,例如 apache
- 类名应该是模块名::功能名,例如
apache::vhost
-
node
-
建议专门新建 nodes.pp 来存放 node 信息
-
默认节点定义
node default {
变量的声明 #声明格式:$变量名="值" 引用格式: ${变量名}
include 类名,...,类名 #已定义好的类class
}
自己编写 facter 的方法
举例:/modules/haproxy/lib/facter/haproxy_version.rb
当 agent apply haproxy 时,就在本地增加了自定义的 facter,该 facter 可以收集 agent 上的 haproxy 的版本号
facter -p haproxy_version 可以查看该 facter 值
最佳实践
调试方法:
Exec {'output': logoutput => on_failure}
notify { "aaa ${fqdn} "}
生成例子:
puppet resource file /etc/keystone/policy.json
file { '/etc/keystone/policy.json':
ensure => 'file',
content => '{md5}459ce538f825ed818c7794beeddf4523',
ctime => '2016-03-02 09:06:02 +0100',
group => '163',
mode => '640',
mtime => '2016-03-02 08:20:02 +0100',
owner => '163',
type => 'file',
}
例子: puppet client 在本地执行 manifest
-
文件管理
-
写一个 manifest: test.pp
file {
"/tmp/haha":
content => "haha"
}
-
执行 puppet apply test.pp
-
在/tmp 目录下会发现新文件
-
包管理
-
写一个 manifest: test.pp
package {
["gcc", "make", "nginx", "haproxy"]:
ensure => installed
}
-
执行 sudo puppet apply test.pp
-
上述 4 个包会被自动安装