2020-03-20 Ansible最核心的組件playbook

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ù)信息。

Ansible playbook組成部分示意圖

定義劇本的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ō)明參見下表。

劇本執(zhí)行過(guò)程輸出的信息

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ō)明。

企業(yè)常用的Facts變量信息

(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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末器躏,一起剝皮案震驚了整個(gè)濱河市俐载,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌登失,老刑警劉巖遏佣,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異揽浙,居然都是意外死亡状婶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門馅巷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)膛虫,“玉大人,你說(shuō)我怎么就攤上這事令杈∽叩校” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)烤蜕。 經(jīng)常有香客問(wèn)我名段,道長(zhǎng),這世上最難降的妖魔是什么另假? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上纲刀,老公的妹妹穿的比我還像新娘。我一直安慰自己担平,他們只是感情好示绊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著暂论,像睡著了一般面褐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上取胎,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天展哭,我揣著相機(jī)與錄音湃窍,去河邊找鬼。 笑死匪傍,一個(gè)胖子當(dāng)著我的面吹牛您市,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播役衡,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茵休,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了映挂?” 一聲冷哼從身側(cè)響起泽篮,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎柑船,沒(méi)想到半個(gè)月后帽撑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞍时,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年亏拉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逆巍。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡及塘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锐极,到底是詐尸還是另有隱情笙僚,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布灵再,位于F島的核電站肋层,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏翎迁。R本人自食惡果不足惜栋猖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汪榔。 院中可真熱鬧蒲拉,春花似錦、人聲如沸痴腌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)士聪。三九已至锦援,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間戚嗅,已是汗流浹背雨涛。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工枢舶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人替久。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓凉泄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蚯根。 傳聞我的和親對(duì)象是個(gè)殘疾皇子后众,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容