目錄
- YAML
-
- 含義
- Ansible的腳本—playbook劇本
- 執行playbook
- hosts和users介紹
- tasks清單和action
- Handlers介紹
- playbook變量
- 直接在yaml中定義變量
- 直接引用一些變量
- 條件測試
- 多條件判斷
- 組條件判斷
- 疊代
YAML
含義
-
是一種非标記語言。是用來寫配置檔案的語言,非常簡潔和強大。YAML文法和其他語言類似,也可以表達散清單、标量等資料結構。
結構通過空格來展示;序列裡配置項通過-來代表;Map裡鍵值用:來分隔;YAML的擴充名為yaml
基本文法規則
- 大小寫敏感
- 使用縮進表示層級關系
- 縮進時不允許使用Tab鍵,隻允許使用空格。
- 縮進的空格數目不重要,隻要相同層級的元素左側對齊即可
YAML支援的資料結構
- 對象:鍵值對的集合,又稱為映射(mapping)/哈希(hashes)/字典(dictionary)
例如:name: Example Developer
-
數組:一組按次序排列的值,又稱為序列 (sequence)/清單(list)
例如:
Apple
Orange
-
純量(變量):單個的、不可再分的值
例如:number: 12.30l
sure: true
yaml示例
name: zhangsan
age: 20
people:
-
name: wangwu
age: 21
Ansible的腳本—playbook劇本
通過task調用ansible的模闆将多個play組織在一個playbook中運作。
playbooks部分組成
- Tasks:任務,即調用子產品完成的某操作
- Variables:變量
- Templates:模闆
- Handlers:處理器,當某條件滿足時,觸發執行的操作
- 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