一、class 类

1)什么是类?

  类是puppet中命名的代码模块,常用于定义一组通用目标的资源,可在puppet全局调用;
  类可以被继承,也可以包含子类;
  具体定义的语法如下:

class NAME{
... puppet code ...
}

  其中,在我们定义的时候,需要注意的是:

  • 类的名称只能以小写字母开头,可以包含小字字母、数字和下划线。
  • 每个类都会引入一个新的变量scope ,这意味着在任何时候访问类中的变量时,都得使用其完全限定名称。
    • 不过,在本地 scope 可以重新为 top scope 中的变量赋予一个新值。

  下面,我们来看一个简单的例子:

vim class1.pp
class redis { #定义一个类
package{'redis':
ensure => installed,
} -> file{'/etc/redis.conf':
ensure => file,
source => '/root/manifests/file/redis.conf',
owner => 'redis',
group => 'root',
mode => '0640',
tag => 'redisconf'
} ~> service{'redis':
ensure => running,
enable => true,
hasrestart => true,
hasstatus => true
}
} include redis #调用类

  注意:类只有被调用才会执行。include后可以跟多个类,直接用","隔开即可。

2)带有参数的类

  我们定义的类也可以进行参数设置,可以进行参数的传递。
  具体语法如下所示:

class NAME(parameter1, parameter2) {	#注意,大括号前有一个空格
...puppet code...
}

  我们来看一个例子:

vim class2.pp
class instpkg($pkg) {
package{"$pkg":
ensure => installed,
}
} class{"instpkg": #给参数传入值
pkg => 'memcached',
}

  注意:单个主机上不能被直接声明两次
  如果对应的参数未传值的话,执行会报错。
  但是我们可以在定义形参的时候,设定一个默认值,这样的话,我们不传入值的话,就会自动调用默认值:

vim class3.pp
class instpkg($pkg='wget') {
package{"$pkg":
ensure => installed,
}
} include instpkg

  这样的话,我们直接使用include调用即可,就不需要给参数传入值了。
  由上,我们可以总结出,调用类的方式有两种

1. include CLASS_NAME1, CLASS_NAME2, ...
2. class{'CLASS_NAME':
attribute => value,
}

  我们来看一个比较全面的例子:
  首先,判断我们系统的版本,是6还是7,由此来确定,是安装mysql还是mariadb,同时,使用调用参数的方式来实现如上需求。
  具体实现的代码如下:

vim dbserver.pp
class dbserver($dbpkg='mariadb-server',$svc='mariadb') { #定义类并给参数赋值
package{"$dbpkg":
ensure => installed,
} service{"$svc":
ensure => running,
enable => true,
hasrestart => true,
hasstatus => true,
}
} if $operatingsystem == 'CentOS' {
if $operatingsystemmajrelease == '7' {
include dbserver #直接调用类
} else {
class{"dbserver": #调用类并对参数重新赋值
dbpkg => 'mysql-server',
svc => 'mysqld'
}
}
}

3)类的继承

  类似于其它编程语言中的类的功能,puppet 的Class 可以被继承,也可以包含子类。
  其定义的语法如下:

class SUB_CLASS_NAME inherits PARENT_CLASS_NAME {
...puppet code...
}

  下面我们来看一个例子:

vim class4.pp
class redis { #定义class类
package{'redis':
ensure => installed,
} service{'redis':
ensure => running,
enable => true,
}
} class redis::master inherits redis { #调用父类
file {'/etc/redis.conf':
ensure => file,
source => '/root/manifests/file/redis-master.conf',
owner => 'redis',
group => 'root',
} Service['redis'] { #定义依赖关系
subscribe => File['/etc/redis.conf']
}
} class redis::slave inherits redis { #调用父类
file {'/etc/redis.conf':
ensure => file,
source => '/root/manifests/file/redis-slave.conf',
owner => 'redis',
group => 'root',
} Service['redis'] { #定义依赖关系
subscribe => File['/etc/redis.conf']
}
}

  一样的,我们的类在调用的时候,可以实现修改原有值额外新增属性的功能。

1.新增属性

  我们的继承父类的时候,可以定义一些父类原本没有的属性:

新增属性

2.新增原有值

  在继承的类中,我们可以在属性原有值的基础上,使用 +> 进行新增修改:

新增原有值

3.修改原有值

  在继承的类中,我们可以直接把原有的值进行覆盖修改,使用 =>进行覆盖即可:

修改原有值

4.整体调用父类,并重写部分值

  在继承的类中,我们还可以在整体调用的基础上,根据不同的需求,把父类中的部分值进行重写修改:

整体调用父类,并重写部分值

二、模板

  模板通常以erb结尾。模板均使用erb语法。
  关于puppet兼容的erb语法,我们可以去官方文档查看,下面附上官方文档地址:https://docs.puppet.com/puppet/latest/reference/lang_template_erb.html
  以下,附上部分重要内容:

    <%= EXPRESSION %> — 插入表达式的值,进行变量替换
<% CODE %> — 执行代码,但不插入值
<%# COMMENT %> — 插入注释
<%% or %%> — 插入%

  接着我们来看一个实例:

实例1:puppet 模板实现修改 redis 端口地址

  我们使用puppet 模板来实现,将redis 监听端口修改为本机的ip地址。
  首先,我们先来定义一个file.pp文件,在该文件中调用我们的模板:

vim file.pp
file{'/tmp/redis.conf': #仅用于测试模板是否生效,所以放在tmp目录下
ensure => file,
content => template('/root/manifests/file/redis.conf.erb'), #调用模板文件
owner => 'redis',
group => 'root',
mode => '0640',
}

  接着,我们去修改配置文件的源,也就是我们的模板文件:

vim file/redis.conf.erb
bind 127.0.0.1 <%= @ipaddress_eth0 %> #修改监听端口

  修改完成以后,我们就可以执行查看结果了:

	puppet apply -v file.pp

  然后,我们去查看一下/tmp/redis.conf文件:

	vim /tmp/redis.conf
监听端口

  可以看出,我们的变量替换已经成功。

三、模块

1)什么是模块?

  实践中,一般需要把manifest 文件分解成易于理解的结构,例如将类文件、配置文件甚至包括后面将提到的模块文件等分类存放,并且通过某种机制在必要时将它们整合起来。
  这种机制即模块,它有助于以结构化、层次化的方式使用puppet,而puppet 则基于“模块自动装载器”。
  从另一个角度来说,模块实际上就是一个按约定的、预定义的结构存放了多个文件或子目录的目录,目录里的这些文件或子目录必须遵循其命名规范

2)模块的命名规范

  模块的目录格式如下:

目录格式

  其中,每个文件夹中存放的内容及其要求如下:

  • MODULE NAME:模块名称,模块名只能以小写字母开头,可以包含小写字母、数字和下划线;但不能使用"main"和"settings";
  • manifests/:必须要有
    • init.pp:必须一个类定义,类名称必须与模块名称相同;
  • files/:静态文件;
    • 其中,每个文件的访问路径遵循:puppet:///modules/MODULE_NAME/FILE_NAME
  • templates/
    • 其中,每个文件的访问路径遵循:tempate('MOD_NAME/TEMPLATE_FILE_NAME')
  • lib/:插件目录,常用于存储自定义的facts以及自定义类型;
  • spec/:类似于tests目录,存储lib/目录下插件的使用帮助和范例;
  • tests/:当前模块的使用帮助或使用范例文件;

实例:定义一个redis主从模块

  下面我们就来看一个实例来具体的了解应该如何定义一个模块:
1)我们先来创建对应的目录格式:

[root@master ~]# mkdir modules
[root@master ~]# cd modoules/
[root@master modules]# ls
[root@master modules]# mkdir -pv redis/{manifests,files,templates,tests,lib,spec}
mkdir: created directory ‘redis’
mkdir: created directory ‘redis/manifests’
mkdir: created directory ‘redis/files’
mkdir: created directory ‘redis/templates’
mkdir: created directory ‘redis/tests’
mkdir: created directory ‘redis/lib’
mkdir: created directory ‘redis/spec’

2)目录格式创建完成之后,我们就可以来创建对应的父类子类文件了。
  首先,我们来创建父类文件:

[root@master modules]# cd redis/
[root@master redis]# vim manifests/init.pp
class redis {
package{'redis':
ensure => installed,
} -> service{'redis':
ensure => running,
enable => true,
hasrestart => true,
hasstatus => true,
require => Package['redis'],
}
}

  创建完成后,我们再来创建对应的子类文件:

[root@master redis]# vim manifests/master.pp
class redis::master inherits redis {
file {'/etc/redis.conf':
ensure => file,
source => 'puppet:///modules/redis/redis-master.conf',
owner => 'redis',
group => 'root',
mode => '0640',
} Package['redis'] -> File['/etc/redis.conf'] ~> Service['redis']
}
[root@master redis]# vim manifests/slave.pp
class redis::slave($master_ip,$master_port='6379') inherits redis {
file {'/etc/redis.conf':
ensure => file,
content => template('redis/redis-slave.conf.erb'),
owner => 'redis',
group => 'root',
mode => '0640',
} Package['redis'] -> File['/etc/redis.conf'] ~> Service['redis']
}

3)准备文件:
  现在我们需要把模板文件准备好,放入我们的templates目录下:

	scp redis.conf.erb /root/modules/redis/templates/redis-slave.conf.erb

  还有我们的静态文件,也要放入我们的files目录下:

	scp redis.conf /root/modules/redis/files/redis-master.conf

4)查看目录结构,确定我们是否都已准备完成:

[root@master modules]# tree
.
└── redis
├── files
│   └── redis-master.conf
├── lib
├── manifests
│   ├── init.pp
│   ├── master.pp
│   └── slave.pp
├── spec
├── templates
│   └── redis-slave.conf.erb
└── tests 7 directories, 5 files

5)现在就可以把我们的准备好的模块放入系统的模块目录下:

[root@master mdoules]# cp -rp redis/ /etc/puppet/modules/

  注意,模块是不能直接被调用的,只有放在/etc/puppet/modules下,或/usr/share/puppet/modules目录下,使其生效才可以被调用。
  我们可以来查看一下我们的模块到底有哪些:

[root@master mdoules]# puppet module list
/etc/puppet/modules
└── redis (???)
/usr/share/puppet/modules (no modules installed)

  可以看出,我们的模块已经定义好了,现在我们就可以直接调用了。
6)调用模块
  我们可以直接命令行传入参数来调用我们准备好的模块:

[root@master modules]# puppet apply -v --noop -e "class{'redis::slave': master_ip => '192.168.37.100'}"		#如果有多个参数,直接以逗号隔开即可

  也可以把我们的调用的类赋值在.pp文件中,然后运行该文件。

[root@master ~]# cd manifests/
[root@master manifests]# vim redis2.pp
class{'redis::slave':
master_ip => '192.168.37.100',
}
[root@master manifests]# puppet apply -e --noop redis2.pp

  以上。实验完成。
  注意,以上实验是我们在单机模式下进行的,如果是要在master/agent 模式下进行,步骤还会略有不同。

四、master/agent 模型

  master/agent模型时通过主机名进行通信的,下面,就来看看 master-agent 模式的puppet运维自动化如何实现:

实现步骤

1、实现前准备

1)下载包
master 端:puppet.noarchpuppet-server.noarch
agent 端:puppet.noarch

puppet包查询

2)主机名解析
  为了方便我们后期的操作,我们可以通过定义/etc/hosts文件实现主机名的解析。如果机器很多的话,可以使用DNS进行解析。

[root@master ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.37.111 master.keer.com
192.168.37.122 server1.keer.com

  注意,该操作需要在每一台主机上进行。
  修改完成以后,我们可以来测试一下是否已经成功:

[root@master ~]# ping server1.keer.com
连通性测试

3)时间同步

[root@master ~]# systemctl start chronyd.service

  所有机器上都开启chronyd.service服务来进行时间同步
  开启过后可以查看一下状态:

[root@master ~]# systemctl status chronyd.service
时间同步状态

  我们可以使用chronyc sources命令来查看时间源:

查看时间源

2、开启 master 端的 puppet 服务

1)手动前台开启,观察服务开启过程:

puppet master -v --no-daemonize		#前台运行


  整个过程都是自动完成的,其中,每一步的意思如下:
  ① 创建key 给CA
  ② 创建一个请求给CA
  ③ 自签名证书
  ④ CA 创建完成
  ⑤ 创建证书吊销列表
  ⑥ 为当前的master 主机签署证书
  ⑦ master 的证书签署完成

2)直接systemctl开启服务,监听在8140端口。

开启服务

3、在 agent 端开启服务

1)在配置文件中指明server端的主机名:

[root@server1 ~]# vim /etc/puppet/puppet.conf
server = master.keer.com
agent端配置文件

  接着,我们可以通过puppet config print命令来打印输出我们配置的参数:

[root@server1 ~]# puppet config print   显示配置文件中的配置参数
[root@server1 ~]# puppet config print --section=main 显示main 段的配置参数
[root@server1 ~]# puppet config print --section=agent 显示agent 段的配置参数
[root@server1 ~]# puppet config print server 显示server 的配置参数
打印输出参数

2)开启 agent 服务

开启agent服务

  我们可以发现,他会一直卡在这里等待CA颁发证书。

3)在 master 端签署证书

[root@master ~]# puppet cert list
"server1.keer.com" (SHA256) B5:67:51:30:5C:FB:45:BA:7A:73:D5:C5:87:D4:E3:1C:D7:02:BE:DD:CC:7A:E2:F0:28:34:87:86:EF:E7:1D:E4
[root@master ~]# puppet cert sign server1.keer.com #颁发证书
Notice: Signed certificate request for server1.keer.com
Notice: Removing file Puppet::SSL::CertificateRequest server1.keer.com at '/var/lib/puppet/ssl/ca/requests/server1.keer.com.pem'

master 端管理证书部署的命令语法如下:
puppet cert <action> [–all|-a] [<host>]
  action:
    list 列出证书请求
    sign 签署证书
    revoke 吊销证书
    clean 吊销指定的客户端的证书,并删除与其相关的所有文件;

注意:某agent证书手工吊销后重新生成一次;
  On master host:
    puppet cert revoke NODE_NAME
    puppet cert clean NODE_NAME
  On agent host:
    重新生成的主机系统,直接启动agent;
    变换私钥,建议先清理/var/lib/puppet/ssl/目录下的文件

4)终止服务开启,再次开启

[root@server1 ~]# puppet agent -v --noop --no-daemonize
开启agent端服务

  可以看出我们的服务开启成功,但是由于master 端没有配置站点清单,所以没有什么动作。

4、配置站点清单,且测试agent 端是否实现

1)设置站点清单
① 查询站点清单应存放的目录,(可以修改,去配置文件修改)

[root@master ~]# puppet config print |grep manifest
查询配置文件的参数
[root@master ~]# cd /etc/puppet/manifests/
[root@master manifests]# vim site.pp
node 'server1.along.com' {
include redis::master
}

  分析:就是简单的调用模块,只有模块提前定义好就可以直接调用;我调用的是上边的redis 模块

2)给puppet 用户授权
  因为agent 端要来master 端读取配置,身份是puppet

[root@master manifests]# chown -R puppet /etc/puppet/modules/redis/*

3)[root@server1 ~]# puppet agent -v --noop --no-daemonize 手动前台开启agent 端服务

enter description here

(4)直接开启服务,agent 会自动去master 端获取配置
[root@server1 ~]# systemctl start puppetagent 包已下载,服务也开启了

enter description here

实战 —— 使用master-agent 模型完成完整的redis 主从架构

1)环境准备

机器名称 IP配置 服务角色
puppet-master 192.168.37.111 puppet的master
puppet-server1-master-redis 192.168.37.122 puppet的agent,redis 的master
puppet-server2-slave-redis 192.168.37.133 puppet的agent,redis 的slave

2)实验前准备

1)下载包
master 端:puppet.noarchpuppet-server.noarch
agent 端:puppet.noarch

puppet包查询

2)主机名解析
  为了方便我们后期的操作,我们可以通过定义/etc/hosts文件实现主机名的解析。如果机器很多的话,可以使用DNS进行解析。

[root@master ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.37.111 master.keer.com
192.168.37.122 server1.keer.com
192.168.37.133 server2.keer.com

  注意,该操作需要在每一台主机上进行。
  修改完成以后,我们可以来测试一下是否已经成功:

[root@master ~]# ping server1.keer.com
连通性测试

3)时间同步

[root@master ~]# systemctl start chronyd.service

  三台机器上都开启chronyd.service服务来进行时间同步
  开启过后可以查看一下状态:

[root@master ~]# systemctl status chronyd.service
时间同步状态

  我们可以使用chronyc sources命令来查看时间源:

查看时间源

3)开启puppet 的master、agent 服务

(1)开启服务

[root@master ~]# systemctl start puppetmaster
[root@server1 ~]# systemctl start puppetagent
[root@server2 ~]# systemctl start puppetagent

  因为server2 是第一次连接,需master 端签署证书

(2)master 签署颁发证书

[root@master manifests]# puppet cert list
[root@master ~]# puppet cert sign server2.keer.com
master 颁发证书

4)配置站点清单

[root@master manifests]# cd /etc/puppet/manifests
[root@master manifests]# vim site.pp 直接调上边完成的模块
node 'server1.keer.com' {
include redis::master
} node 'server2.keer.com' {
class{'redis::slave':
master_ip => 'server1.keer.com'
}
}

5)检测主从架构

[root@server2 ~]# vim /etc/redis.conf
检测主从架构
[root@server2 ~]# redis-cli -a keerya info Replication
enter description here

6)再添加个模块准备配置进站点清单

(1) 创建一个 chrony 模块,前准备

[root@master ~]# cd modules/    进入模块工作目录
[root@master modules]# mkdir chrony 创建chrony 的模块
[root@master modules]# mkdir chrony/{manifests,files} -pv 创建模块结构

(2)配置chrony 模块

[root@master modules]# cd chrony/
[root@master chrony]# cp /etc/chrony.conf files/
[root@master puppet]# vim files/chrony.conf
# test #用于测试实验结果
添加一行
[root@master chrony]# vim manifests/init.pp
class chrony {
package{'chrony':
ensure => installed
} -> file{'/etc/chrony.conf':
ensure => file,
source => 'puppet:///modules/chrony.conf',
owner => 'root',
group => 'root',
mode => '0644'
} ~> service{'chronyd':
ensure => running,
enable => true,
hasrestart => true,
hasstatus => true
}
}

(3)puppet 添加这个模块,并生效

[root@master modules]# cp -rp chrony/ /etc/puppet/modules/
[root@master modules]# puppet module list
查看puppet模块列表

7、再配置站点清单

[root@master ~]# cd /etc/puppet/manifests/
[root@master manifests]# vim site.pp
node 'base' {
include chrony
} node 'server1.keer.com' inherits 'base' {
include redis::master
} node 'server2.keer.com' inherits 'base' {
class{'redis::slave':
master_ip => 'server1.keer.com'
}
}
#node /cache[1-7]+\.keer\.com/ { #可以用正则匹配多个服务器使用模块
# include varnish
#}

8、测试

  我们现在直接去server2机器上,查看我们的配置文件是否已经生效,是否是我们添加过一行的内容:

[root@server2 ~]# vim /etc/chrony.conf
server2上的内容

  发现我们的实验成功。

自动化运维工具——puppet详解(二)的更多相关文章

  1. 企业级自动化运维工具---puppet详解

    本文收录在Linux运维企业架构实战系列 1.认识puppet 1.1 引入 puppet是什么,咱们先不用专业的名词解释它,咱们先描述一些工作场景,看明白这些工作场景,自然会知道puppet是什么. ...

  2. 项目10.2-企业级自动化运维工具---puppet详解

    1.认识puppet 1.1 引入 puppet是什么,咱们先不用专业的名词解释它,咱们先描述一些工作场景,看明白这些工作场景,自然会知道puppet是什么. (1)场景一: 管理员想要在100台服务 ...

  3. 自动化运维工具——puppet详解(一)

    一.puppet 介绍 1.puppet是什么 puppet是一个IT基础设施自动化管理工具,它能够帮助系统管理员管理基础设施的整个生命周期: 供应(provisioning).配置(configur ...

  4. 自动化运维工具——ansile详解

    自动化运维工具——ansible详解(一) 目录 ansible 简介 ansible 是什么? ansible 特点 ansible 架构图 ansible 任务执行 ansible 任务执行模式 ...

  5. 自动化运维工具——ansible详解(一)

    ansible 简介 ansible 是什么? ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.chef.func.fabric)的优点,实现了批量系统 ...

  6. ansible自动化运维工具使用详解

    一. ansible 简介 1. ansible ansible是新出现的 自动化 运维工具 , 基于Python研发 . 糅合了众多老牌运维工具的优点实现了批量操作系统配置.批量程序的部署.批量运行 ...

  7. 自动化运维工具——ansible详解(二)

    Ansible playbook 简介 playbook 是 ansible 用于配置,部署,和管理被控节点的剧本. 通过 playbook 的详细描述,执行其中的一系列 tasks ,可以让远端主机 ...

  8. 自动化运维工具 ~puppet~

    一.模板的应用 到目前为止,资源申报.定义类.声明类等所有功能都只能一个manifest文件中实现,但这却非有效的基于puppet管理IT资源架构的方式.实践 中,一般需要把manifest文件分解成 ...

  9. 自动化运维工具Ansible的部署步骤详解

    本文来源于http://sofar.blog.51cto.com/353572/1579894,主要是看到这样一篇好文章,想留下来供各位同僚一起分享. 一.基础介绍 ================= ...

随机推荐

  1. 2015上海赛区B Binary Tree

    B - Binary Tree   Description The Old Frog King lives on the root of an infinite tree. According to ...

  2. iOS 中的 Delayed Transition

    Android 的动画体系中,存在一类由 TransitionManager. beginDelayedTransition 管理的动画.这个方法,很特殊.执行此方法后,其后续的 UI 变化,不会立即 ...

  3. 远程连接SQL Server 2014遇到的问题和解决

    在本机可以通过IP地址的数据库引擎登录数据库,可用同网段的其它电脑远程登录一直不成功.查看网上资料,认为是主机防火墙的问题. 在微软网站上查找相关的文档找到了答案.http://msdn.micros ...

  4. display、visibility、visible区别

    标签的隐藏可以有三种:display.visibility.服务器控件的visible. 显然,这三者都能起到隐藏与显示的效果,但是用途确完全不一样,请看用法与区别: <div style=&q ...

  5. javaScript中的return,break,continue的区别

    导语: javaScript中有三种方法可以跳出循环或者终止循环.分别为break.return.continue. 正文: 一.break break 会使得整个程序终止执行或者包含了最内层的循环或 ...

  6. HTML学习笔记 iframe引用页面按列(针对target打开方式解释) 第九节 (原创)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. DevExpress.XtraEditors.TextEdit 设为密码输入框

    DevExpress.XtraEditors.TextEdit 设为密码输入框,解决办法: 设计窗口-->属性Properties-->Mask节点-->PasswordChar输入 ...

  8. 流式数据分析模型kafka+storm

    http://www.cnblogs.com/panfeng412/archive/2012/07/29/storm-stream-model-analysis-and-discussion.html ...

  9. SpringMVC处理ajax请求的注意事项

    .首先要知道ajax请求的核心是JavaScrip对象和XmlHttpRequest,而浏览器请求的核心是浏览器 ajax请求 浏览器请求 场景一:使用ajax获取session中的user 从上图可 ...

  10. 使用dropwizard(5)--加入swagger

    前言 Swagger已经成API service的规范了,本处在dropwizard中简单集成Swagger. Demo source https://github.com/Ryan-Miao/l4d ...