本文共 5890 字,大约阅读时间需要 19 分钟。
之前讲了puppet当中的编程元素,包括变量,和流程控制语句,当中的条件判断,if unless,case和selector,这些流程控制语句可以在条件满足的时候,来完成流程控制事的所谓配置文件的编写 但是有时候我们需要用代码来完成重用,事实上对于configuration 而言, 支持另外两种编程元素,函数,类,用的最多是类 puppet的编程源支持两种编程方式,过程式编程和对象式编程,ruby本身就是对象式编程,在puppet代码中也支持类,要想能去配置nginx,nginx有两种功能,web server,反代reverse proxy(7层反代。,4层反代) 配置起来的步骤,无非就是安装程序包,提供配置文件,启动服务 无非就是配置文件不一样 安装程序包,和启动程序,这段配置是可以进行公用的,所以可以把安装包和启动程序定义成一个公共的模块,而后在定义,三个子功能都能调用这个公用的公共模块 而在类的架构当中,这种方式十分容易实现
先定义一个父类,父类其实有两个资源,1.安装程序包,2.启动服务 而后再定义三个子类分别去继承父类,而后在子类中定义一个新资源,比如提供配置文件A文件 再定一个子类,也添加一个文件资源,继承父类 从父类可以得到一部分定义,在本地直接调用使用
父类也叫做基类,这里类更像是过程式编程中的函数,所不同的是,比函数功能更强大,不但能继承,还能重载某些运算符,把某些对应的数据,在子类中额外补充一个功能也可以 父类的资源到子类里,子类觉得不适合,完全可以重写,把原来复制的资源覆盖掉,但是后面的两个子类可以不这么做 对象式编程是以数据为中心,围绕数据组织代码,代码服务于数据,用于改变数据状态 puppet的类: 类:puppet中命名的代码模块,常用于定义一组通用目标的资源,可在puppet全局调用;(不光是当前节点,整个puppet集群) 类可以被继承,也可以包含子类;语法格式:
class NAME {可以想象成自定义类型 …puppet code… }class NAME(parameter1, parameter2) {可以给形参赋值,以在类中进行调用
…puppet code… } 写完类,是不会运行的,等于写完函数,不调用是不会运行的 ,类定义好后,相当于自定义类型,直接拿自定义类型过来,定义成一个资源,才能运行 类代码只有声明后才会执行,调用方式: 类被定义成资源的方式有两种 (1) include CLASS_NAME1, CLASS_NAME2, … (2) class{‘CLASS_NAME’: attribute => value,属性=复制 } 定义一个安装nginx,启动服务 class取名=nginx 正常写的代码放到class内部即可 定义函数一样,是不会执行的 使用include调用 没安装nginx,需要安装 定义include,也可以在外面写 加-e选项,表示执行,include nginx 当前主机找不到nginx类,因为默认在这里引用nginx类,需要找类的时候,是到模块文件中找的,而不是在manifest文件找的, 所以此时带不到后面的文件都没什么区别,必须把整个文件放置成模块才可以 现在必须定义这里,申明类,类还可以有参数(比如centos6是mysqlcentos7是mariadb) facter-p 操作系统是7,主发行版本是7 这里可以用if条件嵌套以后判断 如果说操作系统的版本是centos,再嵌套进去判断,主版本号判定,如果是7就返回mariadb-server,6就返回mysqld-server 这串代码是真正执行时才写的,现在还没有类 创建一个dbserver类,传递参数,定义安装程序包 下面的先不管,上面的代码想要运行,必须要调用,如果要调用,必须要include dbserver 必须要给dbserver这个变量传一个值才可以,也不是没传值就不能运行,可以给一个默认值 传了就是你传的值,没有传就时mariadb-server 就不报错,提示mariadb-server安装 过了,但是服务没启动起来 所以对于这种需要传参数的也可以使用include,如果没有默认值,就需要调用的时候传值,就不能使用include这种方式了 ,而是像申明资源一样来申明 把$pkgname当作属性来赋值 所以叫自定义类型 这是第二种方法,需要传参数时使用这种方法 但是依然做不到,不同的操作系统版本传不同的值,就需要使用下面的代码,先判断值是什么 所以有了代码编程功能以后,对应的代码,对于的配置文件,可以写的更有适用性,不能写一个代码只适用于一种场景 puppet的类: 类:puppet中命名的代码模块,常用于定义一组通用目标的资源,可在puppet全局调用; 类可以被继承,也可以包含子类;语法格式: class NAME { ...puppet code... } class NAME(parameter1, parameter2) { ...puppet code... } 类代码只有声明后才会执行,调用方式: (1) include CLASS_NAME1, CLASS_NAME2, ... (2) class{'CLASS_NAME': attribute => value, } 示例1: class apache2 { $webpkg = $operatingsystem ? { /(?i-mx:(centos|redhat|fedora))/ => 'httpd', /(?i-mx:(ubuntu|debian))/ => 'apache2', default => 'httpd', } package{"$webpkg": ensure => installed, } file{'/etc/httpd/conf/httpd.conf': ensure => file, owner => root, group => root, source => '/tmp/httpd.conf', require => Package["$webpkg"], notify => Service['httpd'], } service{'httpd': ensure => running, enable => true, } } include apache2 示例2: class dbserver($pkgname) { package{"$pkgname": ensure => latest, } service{"$pkgname": ensure => running, enable => true, } } #include dbserver if $operatingsystem == "CentOS" { $dbpkg = $operatingsystemmajrelease ? { 7 => 'mariadb-server', default => 'mysqld-server', } } class{'dbserver': pkgname => $dbpkg, }
刚才定义的内容还有问题,如果期望适用于不同的场景,你的nginx,要么做web,要么做7层反代,4层,应该使用不同的配置文件,怎么让它通过类来继承适用于不同的配置
类继承的方式: class SUB_CLASS_NAME inherits PARENT_CLASS_NAME {定义一个类但是叫inherits继承哪个父类 一个子类从哪个父类来继承 …puppet code… } 而后就能实现拥有父类的代码 这个名称是用了完全限定格式来定义,前面是父类,后面是子类 inherites 继承了nginx 可以把刚才的配置文件再进化一版 **定义三个子类,nginx::web inherits 继承自nginx nginx::7proxy 7层代理 inherits 继承自nginx nginx::webproxy inherits 继承自nginx nginx:: mysqlproxy mysql代理 inherits 继承自nginx 这四个子类每一个都天然拥有父类代码 ** 告诉你nginx还没安装需要安装 服务还没启动,需要启动 子类中再加一个资源,自己新增内容 一旦文件发生更改,就需要通知service资源,可以自己在下面重新定义service资源 提示找不到源文件 先手动装上去试试 】 这个原本就是web服务的不用去修改 再次修改名字,名字应该对应起来 在location中加proxy 配置文件没有什么改变,所以没报什么错 这次就提示配置文件不一样了,服务应该重调之类的 假如在第二个子类中,不期望这个service enable =true,从父类继承到子类就是为true,现在想在webproxy中不为true,可以覆盖父类的值,或者在父类中新增属性,可以覆盖父类资源中某个属性值,或者是增加父类的属性 在子类中为父类的资源新增属性或覆盖指定的属性的值: Type[‘title’] { attribute1 => value, … }在子类中为父类的资源的某属性增加新值:
Type[‘title’] { attribute1 +> value, 有些属性可以带多个参数 … } 子类中为父类资源新增属性或覆盖属性,如果修改 1.现在子类中引用父类的资源 其他值不变,只是把enable改成false 可以真正跑一遍,查看对应状态是什么 nginx装上了,配置文件也提供了反代的,当前状态,应该是启用状态 但是当前并不是开机就启动的,为disabled 这就是覆盖父类中指定资源的属性值 换一个依赖关系,服务依赖包,在子类中,这个service不仅依赖package还依赖file,+> nginx。conf,这个+号,代表不是要覆盖前面的,而是要追加,依赖于这个包,还要依赖于这个文件 表示为父类中的某个属性,新增额外的值 不同的服务程序,他们的配置文件有可能不一样(nginx启动进程应该小于等于cpu核心数,但是不同的agent主机可能不一样),workprocess 可以实现auto,但是想要核心数-1,但是不同主机cpu可能不同,所以不可能给固定值放那里,所以这个时候就需要我们的facts变量来获取到指定主机的物理核心数以后,再去做算术运算-1来实现,这个时候配置文件就需要内嵌代码 ruby的内嵌式模板语言叫erb embedded ruby文本文件中内嵌变量替换机制: <%= @VARIABLE_NAME %> @+变量名 %=的方式来进行定义 process count就是cpu核心数
这个文件定义了两个资源,1.包package,ensure =latest file 主配置文件 path 放在哪里 content 直接生产,内容从内建的templete 函数,加载指定路径下的erb模板文件来实现,这个文件内建了代码 会告诉你配置文件不一样了 现在打开配置文件看看 这就叫做模板,对应的代码可以直接写在一个静态的文件中 变量替换就是%= 通常情况下只是一个变量替换,而有些场景中,可能需要做条件判断 each就是迭代变量中的每一个元素,把每一个元素赋值给val变量,内部执行代码,调用val变量 end结束这个循环 puppet模板:erb:模板语言,embedded ruby;puppet兼容的erb语法: https://docs.puppet.com/puppet/latest/reference/lang_template_erb.html file{'title': ensure => file, content => template('/PATH/TO/ERB_FILE'),}文本文件中内嵌变量替换机制: <%= @VARIABLE_NAME %> 示例: class nginx { package{'nginx': ensure => installed, } service{'nginx': ensure => running, enable => true, require => Package['nginx'], } } class nginx::web inherits nginx { file{'ngx-web.conf': path => '/etc/nginx/conf.d/ngx-web.conf', ensure => file, require => Package['nginx'], source => '/root/manifests/nginx/ngx-web.conf', } file{'nginx.conf': path => '/etc/nginx/nginx.conf', ensure => file, content => template('/root/manifests/nginx.conf.erb'), require => Package['nginx'], } Service['nginx'] { subscribe => [ File['ngx-web.conf'], File['nginx.conf'] ], } } include nginx::web
有了模板就可以按照需要生成配置文件
在模块当中,关键就是定义类,自包含的定义的代码结构 ansible定义role任务,
最好把每一组资源文件所依赖的文件都放在一个独立的目录下。将来运行就放在一个目录下运行 模块有特定的放的位置,转载地址:http://ldkgn.baihongyu.com/