自動化運維工具——puppet詳解(二)

1、class 類

1)什麼是類?

  類是puppet中命名的代碼模塊,經常使用於定義一組通用目標的資源,可在puppet全局調用;
  類能夠被繼承,也能夠包含子類;
  具體定義的語法以下:html

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

  其中,在咱們定義的時候,須要注意的是:node

  • 類的名稱只能以小寫字母開頭,能夠包含小字字母、數字和下劃線。
  • 每一個類都會引入一個新的變量scope ,這意味着在任什麼時候候訪問類中的變量時,都得使用其徹底限定名稱。
    • 不過,在本地 scope 能夠從新爲 top scope 中的變量賦予一個新值。

  下面,咱們來看一個簡單的例子:mysql

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後能夠跟多個類,直接用","隔開便可。redis

2)帶有參數的類

  咱們定義的類也能夠進行參數設置,能夠進行參數的傳遞。
  具體語法以下所示:sql

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

  咱們來看一個例子:編程

vim class2.pp
	class instpkg($pkg) {
		package{"$pkg":
			ensure  => installed,
		}
	}

	class{"instpkg":			#給參數傳入值
		pkg     => 'memcached',
	}

  注意:單個主機上不能被直接聲明兩次
  若是對應的參數未傳值的話,執行會報錯。
  可是咱們能夠在定義形參的時候,設定一個默認值,這樣的話,咱們不傳入值的話,就會自動調用默認值:vim

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 能夠被繼承,也能夠包含子類。
  其定義的語法以下:app

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.總體調用父類,並重寫部分值

  在繼承的類中,咱們還能夠在總體調用的基礎上,根據不一樣的需求,把父類中的部分值進行重寫修改:

總體調用父類,並重寫部分值

總體調用父類,並重寫部分值

2、模板

  模板一般以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
監聽端口

監聽端口

  能夠看出,咱們的變量替換已經成功。

3、模塊

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 模式下進行,步驟還會略有不一樣。

4、master/agent 模型

  master/agent模型時經過主機名進行通訊的,下面,就來看看 master-agent 模式的puppet運維自動化如何實現:

實現步驟

一、實現前準備

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

puppet包查詢

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命令來查看時間源:

查看時間源

查看時間源

二、開啓 master 端的 puppet 服務

1)手動前臺開啓,觀察服務開啓過程:

puppet master -v --no-daemonize		#前臺運行

 

master 初始化過程

  整個過程都是自動完成的,其中,每一步的意思以下:
  ① 建立key 給CA
  ② 建立一個請求給CA
  ③ 自簽名證書
  ④ CA 建立完成
  ⑤ 建立證書吊銷列表
  ⑥ 爲當前的master 主機簽署證書
  ⑦ master 的證書籤署完成

 

2)直接systemctl開啓服務,監聽在8140端口。

開啓服務

開啓服務

三、在 agent 端開啓服務

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

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

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服務

開啓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端服務

開啓agent端服務

 

  能夠看出咱們的服務開啓成功,可是因爲master 端沒有配置站點清單,因此沒有什麼動做。

四、配置站點清單,且測試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

enter description here

(4)直接開啓服務,agent 會自動去master 端獲取配置
[root@server1 ~]# systemctl start puppetagent 包已下載,服務也開啓了

enter description here

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包查詢

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 頒發證書

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

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    #用於測試實驗結果
enter description here

添加一行
[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模塊列表

查看puppet模塊列表

 

七、再配置站點清單

[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
	#}

八、測試

  咱們如今直接去server2機器上,查看咱們的配置文件是否已經生效,是不是咱們添加過一行的內容:

[root@server2 ~]# vim /etc/chrony.conf
enter description here

server2上的內容

  發現咱們的實驗成功。

相關文章
相關標籤/搜索