天天看點

超詳細ansible-playbook劇本編寫YAML

目錄

  • YAML
    • 含義
    • Ansible的腳本—playbook劇本
    • 執行playbook
    • hosts和users介紹
    • tasks清單和action
    • Handlers介紹
    • playbook變量
    • 直接在yaml中定義變量
    • 直接引用一些變量
    • 條件測試
    • 多條件判斷
    • 組條件判斷
    • 疊代

YAML

含義

  • 是一種非标記語言。是用來寫配置檔案的語言,非常簡潔和強大。YAML文法和其他語言類似,也可以表達散清單、标量等資料結構。

    結構通過空格來展示;序列裡配置項通過-來代表;Map裡鍵值用:來分隔;YAML的擴充名為yaml

基本文法規則

  • 大小寫敏感
  • 使用縮進表示層級關系
  • 縮進時不允許使用Tab鍵,隻允許使用空格。
  • 縮進的空格數目不重要,隻要相同層級的元素左側對齊即可

YAML支援的資料結構

  1. 對象:鍵值對的集合,又稱為映射(mapping)/哈希(hashes)/字典(dictionary)

例如:name: Example Developer

  1. 數組:一組按次序排列的值,又稱為序列 (sequence)/清單(list)

    例如:

    Apple

    Orange

  2. 純量(變量):單個的、不可再分的值

    例如:number: 12.30l

    sure: true

yaml示例

name: zhangsan

age: 20

people:

  • name: wangwu

    age: 21

Ansible的腳本—playbook劇本

通過task調用ansible的模闆将多個play組織在一個playbook中運作。

playbooks部分組成

  1. Tasks:任務,即調用子產品完成的某操作
  2. Variables:變量
  3. Templates:模闆
  4. Handlers:處理器,當某條件滿足時,觸發執行的操作
  5. Roles:角色

執行playbook

例如:

ansible-playbook ttt.yaml
           

參數:

-k(-ask-pass)用來互動輸入密碼
-K(-ask-become-pass)用來互動輸入sudo密碼
-u 指定使用者
           

補充指令:

ansible-playbook ttt.yaml --syntax-check #檢查yaml檔案的文法是否正确
ansible-playbook ttt.yaml --list-task #檢查tasks任務
ansible-playbook ttt.yaml --list-hosts #檢查生效的主機
ansible-playbook ttt.yaml --start-at-task='abc' #指定從某個task開始運作
           

hosts和users介紹

- hosts: webserver #指定主機組,可以是一個或多個組
   remote_user: root #指定遠端主機執行的使用者名
           

可以為每個任務定義遠端執行使用者

[[email protected] opt]# vim ping.yaml 
- hosts: mysql
  remote_user: root
  tasks:
   - name: ping #name為給接下來運作的任務起個名字
      ping: #調用ping子產品
      remote_user: mysql #指定遠端主機執行tasks的運作使用者為mysql
           

執行playbook:

ansible-playbook ping.yaml -k #免密的情況下可省略-k
           
[[email protected] ~]# ansible-playbook ping.yaml  #此時發現運作tasks:ping不成功

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [ping] ***********************************************************************************
fatal: [20.0.0.13]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", "unreachable": true}

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=2    changed=0    unreachable=1    failed=0    skipped=0    rescued=0    ignored=0   
           

分析錯誤原因:

"msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)." #沒有權限去執行操作
解決
給mysql使用者提權
           

指定遠端主機sudo切換使用者:

[[email protected] opt]# vim ping.yaml 
- hosts: mysql
  remote_user: root
  become:
  tasks:
   - name: ping
      ping: 
      remote_user: mysql
           
[[email protected] ~]# ansible-playbook ping.yaml 

PLAY [mysql] **********************************************************************************

TASK [Gathering Facts] ************************************************************************
fatal: [20.0.0.13]: FAILED! => {"ansible_facts": {}, "changed": false, "failed_modules": {"setup": {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "failed": true, "module_stderr": "Shared connection to 20.0.0.13 closed.\r\n", "module_stdout": ">>> /etc/sudoers: 文法錯誤 near line 1 <<<\r\nsudo: /etc/sudoers 中第 1 行附近有解析錯誤\r\nsudo: 沒有找到有效的 sudoers 資源,退出\r\nsudo: 無法初始化政策插件\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}}, "msg": "The following modules failed to execute: setup\n"}

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
           

分析原因:

沒有找到有效的 sudoers 資源

解決:

在被控制端的主機/etc/sudoers中添加mysql

[[email protected] ~]# vim ping.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: useradd mysql
     user: name=mysql #建立一個mysql使用者
   - name: sudoers
     shell: /usr/bin/echo "mysql ALL=(root) ALL" >> /etc/sudoers
   - name: ping
     become: yes #允許進行提權
     become_user: mysql #提權賬号
     ping:

[[email protected] ~]# ansible-playbook ping.yaml 

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [sudoers] ********************************************************************************
changed: [20.0.0.13]

TASK [ping] ***********************************************************************************
ok: [20.0.0.13]

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
           

tasks清單和action

  • Play的主體部分是task清單,task清單中的各任務按次序逐個在hosts中指定的主機上執行,即在所有主機上完成第一個任務後再開始第二個任務

    在運作playbook時(從上到下執行),如果一個host執行task失敗,整個tasks都會復原,請修正playbook

    中的錯誤,然後重新執行即可。Task的目的是使用指定的參數執行子產品,而在子產品參數中可以使用變量,子產品執行時幂等的,這意味着多次執行是安全的,因為其結果一緻。

  • 每一個task必須有一個名稱name,這樣在運作playbook時,從其輸出的任務執行資訊中可以很好的辨識出是屬于哪一個task的。
  • 定義一個task,常見的格式:"module: options”例如: yum: name=httpd
  • ansible的自帶子產品中,command子產品和shell子產品無需使用key=value格式

例如:

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: useradd mysql
     user: name=mysql
   - name: sudoers
     shell: usr/bin/echo "mysql ALL=(root) ALL" >> /etc/sudoers #這裡去掉一個/,模拟運作失敗
   - name: ping
     ping:

[[email protected] ~]# ansible-playbook demo.yaml 

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [sudoers] ********************************************************************************
fatal: [20.0.0.13]: FAILED! => {"changed": true, "cmd": "usr/bin/echo \"mysql ALL=(root) ALL\" >> /etc/sudoers", "delta": "0:00:00.002690", "end": "2021-01-14 21:59:18.256832", "msg": "non-zero return code", "rc": 127, "start": "2021-01-14 21:59:18.254142", "stderr": "/bin/sh: usr/bin/echo: 沒有那個檔案或目錄", "stderr_lines": ["/bin/sh: usr/bin/echo: 沒有那個檔案或目錄"], "stdout": "", "stdout_lines": []}

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
           

隻要執行指令的傳回值不為0,就為報錯,tasks停止,此次任務復原

修改

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: useradd mysql
     user: name=mysql
   - name: sudoers
     shell: usr/bin/echo "mysql ALL=(root) ALL" >> /etc/sudoers
     ignore_errors: True #忽略錯誤,強制傳回成功
   - name: ping
     ping:

[[email protected] ~]# ansible-playbook demo.yaml 

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [sudoers] ********************************************************************************
fatal: [20.0.0.13]: FAILED! => {"changed": true, "cmd": "usr/bin/echo \"mysql ALL=(root) ALL\" >> /etc/sudoers", "delta": "0:00:00.002509", "end": "2021-01-14 22:03:43.033818", "msg": "non-zero return code", "rc": 127, "start": "2021-01-14 22:03:43.031309", "stderr": "/bin/sh: usr/bin/echo: 沒有那個檔案或目錄", "stderr_lines": ["/bin/sh: usr/bin/echo: 沒有那個檔案或目錄"], "stdout": "", "stdout_lines": []}
...ignoring

TASK [ping] ***********************************************************************************
ok: [20.0.0.13]

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
           

Handlers介紹

Handlers也是一些task的清單,和一般的task并沒有什麼差別。

由通知者進行的notify,如果沒有被notify,則Handlers不會執行,假如被notify了,則Handlers被執行

不管有多少個通知者進行了notify,等到play中的所有task執行完成之後,handlers也隻會被執行一次

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: useradd mysql
     user: name=mysql
   - name: install apache
     yum: name=httpd
     notify:
      - restart httpd
   - name: restart httpd
     service: name=httpd state=started
  handlers:
      - name: restart httpd
        service: name=httpd state=restarted

[[email protected] ~]# ansible-playbook demo.yaml 

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [install apache] *************************************************************************
changed: [20.0.0.13]

TASK [restart httpd] **************************************************************************
changed: [20.0.0.13]

RUNNING HANDLER [restart httpd] ***************************************************************
changed: [20.0.0.13]

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=5    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
           

playbook變量

通過ansible指令傳遞

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  vars:
   - user:
  tasks:
   - name: useradd mysql
     user: name={{user}}

[[email protected] opt]# ansible-playbook demo.yaml -e user=mysql #使用-e給變量指派
PLAY [mysql] ********************************************************************

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

TASK [useradd mysql] ************************************************************
changed: [20.0.0.13]

PLAY RECAP **********************************************************************
20.0.0.13                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[[email protected] opt]# ansible mysql -m command -a 'tail /etc/passwd' #檢視
20.0.0.13 | CHANGED | rc=0 >>
………………
mysql:x:1001:1001::/home/mysql:/bin/bash
           

直接在yaml中定義變量

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  vars:
   services: httpd
  tasks:
   - name: useradd mysql
     user: name=mysql
   - name: install apache
     yum: name={{services}}
     notify:
      - restart httpd
   - name: restart httpd
     service: name={{services}} state=started
  handlers:
      - name: restart httpd
        service: name={{services}} state=restarted

[[email protected] ~]# ansible-playbook demo.yaml

PLAY [mysql] **********************************************************************************

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

TASK [useradd mysql] **************************************************************************
ok: [20.0.0.13]

TASK [install apache] *************************************************************************
ok: [20.0.0.13]

TASK [restart httpd] **************************************************************************
ok: [20.0.0.13]

PLAY RECAP ************************************************************************************
20.0.0.13                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
           

直接引用一些變量

引用ansible的固定變量

[[email protected] opt]# vi demo.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: copy ipv4
     copy: content="{{ansible_all_ipv4_addresses}}" dest=/opt/ipv4.txt
[[email protected] opt]# ansible-playbook demo.yaml 

PLAY [mysql] ********************************************************************

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

TASK [copy ipv4] ****************************************************************
changed: [20.0.0.13]

PLAY RECAP **********************************************************************
20.0.0.13                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
           

mysql主機檢視

[[email protected] opt]# cat ipv4.txt 
["192.168.122.1", "20.0.0.13"]
           

條件測試

如果需要根據變量、facts(setup)或此前任務的執行結果來作為某task執行與否的前提時要用到條件測試,在playbook中條件測試使用when子句,在task背景添加when子句即可使用條件測試:when子句支援jinjia2表達式或文法(jinjia2:基于python語言,格式為{{}},是一種特殊的占位符)

[[email protected] opt]# vi when.yaml
- hosts: webserver
  remote_user: root
  tasks:
   - name: shutdown
     command: /sbin/shutdown -r now 
     when: #當系統版本為CentOS時,關閉webserver主機
      - ansible_distribution == "CentOS" 
           

多條件判斷

[[email protected] opt]# vi when.yaml
- hosts: webserver
  remote_user: root
  tasks:
   - name: shutdown
     command: /sbin/shutdown -r now 
     when: #當系統版本為CentOS7時,關閉webserver主機
      - ansible_distribution == "CentOS" 
      - ansible_distribution_major_version == "7"
           

組條件判斷

[[email protected] opt]# vi when.yaml
- hosts: webserver
  remote_user: root
  tasks:
   - name: shutdown CentOS6 and CentOS7 
     command: /sbin/shutdown -r now 
     when: #當系統版本為CentOS7時,關閉webserver主機
      - ansible_distribution == "CentOS"  and ansible_distribution_major_version == "6"
      - ansible_distribution == "Debian" and ansible_distribution_major_version == "7"
           

疊代

當有需要重複性執行的任務時,可以使用疊代機制。其使用格式為item變量引用,并通過with_items語句指明疊代的元素

[[email protected] opt]# vi demo.yaml
 hosts: mysql
  remote_user: root
  tasks:
   - name: install
     yum: name={{ item }} state=latest
     with_items:
      - httpd
      - php
      - tree         

[[email protected] opt]# ansible-playbook demo.yaml 
PLAY [mysql] ********************************************************************

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

TASK [install] ******************************************************************
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via 
squash_actions is deprecated. Instead of using a loop to supply multiple items 
and specifying `name: "{{ item }}"`, please use `name: ['httpd', 'php']` and 
remove the loop. This feature will be removed in version 2.11. Deprecation 
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
changed: [20.0.0.13] => (item=[u'httpd', u'php'])

PLAY RECAP **********************************************************************
20.0.0.13                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
           

也可以自己定義

[[email protected] ~]# vim demo.yaml
- hosts: mysql
  remote_user: root
  tasks:
   - name: useradd
     user: name={{item.name}} state=present group={{item.groups}}
     with_items:
      - { name: test1, groups: wheel}
      - { name: test2, groups: root}


[[email protected] opt]# ansible-playbook demo.yaml 

PLAY [mysql] ********************************************************************

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

TASK [useradd] ******************************************************************
changed: [20.0.0.13] => (item={u'name': u'test1', u'groups': u'wheel'})
changed: [20.0.0.13] => (item={u'name': u'test2', u'groups': u'root'})

PLAY RECAP **********************************************************************
20.0.0.13                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[[email protected] opt]# ansible mysql -a " tail /etc/passwd"
20.0.0.13 | CHANGED | rc=0 >>
…………………………
test1:x:1002:10::/home/test1:/bin/bash
test2:x:1003:0::/home/test2:/bin/bash
           

繼續閱讀