Ansible之playbook拓展

  一、handlers和notify結合使用觸發條件

  handlers同tasks是屬同級,相當於一個特殊任務列表,這些任務同前文說的tasks里的任務沒有本質的不同,用於當關注的資源發生變化時,才會採取一定的操作。notify此action可用於在每一個play的最後被觸發,這樣可避免多次有改變發生時都執行指定的操作,僅在所有的變化發生完成后一次性地執行指定操作,在notify中列出的操作稱為handler,換句話說當所關注的資源發生變化時notify將調用handlers中定義的操作。其中notify所在任務就是被監控的任務資源變化的任務,notify可以調用多個handlers定義的操作,一個handlers里可以定義很多任務。

---
- hosts: websers
  remote_user: root

  tasks:
    - name: create apache group
      group: name=apache gid=80 system=yes
    - name: create apache user
      user: name=apache uid=80 group=apache system=yes shell=/sbin/nologin home=/var/www/html 
    - name: install httpd
      yum: name=httpd
    - name: copy config file
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
      notify: restart httpd service

    - name: start httpd service
      service: name=httpd state=started enabled=yes

  handlers:
    - name: restart httpd service
      service: name=httpd state=restarted   

  說明:notify后指定的名稱必須要和handlers里的任務名稱相同,如不同handlers所定義的任務將不會執行,相當於沒有notify調用handlers里的任務。

  在某些情況下,我們可能同時需要調用多個handlers,或者需要使用handlers其他handlers,ansible可以很簡單的實現這些功能,如下所示

  1)調用多個handlers

---
- hosts: websers
  remote_user: root

  tasks:
    - name: create apache group
      group: name=apache gid=80 system=yes
    - name: create apache user
      user: name=apache uid=80 group=apache system=yes shell=/sbin/nologin home=/var/www/html 
    - name: install httpd
      yum: name=httpd
    - name: copy config file
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
      notify: 
        - restart httpd service
        - check httpd process

    - name: start httpd service
      service: name=httpd state=started enabled=yes

  handlers:
    - name: restart httpd service
      service: name=httpd state=restarted
    - name: check httpd process                                                                                      
      shell: /usr/bin/killall -0 httpd &> /tmp/httpd.log

  說明:調用多個handlers我們需要在notify中寫成列表的形式,同樣我們被觸發的任務名稱需要同handlers里的被調用的任務名稱完全相同

  2)handlers調用handlers

---
- hosts: websers
  remote_user: root

  tasks:
    - name: create apache group
      group: name=apache gid=80 system=yes
    - name: create apache user
      user: name=apache uid=80 group=apache system=yes shell=/sbin/nologin home=/var/www/html 
    - name: install httpd
      yum: name=httpd
    - name: copy config file
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
      notify: restart httpd service

    - name: start httpd service
      service: name=httpd state=started enabled=yes

  handlers:
    - name: restart httpd service
      service: name=httpd state=restarted
      notify: check httpd process                                                                                    
    - name: check httpd process
      shell: /usr/bin/killall -0 httpd &> /tmp/httpd.log

  說明:handlers調用handlers,則直接在handlers中使用notify選項就可以。

在使用handlers我們需要注意一下幾點:

  1)handlers只有在其所在任務被執行時才會被運行,handlers定義的任務它不會像task任務那樣,自動會從上至下依次執行,它只會被notify所在的任務發生狀態改變時才會觸發handlers 的任務執行,如果一個任務中定義了notify調用handlers,但由於條件的判斷等原因,該任務尚未執行,那麼notify調用的handlers同樣也不會執行。

  2)handlers只會在play的末尾運行一次;如果想要在一個playbook的中間運行handlers,則需要使用meta模塊來實現,如:-mate: flush_handlers

  二、playbook中變量的使用

ansible中變量的命名規範同其他語言或系統中變量命名規則非常類似。變量名以英文大小寫字母開頭,中間可以包含下劃線和数字,ansible變量的來源有很多,具體有以下幾點:

  1)ansible setup模塊,這個模塊可以從遠程主機上獲取很多遠程主機的基本信息,它所返回的所有變量都可以直接調用,有關setup說明請參考本人博客

  2)在/etc/ansible/hosts中定義,此文件是ansible執行名時默認加載的主機清單文件,在裏面除了可定義我們要管理的主機外,我們還可以定義針對單個主機定義單獨的變量,我們把針對單獨某一台主機定義的變量叫做普通變量(也可叫做主機變量);還有一種變量它不是針對單獨一個主機,它針對某一個組裡的所有主機,我們把這種變量叫做公共組變量。主機清單中定義的變量優先級是普通變量高於公共變量。

    2.1)主機變量,可以在主機清單中定義主機時為其添加主機變量以便於在playbook中使用,如下所示

[websers]
192.168.0.128 http_port=80 maxRequestsPerChild=808
192.168.0.218 http_port=81 maxRequestsPerChild=909

    2.2)主機組變量,組變量是指定賦予給指定組內所有主機上的在playbook中可使用的變量,如下所示

[websers]
192.168.0.128 http_port=80 
192.168.0.218 http_port=81 
[websers:vars]
maxRequestsPerChild=909

  3)通過命令行指定變量(-e指定變量賦值,可以說多個但需要用引號引起或者一個變量用一個-e指定賦值),這種在命令行指定的優先級最高。如下所示

ansible-playbook -e 'package_name1=httpd package_name2=nginx' test_vars.yml

  4)在playbook中定義變量,最常見的定義變量的方法是使用vars代碼塊,如下所示

---
- hosts: websers
  remote_user: root
  vars:
    - abc: xxx 
    - bcd: aaa  

  5)在獨立的變量yml文件中定義,在playbook中使用vars_files代碼塊引用其變量文件,如下所示

[root@test ~]#cat vars.yml 
---
package_name1: vsftpd
package_name2: nginx
[root@test ~]#cat test_vars.yml 
---
- hosts: websers
  remote_user: root
  vars_files:
    - vars.yml
  tasks:
    - name: install package1
      yum: name={{ package_name1 }}
    - name: install package2
      yum: name={{ package_name2 }}
[root@test ~]#

  6)在role中定義,這個後續說到角色在做解釋

  變量的調用方式:第一種在playbook中使用變量需要用“{{}}”將變量括起來,表示括號里的內容是一個變量,有時用“{{  variable_name }}”才生效;第二種是ansible-playbook -e 選項指定其變量,ansible-playbook -e “hosts=www user=xxxx” test.yml

  在主機清單中定義變量的方法雖然簡單直觀,但是當所需要定義的變量有很多時,並且被多台主機使用時,這種方法顯得非常麻煩,事實上ansible的官方手冊中也不建議我們把變量直接定義到hosts文件中;在執行ansible命令時,ansible會默認會從/etc/ansible/host_vars/和/etc/ansible/group_vars/兩個目錄下讀取變量定義文件,如果/etc/ansible/下沒有以上這兩個目錄,我們可以手動創建,並且可以在這兩個目錄下創建與hosts文件中的主機名或主機組同名的文件來定義變量。比如我們要給192.168.0.218 這個主機定義個變量文件,我們可以在/etc/ansible/host_vars/目錄下創建一個192.168.0.218的空白文件,然後在文件中以ymal語法來定義所需變量即可。如下所示

[root@test ~]#tail -6 /etc/ansible/hosts 
## db-[99:101]-node.example.com
[websers]
192.168.0.128 
192.168.0.218 
[appsers]
192.168.0.217
[root@test ~]#cat /etc/ansible/host_vars/192.168.0.218 
---
file1: abc
file2: bcd
[root@test ~]#cat test.yml 
---
- hosts: 192.168.0.218
  remote_user: root
  
  tasks:
    - name: touch file1
      file: name={{ file1 }} state=touch
    - name: toch file2
      file: name={{ file2 }} state=touch
[root@test ~]#ansible-playbook test.yml 

PLAY [192.168.0.218] ************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.218]

TASK [touch file1] **************************************************************************************************
changed: [192.168.0.218]

TASK [toch file2] ***************************************************************************************************
changed: [192.168.0.218]

PLAY RECAP **********************************************************************************************************
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#ansible 192.168.0.218 -m shell -a 'ls -l /root'
192.168.0.218 | SUCCESS | rc=0 >>
總用量 12
-rw-r--r--. 1 root   root    0 11月 17 16:49 abc
-rw-r--r--. 1 root   root    0 11月 17 16:49 bcd
drwxr-xr-x. 2 qiuhom root 4096 11月 11 19:18 scripts
drwxr-xr-x. 3 qiuhom root 4096 11月 11 19:28 test
-rw-r--r--. 1 root   root   57 11月 13 19:15 test_cron_file

[root@test ~]#

  說明:可看到我們定義在/etc/ansible/host_vars/下的主機變量文件中的變量生效了。

同理,我們要想針對某個組的主機定義一些變量,我們只需要在/etc/ansible/group_vars/目錄下創建與主機清單中的主機組同名的文件即可。

  三、使用高階變量

  對於普通變量,例如由ansible命令行設定的,hosts文件中定義的以及playbook中定義的和變量文件中定義的,這些變量都被稱為普通變量或者叫簡單變量,我們可以在playbook中直接用雙大括號加變量名來讀取變量內容;除此以外ansible還有數組變量或者叫做列表變量,如下所示:

[root@test ~]#cat vars.yml 
---
packages_list:
  - vsftpd
  - nginx
[root@test ~]#

  列表定義完成后我們要使用其中的變量可以列表名加下標的方式去訪問,有點類似shell腳本里的數組的使用,如下所示

[root@test ~]#cat test.yml 
---
- hosts: 192.168.0.218
  remote_user: root
  
  vars_files:
    - vars.yml
  tasks:
    - name: touch file
      file: name={{ packages_list[0] }} state=touch
    - name: mkdir dir
      file: name={{ packages_list[1] }} state=directory
[root@test ~]#

  說明:我們要使用列表中的第一個元素變量,我們可以寫成vars_list[0],使用第二個變量則下標就是1,依此類推

[root@test ~]#ansible *218 -m shell -a 'ls -l /root'
192.168.0.218 | SUCCESS | rc=0 >>
總用量 12
-rw-r--r--. 1 root   root    0 11月 17 16:49 abc
-rw-r--r--. 1 root   root    0 11月 17 16:49 bcd
drwxr-xr-x. 2 qiuhom root 4096 11月 11 19:18 scripts
drwxr-xr-x. 3 qiuhom root 4096 11月 11 19:28 test
-rw-r--r--. 1 root   root   57 11月 13 19:15 test_cron_file

[root@test ~]#ansible-playbook test.yml 

PLAY [192.168.0.218] ************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.218]

TASK [touch file] ***************************************************************************************************
changed: [192.168.0.218]

TASK [mkdir dir] ****************************************************************************************************
changed: [192.168.0.218]

PLAY RECAP **********************************************************************************************************
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#ansible *218 -m shell -a 'ls -l /root'
192.168.0.218 | SUCCESS | rc=0 >>
總用量 16
-rw-r--r--. 1 root   root    0 11月 17 16:49 abc
-rw-r--r--. 1 root   root    0 11月 17 16:49 bcd
drwxr-xr-x. 2 root   root 4096 11月 17 17:23 nginx
drwxr-xr-x. 2 qiuhom root 4096 11月 11 19:18 scripts
drwxr-xr-x. 3 qiuhom root 4096 11月 11 19:28 test
-rw-r--r--. 1 root   root   57 11月 13 19:15 test_cron_file
-rw-r--r--. 1 root   root    0 11月 17 17:23 vsftpd

[root@test ~]#

  說明:可看到我們創建的文件和目錄在目標主機已經生成

上面的用法是典型的python列表的用法,在python中讀取列表中的元素就是用下標的表示來讀取相應的元素的值。接下我們將介紹另外一種更為複雜的變量,它類似python中的字典概念,但比字典的維度要高,更像是二維字典。ansible內置變量ansible_eth0就是這樣一種,它用來保存遠端主機上面eth0接口的信息,包括ip地址和子網掩碼等。如下所示

[root@test ~]#cat test.yml     
---
- hosts: 192.168.0.218
  remote_user: root
  
  tasks:
    - debug: var=ansible_eth0 
[root@test ~]#ansible-playbook test.yml 

PLAY [192.168.0.218] ************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.218]

TASK [debug] ********************************************************************************************************
ok: [192.168.0.218] => {
    "ansible_eth0": {
        "active": true, 
        "device": "eth0", 
        "features": {
            "fcoe_mtu": "off [fixed]", 
            "generic_receive_offload": "on", 
            "generic_segmentation_offload": "on", 
            "highdma": "off [fixed]", 
            "large_receive_offload": "off [fixed]", 
            "loopback": "off [fixed]", 
            "netns_local": "off [fixed]", 
            "ntuple_filters": "off [fixed]", 
            "receive_hashing": "off [fixed]", 
            "rx_checksumming": "on", 
            "rx_vlan_filter": "on [fixed]", 
            "rx_vlan_offload": "on [fixed]", 
            "scatter_gather": "on", 
            "tcp_segmentation_offload": "on", 
            "tx_checksum_fcoe_crc": "off [fixed]", 
            "tx_checksum_ip_generic": "on", 
            "tx_checksum_ipv4": "off", 
            "tx_checksum_ipv6": "off", 
            "tx_checksum_sctp": "off [fixed]", 
            "tx_checksum_unneeded": "off", 
            "tx_checksumming": "on", 
            "tx_fcoe_segmentation": "off [fixed]", 
            "tx_gre_segmentation": "off [fixed]", 
            "tx_gso_robust": "off [fixed]", 
            "tx_lockless": "off [fixed]", 
            "tx_scatter_gather": "on", 
            "tx_scatter_gather_fraglist": "off [fixed]", 
            "tx_tcp6_segmentation": "off", 
            "tx_tcp_ecn_segmentation": "off", 
            "tx_tcp_segmentation": "on", 
            "tx_udp_tnl_segmentation": "off [fixed]", 
            "tx_vlan_offload": "on [fixed]", 
            "udp_fragmentation_offload": "off [fixed]", 
            "vlan_challenged": "off [fixed]"
        }, 
        "hw_timestamp_filters": [], 
        "ipv4": {
            "address": "192.168.0.218", 
            "broadcast": "192.168.0.255", 
            "netmask": "255.255.255.0", 
            "network": "192.168.0.0"
        }, 
        "ipv6": [
            {
                "address": "fe80::20c:29ff:fee8:f67b", 
                "prefix": "64", 
                "scope": "link"
            }
        ], 
        "macaddress": "00:0c:29:e8:f6:7b", 
        "module": "e1000", 
        "mtu": 1500, 
        "pciid": "0000:02:01.0", 
        "promisc": false, 
        "speed": 1000, 
        "timestamping": [
            "rx_software", 
            "software"
        ], 
        "type": "ether"
    }
}

PLAY RECAP **********************************************************************************************************
192.168.0.218              : ok=2    changed=0    unreachable=0    failed=0   

[root@test ~]#

  說明:以上playbook就實現了對ansible_eth0這個變量進行調試並打印,可以看到ansible_eth0是一個相對比較複雜的變量,裡面包含了字典,列表混合一起的一個大字典。

我們可以看到ansible_eht0裡面包含了很多內容,我們要想讀取其中的IPV4地址,我們可以採用“.”或者下標的方式去訪問,如下所示

[root@test ~]#cat test.yml 
---
- hosts: 192.168.0.218
  remote_user: root
  
  tasks:
    - name: print ipv4  
      shell: echo {{ ansible_eth0["ipv4"]["address"] }} 
    - name: print mac
      shell: echo  {{ ansible_eth0.macaddress }}
[root@test ~]#ansible-playbook test.yml -v
Using /etc/ansible/ansible.cfg as config file

PLAY [192.168.0.218] ************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
ok: [192.168.0.218]

TASK [print ipv4] ***************************************************************************************************
changed: [192.168.0.218] => {"changed": true, "cmd": "echo 192.168.0.218", "delta": "0:00:00.001680", "end": "2019-11-17 18:30:21.926368", "rc": 0, "start": "2019-11-17 18:30:21.924688", "stderr": "", "stderr_lines": [], "stdout": "192.168.0.218", "stdout_lines": ["192.168.0.218"]}

TASK [print mac] ****************************************************************************************************
changed: [192.168.0.218] => {"changed": true, "cmd": "echo 00:0c:29:e8:f6:7b", "delta": "0:00:00.001746", "end": "2019-11-17 18:30:22.650541", "rc": 0, "start": "2019-11-17 18:30:22.648795", "stderr": "", "stderr_lines": [], "stdout": "00:0c:29:e8:f6:7b", "stdout_lines": ["00:0c:29:e8:f6:7b"]}

PLAY RECAP **********************************************************************************************************
192.168.0.218              : ok=3    changed=2    unreachable=0    failed=0   

[root@test ~]#

  說明:由此可以看出ansible多級變量的調用,使用中括號和點號都是可以的

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

※評比南投搬家公司費用收費行情懶人包大公開