天天看點

Ansible之playbook拓展

Ansible之playbook拓展

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

  一、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說明請參考本人部落格https://www.cnblogs.com/qiuhom-1874/p/11853512.html

  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多級變量的調用,使用中括号和點号都是可以的

作者:Linux-1874

出處:https://www.cnblogs.com/qiuhom-1874/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利.

繼續閱讀