1. playbook基本語(yǔ)法
Ansible的playbook文件格式為YAML語(yǔ)法彤灶,所以對(duì)于編寫劇本的初學(xué)者,建議先對(duì)YAML語(yǔ)法結(jié)構(gòu)有一定的了解批旺,否則在運(yùn)行playbook的時(shí)候會(huì)經(jīng)常碰到語(yǔ)法錯(cuò)誤幌陕。關(guān)于YAML的語(yǔ)法的詳細(xì)介紹信息可以通過(guò)https://yaml.org/spec/1.2/spec.html網(wǎng)站進(jìn)行了解。
安裝部署Nginx服務(wù)的劇本編寫案例:
[root@m01 ~]# cat nginx.yaml
---
- hosts: all
tasks:
- name: Install Nginx Package
yum: name=nginx state=present
- nane: Copy Nginx.conf
copy: src=./nginx.conf dest=/etc/nginx/nginx.conf mode=0644
對(duì)于以上playbook劇本代碼信息汽煮,這里進(jìn)行簡(jiǎn)單說(shuō)明解釋:
- 第1行表示該文件注釋說(shuō)明搏熄,YAML文件中通常使用三個(gè)短橫線表示注釋,也可以使用#暇赤。
- 第2行定義該playbook劇本管理的目標(biāo)主機(jī)心例,all表示針對(duì)所有的主機(jī),這個(gè)位置定義支持Ansible Ad-Hoc模式的所有參數(shù)鞋囊。
- 第3行定義該playbook所有的任務(wù)集合信息止后,比如次劇本代碼中定義了兩個(gè)任務(wù)。
- 第4行定義一個(gè)任務(wù)的名稱溜腐,非必須译株,建議根據(jù)實(shí)際任務(wù)命名。
- 第5行定義一個(gè)任務(wù)的具體操作動(dòng)作挺益,比如這里使用yum實(shí)現(xiàn)nginx軟件包的安裝歉糜。
- 第6到7行表示使用copy模塊,將本地的nginx配置文件推送分發(fā)給其他所有被管理的主機(jī)望众,并且修改設(shè)置文件權(quán)限為644匪补。
編寫劇本主要需要注意兩點(diǎn)規(guī)范:第一就是劇本內(nèi)容組成規(guī)范;第二就是劇本編寫語(yǔ)法規(guī)范烂翰。
1.1 playbook內(nèi)容組成規(guī)范
Ansible的playbook由最基本的兩個(gè)部分組成——hosts定義劇本所管理的主機(jī)信息夯缺,tasks定義所管理的主機(jī)需要執(zhí)行的任務(wù)信息。
定義劇本的host部分可以有多種方式甘耿,常見的方式有以下幾種:
方式一:定義所管理的主機(jī)IP地址
- hosts: 192.168.9.5
tasks:
---- 任務(wù)內(nèi)容先省略 ----
方式二:定義所管理的主機(jī)名稱信息
- hosts: backup_host
tasks:
---- 任務(wù)內(nèi)容先省略 ----
方式三:定義所管理的主機(jī)組信息
- hosts: rsync_server
tasks:
---- 任務(wù)內(nèi)容先省略 ----
- hosts: rsync_client
tasks:
---- 任務(wù)內(nèi)容先省略 ----
方式四:定義所管理的多個(gè)主機(jī)信息
- hosts: 192.168.9.5, backup_host
tasks:
---- 任務(wù)內(nèi)容先省略 ----
方式五:定義所管理所有主機(jī)信息
- hosts: all
tasks:
---- 任務(wù)內(nèi)容先省略 ----
企業(yè)可根據(jù)自身需求踊兜,對(duì)以上常用方式進(jìn)行自行擴(kuò)展。以上定義劇本所管理的主機(jī)信息的幾種方法有一個(gè)最重要的前提棵里,即所管理的主機(jī)在Ansible主機(jī)清單文件中必須有相應(yīng)定義润文,即默認(rèn)/etc/ansible/hosts文件中必須有定義,否則劇本將不能直接管理相應(yīng)主機(jī)殿怜。
定義劇本的tasks部分也可以有多種方式典蝌,常見的方式有以下幾種:
方式一:采用變量格式設(shè)置任務(wù)信息
tasks:
- name: make sure apache is running
service: name=httpd state=running
當(dāng)需要傳入的參數(shù)列表過(guò)長(zhǎng)時(shí),可以將其分隔到多行
tasks:
- name: copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
方式二:采用字典格式設(shè)置任務(wù)信息
tasks:
- name: copy ansible inventory file to client
copy:
src: /etc/ansible/hosts
dest: /etc/ansible/hosts
owner: root
group: root
mode: 0644
1.2 playbook編寫語(yǔ)法規(guī)范
(1)注意劇本編寫縮進(jìn)規(guī)范
在編寫劇本時(shí)头谜,需要注意不同行信息之間有時(shí)需要有縮進(jìn)關(guān)系骏掀,一般將兩個(gè)空格作為一個(gè)縮進(jìn)。
- hosts: oldboy
task:
- name: exec scripts
script: /server/scripts/oldboy.sh
(2)主機(jī)劇本編寫字典規(guī)范
在編寫劇本時(shí)柱告,有時(shí)需要定義變量信息或設(shè)置模塊參數(shù)的配置信息截驮,可以采用字典格式進(jìn)行設(shè)置,字典配置信息格式為:
key: value
key和value之間用冒號(hào)加空格進(jìn)行分割
具體編寫的劇本樣例:
- hosts: oldboy
tasks:
- name: create file
file:
path: /oldboy/oldboy.txt
state: directory
mode: 644
owner: oldboy
group: oldboy
(3)主機(jī)劇本編寫列表規(guī)范
在編寫劇本時(shí)际度,劇本中定義的有些信息可能會(huì)重復(fù)出現(xiàn)葵袭,并且縮進(jìn)關(guān)系一致,以及他們表達(dá)的意思也比較相近乖菱,這樣不同行的信息就構(gòu)成了列表坡锡,列表信息格式為:
- list01
- list02
- list03
短橫線和列表信息中間有空格
2. playbook執(zhí)行方式
劇本編寫完成之后,需要進(jìn)行運(yùn)行窒所,才能完成劇本的主機(jī)管理功能鹉勒。在Ansible程序中,加載使用模塊信息時(shí)吵取,可以使用Ansible命令禽额,加載執(zhí)行劇本文件時(shí),可以使用ansible-playbook命令皮官。
ansible-playbook oldboy.yml
說(shuō)明:可以使用相對(duì)路徑加載劇本文件脯倒,也可以使用絕對(duì)路徑加載劇本文件。
查看劇本執(zhí)行時(shí)輸出的詳細(xì)信息:
ansible-playbook oldboy.yml --verbose
查看劇本執(zhí)行時(shí)會(huì)影響哪些主機(jī)信息:
ansible-playbook oldboy.yml --list-hosts
執(zhí)行playbook時(shí)指定加載的主機(jī)清單文件:
ansible-playbook oldboy.yml -i /etc/ansible/hosts
執(zhí)行playbook時(shí)檢查劇本語(yǔ)法是否正確:
ansible-playbook oldboy.yml --syntax-check
執(zhí)行playbook時(shí)只是模擬執(zhí)行臣疑,不會(huì)影響主機(jī)的配置:
ansible-playbook oldboy.yml -c
3. playbook的輸出
劇本在執(zhí)行過(guò)程中盔憨,會(huì)產(chǎn)生相應(yīng)輸出,根據(jù)輸出的信息可以掌握劇本是否完整執(zhí)行讯沈、每個(gè)執(zhí)行過(guò)程是否正確郁岩,以及根據(jù)輸出的錯(cuò)誤提示信息,可以排查劇本編寫中的邏輯問(wèn)題缺狠。
劇本在執(zhí)行時(shí)问慎,任務(wù)中的每個(gè)Action會(huì)調(diào)用一個(gè)模塊,然后在模塊中檢查當(dāng)前系統(tǒng)狀態(tài)并決定是否需要重新執(zhí)行挤茄。
- 如果本地執(zhí)行了如叼,那么Action會(huì)得到返回值changed。
- 如果不需要執(zhí)行穷劈,那么Action會(huì)得到返回值ok笼恰。
模塊的執(zhí)行狀態(tài)的具體判斷規(guī)則由各個(gè)模塊自己決定和實(shí)現(xiàn)踊沸。例如,copy模塊的判斷方法是比較文件的checksum社证,copy模塊的代碼如下:
checksum_src = module.sha1(src)
...
checksum_dest = module.sha1(dest)
...
if checksum_src != checksum_dest or os.path.islink(b_dest):
...
changed = True
else:
changed = False
下面以一個(gè)copy文件的任務(wù)為例逼龟,展示在執(zhí)行任務(wù)狀態(tài)到底有什么不同的行為:
- hosts: oldboy
tasks:
- name: copy the /etc/hosts
copy: src=/etc/hosts dest=/etc/hosts
第一次執(zhí)行,執(zhí)行結(jié)果如下所示:
[root@m01 ~]# ansible-playbook copy_hosts.yaml
PLAY [oldboy] **************************************************************************
TASK [Gathering Facts] *****************************************************************
ok: [192.168.9.6]
ok: [192.168.9.5]
TASK [copy the /etc/hosts] *************************************************************
changed: [192.168.9.5]
changed: [192.168.9.6]
PLAY RECAP *****************************************************************************
192.168.9.5 : ok=2 changed=1 unreachable=0 failed=0
192.168.9.6 : ok=2 changed=1 unreachable=0 failed=0
第二次執(zhí)行追葡,執(zhí)行結(jié)果如下所示:
[root@m01 ~]# ansible-playbook copy_hosts.yaml
PLAY [oldboy] **************************************************************************
TASK [Gathering Facts] *****************************************************************
ok: [192.168.9.6]
ok: [192.168.9.5]
TASK [copy the /etc/hosts] *************************************************************
ok: [192.168.9.6]
ok: [192.168.9.5]
PLAY RECAP *****************************************************************************
192.168.9.5 : ok=2 changed=0 unreachable=0 failed=0
192.168.9.6 : ok=2 changed=0 unreachable=0 failed=0
由于第一次執(zhí)行copy_hosts.yaml時(shí)腺律,已經(jīng)復(fù)制過(guò)文件,因此Ansible會(huì)根據(jù)文件的狀態(tài)避免重復(fù)復(fù)制宜肉。
接著更改192.168.9.5主機(jī)的/etc/hosts再執(zhí)行匀钧,發(fā)現(xiàn)只有192.168.9.5的主機(jī)狀態(tài)是changed,另外一臺(tái)遠(yuǎn)程主機(jī)的狀態(tài)是ok:
[root@m01 ~]# ansible-playbook copy_hosts.yaml
PLAY [oldboy] **************************************************************************
TASK [Gathering Facts] *****************************************************************
ok: [192.168.9.6]
ok: [192.168.9.5]
TASK [copy the /etc/hosts] *************************************************************
ok: [192.168.9.6]
changed: [192.168.9.5]
PLAY RECAP *****************************************************************************
192.168.9.5 : ok=2 changed=1 unreachable=0 failed=0
192.168.9.6 : ok=2 changed=0 unreachable=0 failed=0
通過(guò)以上執(zhí)行劇本輸出的信息谬返,可以將劇本執(zhí)行過(guò)程輸出的信息總結(jié)為三個(gè)部分之斯,具體說(shuō)明參見下表。
4. playbook擴(kuò)展配置
4.1 playbook設(shè)置變量功能
在劇本中可以通過(guò)設(shè)置變量信息遣铝,實(shí)現(xiàn)相應(yīng)參數(shù)的配置功能吊圾,在某些場(chǎng)景下,可以簡(jiǎn)化對(duì)劇本的修改調(diào)整翰蠢。在playbook中项乒,常用的幾種變量設(shè)置方法如下:
1)在playbook中用戶自定義的變量。
2)用戶無(wú)須定義梁沧,Ansible會(huì)在執(zhí)行playbook之前去管理主機(jī)上收集關(guān)于遠(yuǎn)程主機(jī)系統(tǒng)的信息的變量檀何。
3)在文件模板中,可以直接使用上述兩種變量廷支。
4)把任務(wù)的運(yùn)行結(jié)果作為一個(gè)變量來(lái)使用频鉴,這個(gè)叫作注冊(cè)變量。
5)為了使playbook更靈活恋拍,通用性更強(qiáng)垛孔,允許用戶在執(zhí)行playbook時(shí)傳入變量的值,這個(gè)時(shí)候就需要用到額外變量施敢。
(1)在playbook中用戶自定義的變量
用戶可以在playbook中周荐,通過(guò)vars關(guān)鍵字自定義變量,之后再用{{}}調(diào)用即可僵娃。
- playbook中定義和變量的方法
例如:下面的例子中概作,用戶定義變量為http_port,其值為80默怨。在tasks下的firewalld中讯榕,可通過(guò){{ http_port }}調(diào)用該變量。
- hosts: web
vars:
http_port: 80
remote_user: root
tasks:
- name: insert firewalld rule for httpd
firewalld: port={{ http_port }}/tcp permanent=true state=enabled imme-diate=yes
- 將變量配置在單獨(dú)文件中
當(dāng)變量較多的時(shí)候,或者變量需要在多個(gè)playbook中重用的時(shí)候愚屁,可以把變量放到一個(gè)單獨(dú)的文件中济竹,之后通過(guò)關(guān)鍵字“var_files”可將該變量引用到playbook中。使用變量的方法和在文件中定義變量的方法相同:
- hosts: web
vars_files:
- vars/server_vars.yml
remote_user: root
tasks:
- name: insert firewalld rule for httpd
firewalld: port={{ http_port }}/tcp permanent=true state=enabled imme-diate=yes
變量文件/vars/server_vars.yml的內(nèi)容為:
http_port: 80
- 定義和使用復(fù)雜的變量
在某些場(chǎng)景中需要使用的變量的值不是簡(jiǎn)單的字符串或者數(shù)字霎槐,而是一個(gè)對(duì)象规辱。對(duì)象的定義語(yǔ)法如下,格式為YAML的字典格式:
foo:
field1: one
field2: two
訪問(wèn)復(fù)雜變量中的子屬性栽燕,可以利用中括號(hào)或者點(diǎn)號(hào):
foo['field1']
foo.field1
(2)遠(yuǎn)程主機(jī)的系統(tǒng)變量(Facts)
Ansible會(huì)通過(guò)模塊“setup”來(lái)搜集主機(jī)的系統(tǒng)信息,這些搜集到的系統(tǒng)信息稱為Facts改淑。每個(gè)playbook在執(zhí)行前都會(huì)默認(rèn)執(zhí)行setup模塊碍岔,所以這些Facts信息可以直接以變量的形式使用。
可以通過(guò)在命令行中調(diào)用setup模塊命令朵夏,查看所有可以調(diào)用的Facts變量信息:
ansible all -m setup -u root
在劇本中調(diào)用收集到的Facts變量信息:
- hosts: all
user: root
tasks:
- name: print system info
debug: msg={{ ansible_os_family }}
- name: install git on Debian linux
apt: name=git state=installed
when: ansible_os_family == "Debian"
- name: install git on RedHat linux
yum: name=git state=installed
when: ansible_os_family == "RedHat"
- 使用復(fù)雜的Facts變量
一般在系統(tǒng)中搜集到如下信息時(shí)蔼啦,復(fù)雜的、多層級(jí)的Facts變量是如何進(jìn)行調(diào)取的呢仰猖?
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "10.0.0.200",
"broadcast": "10.0.0.255",
"netmask": "255.255.255.0",
"network": "10.0.0.0"
},
}
...
可以通過(guò)下面的兩種方式訪問(wèn)復(fù)雜變量中的子屬性:
- 中括號(hào)調(diào)用
{{ ansible_eth0["ipv4"]["address"] }}
- 點(diǎn)號(hào)調(diào)用
{{ ansible_eth0.ipv4.address }}
- 關(guān)閉Facts
搜集Facts信息會(huì)消耗額外的時(shí)間捏肢,如果不需要Facts信息,則可以在playbook中饥侵,通過(guò)關(guān)鍵字gather_facts來(lái)控制是否搜集遠(yuǎn)程系統(tǒng)的信息鸵赫。如果不搜集系統(tǒng)信息,那么上面的Facts變量就不能在該playbook中使用了:
- hosts: oldboy
gather_facts: no
通過(guò)setup模塊搜集主機(jī)信息時(shí)躏升,會(huì)發(fā)現(xiàn)很多可以作為劇本的facts變量信息辩棒,以下為企業(yè)中常用的Facts變量信息說(shuō)明。
(3)文件模板中使用的變量
template模塊在Ansible中十分常用膨疏,而它在使用中并沒(méi)有顯式地指定template文件中的值一睁,所以有時(shí)候用戶會(huì)對(duì)template文件中的變量感到困惑,所以這里強(qiáng)調(diào)以下它的變量的使用佃却。
- template中變量的定義
在playbook中定義的變量者吁,可以直接在template中使用,同時(shí)Facts變量可以直接在template中使用饲帅,當(dāng)然在Inventory中定義的Hosts和Group變量也是如此复凳。所有在playbook中可以訪問(wèn)的變量,都可以在template文件中使用灶泵。
下面的playbook腳本中使用了template模塊來(lái)復(fù)制文件index.html.j2染坯,并且替換index.html.j2中的變量為playbook中定義的變量值。
- hosts: web
vars:
http_port: 80
defined_name: "Hello My name is oldboy"
remote_user: root
tasks:
- name: write the default index.html file
template: src=templates/index.html.j2 dest=/var/www/html/index.html
- template中變量的使用
在上面的劇本舉例中丘逸,index.html.j2模板文件直接使用了以下變量信息:
系統(tǒng)定義變量:{{ ansible_hostname }} {{ ansible_default_ipv4.address }}
用戶定義變量:{{ defined_name }}
index.html.j2文件的內(nèi)容如下:
<html>
<title>Demo</title>
<boby>
<div class="""block" style="height: 99%;">
<div class="centered">
<h1>#46 Demo {{ defined_name }}</h1>
<p>Served by {{ ansible_hostname }} {{{ ansible_default_ipv4.address }}}.</p>
</div>
</div>
</body>
</html>
(4)運(yùn)行結(jié)果注冊(cè)變量
把任務(wù)的執(zhí)行結(jié)果當(dāng)作一個(gè)變量的值也是可以的单鹿。這個(gè)時(shí)候就需要用到“注冊(cè)變量”,即把執(zhí)行結(jié)果注冊(cè)到一個(gè)變量中深纲,待后面的任務(wù)使用仲锄。把執(zhí)行結(jié)果注冊(cè)到變量中的關(guān)鍵字時(shí)register劲妙,使用方法如下:
- hosts: web
tasks:
- shell: ls
register: result
ignore_errors: True
- shell: echo "{{ result.stdout }}"
when: result.rc == 5
- debug: msg=""{{ result.stdout }}
注冊(cè)變量經(jīng)常和debug模塊一起使用,這樣可以得到更多的關(guān)于執(zhí)行錯(cuò)誤的信息儒喊,以幫助用戶調(diào)試劇本內(nèi)容镣奋。
(5)用命令行傳遞變量信息
為了使playbook更靈活,通用性更強(qiáng)怀愧,允許用戶在執(zhí)行的時(shí)候傳入指定變量的值侨颈,此時(shí)就需要用到“額外變量”。
- 定義命令變量
在oldboy.yml文件中芯义,hosts和user都定義為變量哈垢,它們需要從命令行傳遞變量值。如果在命令行中不傳入值扛拨,那么執(zhí)行playbook是會(huì)報(bào)錯(cuò)的:
- hosts: '{{ hosts }}'
remote_user: '{{ user }}'
tasks:
- ...
當(dāng)然也可以直接在playbook中定義變量信息耘分。例如下面的劇本,如果在命令行中傳入新的值绑警,那么會(huì)覆蓋playbook中的值求泰,未在命令行中的傳入值也不會(huì)報(bào)錯(cuò):
- hosts: localhost
remote_user: root
vars:
test_name: "Value in playbook file"
tasks:
- debug: msg=""{{ test_name }}"
- 使用命令行變量
ansible-playbook oldboy.yml --extra-vars "hosts=web user=root"
還可以用JSON格式傳遞參數(shù):
ansible-playbook oldboy.yml --extra-vars "{'hosts':'web', 'user':'root'}"
4.2 playbook邏輯控制語(yǔ)句
在playbook中也可以設(shè)置一些邏輯控制語(yǔ)句(類似于Shell腳本中的邏輯語(yǔ)句信息),使劇本配置方式更加靈活多樣计盒,在劇本中常用的邏輯語(yǔ)句的參數(shù)如下:
- when:條件判斷語(yǔ)句渴频,類似編程語(yǔ)言中的if。
- loop:循環(huán)語(yǔ)句北启,類似編程語(yǔ)言中while枉氮。
- block:把幾個(gè)任務(wù)組成一個(gè)代碼塊,以便針對(duì)一組操作的異常進(jìn)行處理暖庄。
(1)條件判斷語(yǔ)句when
- when的基本用法
有時(shí)候很可能需滿足特定條件才執(zhí)行某一個(gè)特定的步驟聊替,例如在某一個(gè)特定版本的系統(tǒng)中安裝軟件包,或者只在磁盤空間不足的文件系統(tǒng)上執(zhí)行清理操作培廓。這些操作在playbook中用when語(yǔ)句實(shí)現(xiàn)惹悄。
若遠(yuǎn)程主機(jī)為Debian Linux系統(tǒng),則立刻關(guān)閉主機(jī)系統(tǒng):
tasks:
- name: "shutdown Debian system"
command: /sbin/shutdown -t now
when: ansible_os_family == "Debian"
進(jìn)行判斷的方式有多種肩钠。
1)簡(jiǎn)單方式:
command: echo oldboy
when: ansible_os_family == "centos"
說(shuō)明:當(dāng)指定條件滿足時(shí)泣港,執(zhí)行模塊動(dòng)作
2)取反方式:
command: echo oldboy
when: ansible_os_family != "centos"
說(shuō)明:當(dāng)指定條件不滿足時(shí),執(zhí)行模塊動(dòng)作
3)多個(gè)條件:
command: echo oldboy
when: ansible_os_family == " centos" and ansible_hosts == "web01"
說(shuō)明:當(dāng)多個(gè)條件同時(shí)滿足時(shí)价匠,執(zhí)行模塊動(dòng)作
command: echo oldboy
when: ansible_os_family == "centos" or ansible_hosts == "web01"
說(shuō)明:當(dāng)多個(gè)條件其中之一滿足時(shí)当纱,執(zhí)行模塊動(dòng)作
(2)邏輯循環(huán)語(yǔ)句loop
- 標(biāo)準(zhǔn)循環(huán)
為了保持簡(jiǎn)潔,重復(fù)的任務(wù)可以用以下簡(jiǎn)寫方式:
- name: add server users
user: name={{ item }} state=present group=oldboy
with_item:
- testuser1
- testuser2
如果在變量文件中或者“vars”區(qū)域定義了一組列表變量somelist踩窖,也可以進(jìn)行如下配置:
vars:
somelist: ["testuser1", "testuser2"]
tasks:
- name: add server user
user: name={{ item }} state=present groups=oldboy
with_items: "{{ somelist }}"
“with_item”用于迭代的list類型變量坡氯,不僅支持簡(jiǎn)單的字符串列表,也可以支持哈希列表,那么可以用以下方式來(lái)引用子項(xiàng):
- name: add server user
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'test1' }
- { name: 'testuser2', groups: 'test2' }
注意:如果同時(shí)使用when和with_items箫柳,那么when聲明會(huì)針對(duì)每個(gè)條目單獨(dú)判斷一次手形。
- 嵌套循環(huán)
循環(huán)也可以嵌套,用[]訪問(wèn)內(nèi)存和外層的循環(huán):
- name: give users access to multiple databases
mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
with_nested:
- [ 'alice', 'bob' ]
- [ 'clientdb', 'employeedb', 'providerd' ]
或者用點(diǎn)號(hào)(.)訪問(wèn)內(nèi)存和外層的變量:
- name: give users access to multiple databases
mysql_user: name={{ item.0 }} priv={{ item.1 }}.*:ALL append_privs=yes password=foo
with_nested:
- [ 'alice', 'bob' ]
- [ 'clientdb', 'employeedb', 'providerd' ]
4.3 playbook調(diào)試功能配置
編寫劇本時(shí)悯恍,可以加入一些調(diào)試功能库糠,以便在劇本執(zhí)行報(bào)錯(cuò)時(shí)進(jìn)行調(diào)試修改,常用的調(diào)試功能有以下幾種:
- ignore_errors:忽略劇本執(zhí)行過(guò)程中的報(bào)錯(cuò)信息涮毫。
- tags:給劇本打標(biāo)簽瞬欧。
(1)劇本執(zhí)行錯(cuò)誤忽略功能
在執(zhí)行劇本時(shí),由于Ansible具有串行執(zhí)行特性罢防,即一個(gè)任務(wù)執(zhí)行成功艘虎,才會(huì)執(zhí)行下一個(gè)任務(wù),如果一個(gè)劇本中的某任務(wù)執(zhí)行失敗了篙梢,就會(huì)停止劇本的執(zhí)行。在引入劇本執(zhí)行報(bào)錯(cuò)忽略功能后美旧,可以先忽略有些可能有錯(cuò)誤的任務(wù)渤滞,確保劇本中的其他任務(wù)執(zhí)行完畢,之后再研究出現(xiàn)錯(cuò)誤的任務(wù)榴嗅。
實(shí)現(xiàn)忽略錯(cuò)誤的劇本信息為:
tasks:
- name: install software
shell: yum install -y rsync
- name: create user
shell: useradd oldboy
ignore_errors: yes
- name: boot server
shell: systemctl start rsyncd
(2)劇本標(biāo)簽功能
在某些場(chǎng)景中編寫劇本任務(wù)的步驟會(huì)非常煩瑣復(fù)雜妄呕,在進(jìn)行測(cè)試時(shí),某一個(gè)任務(wù)很可能出現(xiàn)問(wèn)題嗽测,從而需要對(duì)劇本進(jìn)行調(diào)試绪励,而劇本調(diào)試完畢后,重新測(cè)試時(shí)唠粥,又會(huì)反復(fù)執(zhí)行已經(jīng)成功執(zhí)行的任務(wù)疏魏,影響劇本的調(diào)試效率。實(shí)際上晤愧,可以利用劇本標(biāo)簽功能只執(zhí)行某個(gè)劇本任務(wù)大莫。
添加標(biāo)簽功能的劇本信息如下:
tasks:
- name: create file info
file: path:/tmp/this_is_{{ ansible_hostname }}_file state=touch
when: (ansible_hostname == "nfs01") or (ansible_hostname == "backup")
tags: t1
- name: install httpd
yum: name=httpd state=installed
when: (ansible_all_ipv4_addresses == ["192.168.9.5","192.168.9.6"])
tags: t2
以上劇本包含了兩個(gè)任務(wù)信息,分別對(duì)它們做了標(biāo)記官份,可以利用Ansible執(zhí)行劇本的命令參數(shù)只厘,以進(jìn)行如下操作。
執(zhí)行指定標(biāo)簽任務(wù)的命令:
ansible-playbook test_tags.yml -t t1
跳過(guò)指定標(biāo)簽任務(wù)的命令:
ansible-playbook test_tags.yml --skip-tags t2
4.4 playbook觸發(fā)功能
(1)什么是劇本觸發(fā)功能(handlers)
每個(gè)主流的編程語(yǔ)言都有Event機(jī)制舅巷,而handlers就是playbook的Event羔味。
handlers里面的每一個(gè)觸發(fā)器信息都是對(duì)模塊的一次調(diào)用。而handlers與任務(wù)不同钠右,任務(wù)會(huì)默認(rèn)地按照定義順序執(zhí)行赋元,而handlers則不會(huì),它需要在任務(wù)中調(diào)用,才有可能得到執(zhí)行们陆。
任務(wù)表中的任務(wù)都是有狀態(tài)的:changed或者ok寒瓦。在Ansible中,只有在任務(wù)的執(zhí)行狀態(tài)為changed時(shí)坪仇,才會(huì)執(zhí)行該任務(wù)調(diào)用的handler杂腰。這也是handler與普通的Event機(jī)制不同的地方。
(2)劇本觸發(fā)功能應(yīng)用場(chǎng)景
如果在任務(wù)中修改了Apache的配置文件椅文,那么需要重啟Apache喂很。如果還安裝了Apache的插件,那么還需要重啟Apache皆刺。像這樣的應(yīng)用場(chǎng)景少辣,重啟Apache就可以設(shè)計(jì)成一個(gè)handler。
一個(gè)handler最多只執(zhí)行一次羡蛾,并且是在所有的任務(wù)都執(zhí)行完之后再執(zhí)行漓帅。如果有多個(gè)任務(wù)調(diào)用(notify)同一個(gè)handler,那么只執(zhí)行一次痴怨。
在下面的例子中Apache重啟只執(zhí)行一次:
- hosts: lb
remote_user: root
vars:
random_number1: "{{ 10000| random }}"
random_number2: "{{ 10000000| random }}"
tasks:
- name: copy the /etc/hosts to /tmp/hosts.{{ random_number1 }}
copy: src=/etc/hosts dest=/tmp/hosts.{{ random_number1 }}
notify:
- call in every action
- name: copy the /etc/hosts to /tmp/hosts.{{ random_number2 }}
copy: src=/etc/hosts dest=/tmp/hosts.{{ random_number2 }}
notify:
- call in every action
handlers:
- name: call in every action
debug: msg=""call in every action, but execute only one time"
只有是changed狀態(tài)的任務(wù)才會(huì)觸發(fā)handler的執(zhí)行忙干。
下面的劇本執(zhí)行了兩次,執(zhí)行結(jié)果是不同的浪藻。
- 第一次執(zhí)行時(shí):
任務(wù)的狀態(tài)都是changed捐迫,會(huì)觸發(fā)兩次handler。 - 第二次執(zhí)行時(shí):
第一個(gè)任務(wù)的狀態(tài)是ok爱葵,因而不會(huì)觸發(fā)handlers “call by /tmp/hosts”施戴;
第二個(gè)任務(wù)的狀態(tài)是changed,觸發(fā)了handler “call by /tmp/hosts random_number”萌丈。
測(cè)試代碼如下:
- hosts: lb
remote_user: root
vars:
random_number: "{{ 10000| random }}"
tasks:
- name: copy the /etc/hosts to /tmp/hosts
copy: src=/etc/hosts dest=/tmp/hosts
notify:
- call by /tmp/hosts
- name: copy the /etc/hosts to /tmp/hosts.{{ random_number }}
copy: src=/etc/hosts dest=/tmp/hosts.{{ random_number }}
notify:
- call by /tmp/hosts.random_number
handlers:
- name: call by /tmp/hosts
debug: msg=""call first time"
- name: call by /tmp/hosts.random_number
debug: msg=""call by /tmp/hosts.random_number"
(3)按定義的順序執(zhí)行觸發(fā)功能
handler是按照定義的順序執(zhí)行的赞哗,而不是按照所安裝的任務(wù)中調(diào)用的順序執(zhí)行的。下面的例子定義的順序是1>2>3辆雾,調(diào)用的順序是3>2>1懈玻,實(shí)際執(zhí)行順序是1>2>3。
- hosts: lb
remote_user: root
gather_facts: no
vars:
random_number1: "{{ 10000| random }}"
random_number2: "{{ 10000000| random }}"
tasks:
- name: copy the /etc/hosts to /tmp/hosts.{{ random_number1 }}
copy: src=/etc/hosts dest=/tmp/hosts.{{ random_number1 }}
notify:
- define the 3nd handler
- name: copy the /etc/hosts to /tmp/hosts.{{ random_number2 }}
copy: src=/etc/hosts dest=/tmp/hosts.{{ random_number2 }}
notify:
- define the 2nd handler
- define the 1nd handler
handlers:
- name: define the 1nd handler
debug: msg""" define the 1nd handler""
- name: define the 2nd handler
debug: msg""" define the 2nd handler""
- name: define the 3nd handler
debug: msg""" define the 3nd handler""
4.5 playbook整合
在編寫多個(gè)劇本信息時(shí)乾颁,有時(shí)會(huì)實(shí)現(xiàn)自動(dòng)化批量管理涂乌,需要執(zhí)行多個(gè)劇本,這時(shí)可以將需要執(zhí)行的多個(gè)劇本的信息進(jìn)行整合英岭,省去利用ansible-playbook命令逐個(gè)加載執(zhí)行劇本的低效工作湾盒。實(shí)現(xiàn)劇本整合的方式常見的有兩種。
1. 只定義單個(gè)劇本任務(wù)信息
在整合多個(gè)劇本信息時(shí)诅妹,可以只在每個(gè)劇本中定義具體的任務(wù)信息罚勾,而無(wú)須定義hosts管理的主機(jī)信息毅人,在匯總劇本中靈活調(diào)用整合多個(gè)劇本,并定義需要執(zhí)行任務(wù)的hosts主機(jī)信息尖殃,具體的劇本配置信息如下:
- hosts: all
remote_user: root
tasks:
- include_tasks: f1.yml
- include_tasks: f2.yml
2. 直接將編寫好的劇本進(jìn)行整合
在整合劇本信息時(shí)丈莺,比較簡(jiǎn)單的方式就是找到相應(yīng)劇本,直接利用import_playbook參數(shù)進(jìn)行整合送丰,在執(zhí)行時(shí)會(huì)按照整合加載的順序缔俄,執(zhí)行每一個(gè)劇本,具體劇本配置信息如下:
- import_playbook: base.yml
- import_playbook: rsync.yml
- import_playbook: nfs.yml