自動化運維工具——YAML詳解
- YAML介紹
- YAML文法
-
- 基本文法
- YAML支援的資料結構:
- playbook的組成
- 三要素
- playbook 文法
- hosts和users介紹
- 指定遠端主機sudo切換使用者
- 小實驗 練練手
-
- 實驗要求:
- Handlers介紹
-
- 1、在playbook直接使用變量
- 2、通過ansible指令傳遞
- 3、直接在yaml中定義變量
- 4、直接引用主機變量
- 條件測試
-
- 多條件判斷
- 組條件判斷
- 疊代
YAML介紹
YAML是一個可讀性高的用來表達資料序列的格式。YAML參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。Clark Evans在2001年在首次發表了這種語言,另外Ingy döt Net與Oren Ben-Kiki也是這語言的共同設計者。
YAML Ain’t Markup Language,即YAML不是XML。不過,在開發的這種語言時,YAML的意思其實是:“Yet Another Markup Language”(仍是一種标記語言)。其特性:
YAML的可讀性好
YAML和腳本語言的互動性好
YAML使用實作語言的資料類型
YAML有一個一緻的資訊模型
YAML易于實作
YAML可以基于流來處理
YAML表達能力強,擴充性好
YAML文法
YAML的文法和其他高階語言類似,并且可以簡單表達清單、散清單、标量等資料結構。其結構(Structure)通過空格來展示,序列(Sequence)裡的項用"-“來代表,Map裡的鍵值對用”:"分隔。下面是一個示例。YAML是用鍵值對和縮進來表示的。
基本文法
1、大小寫敏感
2、使用縮進表示層級關系
3、縮進時不允許使用Tab鍵,隻能使用空格
4、縮進的空格數且不重要,隻要相同層級的元素左側對其即可
YAML支援的資料結構:
1.對象:鍵值對的集合,又稱為映射(mapping)/哈希(hashes)/字典(dictionary)
例如:
name:Example Developer
鍵值
⒉數組:一組按次序排列的值,又稱為序列(sequence)/清單(list)例如:-Apple
-Orange
3.純量:單個的、不可再分的值
例如:number: 12.30
sure: true
yaml示例:
name:zhangsan
age:20
name:lisi
age:22
people:
-name:zhangsan
age:20
-name:lisiage:22
playbook的組成
Ansible的腳本—playbook劇本
通過task調用ansible的模闆将多個play組織在一個
playbook中運作。playbooks本身由以下各部分組成
(1)Tasks:任務,即調用子產品完成的某操作;
(2) Variables:變量
(3) Templates:模闆
(4)Handlers:處理器,當某條件滿足時,觸發執行的操作;
(5) Roles:角色。
三要素
劇本的三要素
1、演出的場地
2、演員要到位
3、故事情節
playbook的三要素
1、場地—主機組hosts
2、演員—授權執行的使用者 remote user
3、故事情節----執行的任務tasks (調用的是各種ansible子產品)
playbook 文法
執行一個playbook
ansible-playbook [yaml檔案名]
例如:ansible-playbook ping.yml
參數:-k(-ask-pass)用來互動輸入ssh密碼
-K(-ask-become-pass)用來互動輸入sudo密碼
-u指定使用者
補充指令:
ansible-playbook nginx.yaml --syntax-check #檢查yaml檔案的文法是否正确
ansible-playbook nginx.yaml --list-task #檢查tasks任務
ansible-playbook nginx.yaml --list-hosts #檢查生效的主機
ansible-playbook nginx.yaml --start-at-task='Copy Nginx.conf’ #指定從某個task開始運作
hosts和users介紹
hosts: webserver #指定主機組,可以是一個或多個組。
remote user: root #指定遠端主機執行的使用者名
[[email protected] ~]# vim ping.yaml
- hosts: all #定義主機組
remote_user: root #指定root使用者 全局變量
tasks:
- name: test connection
ping:
[[email protected] ~]# ansible-playbook ping.yaml --syntax-check //檢查文法
playbook: ping.yaml
[[email protected] ~]# ansible-playbook ping.yaml //執行
PLAY [all] ************************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
ok: [192.168.188.20]
TASK [test connection] ************************************************************
ok: [192.168.188.20]
ok: [192.168.188.30]
PLAY RECAP ************************************************************************
192.168.188.20 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.188.30 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
指定遠端主機sudo切換使用者
[[email protected] ~]# vim sudo.yaml
- hosts: webservers
remote_user: root
become: yes //切換使用者執行
become_user: lisi //指定sudo使用者為lisi
tasks:
- name: copy text
copy: src=/etc/fstab dest=/home/lisi/fstab.bak
[[email protected] ~]# ansible-playbook sudo.yaml --syntax-check //檢視文法
playbook: sudo.yaml
[[email protected] ~]# ansible-playbook sudo.yaml //執行
PLAY [webservers] *****************************************************************
TASK [Gathering Facts] ************************************************************
[WARNING]: Module remote_tmp /home/lisi/.ansible/tmp did not exist and was created
with a mode of 0700, this may cause issues when running as another user. To avoid
this, create the remote_tmp dir with the correct permissions manually
ok: [192.168.188.20]
TASK [copy text] ******************************************************************
changed: [192.168.188.20]
PLAY RECAP ************************************************************************
192.168.188.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
去node1驗證
[[email protected] ~]# id lisi
uid=1001(lisi) gid=1001(lisi) 組=1001(lisi)
[[email protected] ~]# cd /home/lisi/
[[email protected] lisi]# ls
[[email protected] lisi]# ls
fstab.bak
小實驗 練練手
實驗要求:
安裝Apcha
開啟Apcha
關閉防火牆
給Apcha首頁換成this is Apche
[[email protected] ~]# vim Apcha.yaml
- hosts: mysql
remote_user: root
tasks:
- name: yum httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started
- name: stop firewalld
service: name=firewalld state=stopped
- name: index.html
copy: content="this is Apcha" dest=/var/www/html/index.html
[[email protected] ~]# ansible-playbook Apcha.yaml --syntax-check
playbook: Apcha.yaml
[[email protected] ~]# ansible-playbook Apcha.yaml
PLAY [mysql] **********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
TASK [yum httpd] ******************************************************************
changed: [192.168.188.30]
TASK [start httpd] ****************************************************************
changed: [192.168.188.30]
TASK [stop firewalld] *************************************************************
ok: [192.168.188.30]
TASK [index.html] *****************************************************************
changed: [192.168.188.30]
PLAY RECAP ************************************************************************
192.168.188.30 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 驗證
[[email protected] ~]# rpm -q httpd
httpd-2.4.6-67.el7.centos.x86_64
[[email protected] ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: active (running) since 四 2021-01-14 10:07:20 CST; 25s ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 42301 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
[[email protected] ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
如果一個hosts執行task失敗,整個task就會復原,請修正playbook錯誤,然後重新執行
[[email protected] ~]# vim Apcha.yaml
- hosts: webservers
remote_user: root
tasks:
- name: yum httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started
- name: stop firewalld
service: name=firewall state=stopped //firewalld 少d
- name: index.html
copy: content="this is Apcha" dest=/var/www/html/index.html
[[email protected] ~]# ansible-playbook Apcha.yaml --syntax-check //文法正确
playbook: Apcha.yaml
[[email protected] ~]# ansible-playbook Apcha.yaml //執行 到stop firewalld顯示錯誤 後面不執行
PLAY [webservers] *****************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.20]
TASK [yum httpd] ******************************************************************
changed: [192.168.188.20]
TASK [start httpd] ****************************************************************
changed: [192.168.188.20]
TASK [stop firewalld] *************************************************************
fatal: [192.168.188.20]: FAILED! => {"changed": false, "msg": "Could not find the requested service firewall: host"}
PLAY RECAP ************************************************************************
192.168.188.20 : ok=3 changed=2 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
node1 驗證
[[email protected] lisi]# id httpd
id: httpd: no such user
[[email protected] lisi]# systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: active (running) since 四 2021-01-14 10:48:41 CST; 1min 18s ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 42757 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
[[email protected] lisi]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: active (running) since 四 2021-01-14 10:50:29 CST; 16s ago
Docs: man:firewalld(1)
Main PID: 42868 (firewalld)
CGroup: /system.slice/firewalld.service
└─42868 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
在stop firewalld 下面添加ignore_errors: True(忽略錯誤,強制傳回成功)
[[email protected] ~]# vim Apcha.yaml
- hosts: webservers
remote_user: root
tasks:
- name: yum httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started
- name: stop firewalld
service: name=firewall state=stopped
ignore_errors: True
- name: index.html
copy: content="this is Apcha" dest=/var/www/html/index.html
[[email protected] ~]# ansible-playbook Apcha.yaml --syntax-check
playbook: Apcha.yaml
[[email protected] ~]# ansible-playbook Apcha.yaml
PLAY [webservers] *****************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.20]
TASK [yum httpd] ******************************************************************
ok: [192.168.188.20]
TASK [start httpd] ****************************************************************
ok: [192.168.188.20]
TASK [stop firewalld] *************************************************************
fatal: [192.168.188.20]: FAILED! => {"changed": false, "msg": "Could not find the requested service firewall: host"}
...ignoring
TASK [index.html] *****************************************************************
changed: [192.168.188.20]
PLAY RECAP ************************************************************************
192.168.188.20 : ok=5 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也隻會被執行一次
1、在playbook直接使用變量
[[email protected] ~]# vim Apcha.yaml
- hosts: webservers
remote_user: root
vars:
- abc: httpd //把httpd變成abc
tasks:
- name: yum httpd
yum: name={{abc}}
- name: start httpd
service: name={{abc}} state=started
- name: stop firewalld
service: name=firewalld state=stopped
- name: index.html
copy: content="this is Apcha" dest=/var/www/html/index.html
[[email protected] ~]# ansible-playbook Apcha.yaml --syntax-check
playbook: Apcha.yaml
[[email protected] ~]# ansible-playbook Apcha.yaml
PLAY [webservers] *****************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.20]
TASK [yum httpd] ******************************************************************
changed: [192.168.188.20]
TASK [start httpd] ****************************************************************
changed: [192.168.188.20]
TASK [stop firewalld] *************************************************************
ok: [192.168.188.20]
TASK [index.html] *****************************************************************
ok: [192.168.188.20]
PLAY RECAP ************************************************************************
192.168.188.20 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2、通過ansible指令傳遞
[[email protected] ~]# vim Apcha.yaml
- hosts: webservers
remote_user: root
vars:
- abc: //空的 在外面用指令設定
tasks:
- name: yum httpd
yum: name={{abc}}
- name: start httpd
service: name={{abc}} state=started
- name: stop firewalld
service: name=firewalld state=stopped
- name: index.html
copy: content="this is Apcha" dest=/var/www/html/index.html
[[email protected] ~]# ansible-playbook Apcha.yaml -e 'abc=httpd'
PLAY [webservers] *****************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.20]
TASK [yum httpd] ******************************************************************
ok: [192.168.188.20]
TASK [start httpd] ****************************************************************
ok: [192.168.188.20]
TASK [stop firewalld] *************************************************************
ok: [192.168.188.20]
TASK [index.html] *****************************************************************
ok: [192.168.188.20]
PLAY RECAP ************************************************************************
192.168.188.20 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3、直接在yaml中定義變量
[[email protected] ~]# vim test.yaml
- hosts: mysql
remote_user: root
tasks:
- name: copy file
copy: content="{{ansible_all_ipv4_addresses}}" dest=/opt/addr.txt
[[email protected] ~]# ansible-playbook test.yaml --syntax-check
playbook: test.yaml
[[email protected] ~]# ansible-playbook test.yaml
PLAY [mysql] **********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
TASK [copy file] ******************************************************************
changed: [192.168.188.30]
PLAY RECAP ************************************************************************
192.168.188.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
到node2 驗證
[[email protected] ~]# cd /opt/
[[email protected] opt]# ls
addr.txt rh
[[email protected] opt]# cat addr.txt
["192.168.122.1", "192.168.188.30"][[email protected] opt]#
4、直接引用主機變量
[[email protected] ~]# vim /etc/ansible/hosts
[webservers]
192.168.188.20
[mysql]
192.168.188.30 num="123456"
[[email protected] ~]# vim test.yaml
- hosts: mysql
remote_user: root
tasks:
- name: copy file
copy: content="{{ansible_all_ipv4_addresses}},{{num}}" dest=/opt/num.txt
[[email protected] ~]# ansible-playbook test.yaml --syntax-check
playbook: test.yaml
[[email protected] ~]# ansible-playbook test.yaml
PLAY [mysql] **********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
TASK [copy file] ******************************************************************
changed: [192.168.188.30]
PLAY RECAP ************************************************************************
192.168.188.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
去node2驗證
[[email protected] opt]# ls
addr.txt num.txt rh
[[email protected] opt]# cat num.txt
([u'192.168.122.1', u'192.168.188.30'], 123456)[[email protected] opt]#
條件測試
[[email protected] ~]# vim when.yaml
- hosts: mysql
remote_user: root
tasks:
- name: "shutdown CentOS"
command: /sbin/shutdown -h now
when: ansible_distribution == "CentOS" //判斷系統CentOS
[[email protected] ~]# ansible-playbook when.yaml
PLAY [mysql] **********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
TASK [shutdown CentOS] ************************************************************
fatal: [192.168.188.30]: FAILED! => {"msg": "Failed to connect to the host via ssh: ssh: connect to host 192.168.188.30 port 22: Connection refused"}
PLAY RECAP ************************************************************************
192.168.188.30 : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
多條件判斷
[[email protected] ~]# vim when.yaml
- hosts: mysql
remote_user: root
tasks:
- name: "shut down CentOS 7 systems"
command: /sbin/shutdown -r now
when:
- ansible_distribution == "CentOS" //判斷CentOS系統
- ansible_distribution_major_version == "7" //7版本
[[email protected] ~]# ansible-playbook when.yaml
PLAY [mysql] **********************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
TASK [shut down CentOS 7 systems] *************************************************
fatal: [192.168.188.30]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Shared connection to 192.168.188.30 closed.", "unreachable": true}
PLAY RECAP ************************************************************************
192.168.188.30 : ok=1 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
組條件判斷
[[email protected] ~]# vim when.yaml
- hosts: mysql
remote_user: root
tasks:
- name: "shut down CentOS 7 systems"
command: /sbin/shutdown -r now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or (ansible_distribution == "Debian " and ansible_distribution_major_version == "7") //判斷你的系統是CentOS 版本是6 或者系統是Debian 7
[[email protected] ~]# ansible-playbook when.yaml --syntax-check
playbook: when.yaml
[[email protected]erver1 ~]# ansible-playbook when.yaml
疊代
當有需要重複性執行的任務時,可以使用疊代機制
[[email protected] ~]# vim yum.yaml
- hosts: all
remote_user: root
tasks:
- name: install httpd tomcat
yum: name={{item}}
with_items:
- httpd
- tomcat
[[email protected] ~]# ansible-playbook yum.yaml --syntax-check
playbook: yum.yaml
[[email protected] ~]# ansible-playbook yum.yaml
LAY [all] ************************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.30]
ok: [192.168.188.20]
TASK [install httpd tomcat] *******************************************************
[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', 'tomcat']` 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.
[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', 'tomcat']` 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: [192.168.188.20] => (item=[u'httpd', u'tomcat'])
changed: [192.168.188.30] => (item=[u'httpd', u'tomcat'])
PLAY RECAP ************************************************************************
192.168.188.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.188.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[[email protected] ~]# rpm -q httpd
httpd-2.4.6-67.el7.centos.x86_64
[[email protected] ~]# rpm -q tomcat
tomcat-7.0.76-2.el7.noarch
[[email protected] ~]# rpm -q httpd
httpd-2.4.6-67.el7.centos.x86_64
[[email protected] ~]# rpm -q tomcat
tomcat-7.0.76-2.el7.noarch
也可以自己定義
[[email protected] ~]# vim user.yaml
- hosts: all
remote_user: root
tasks:
- name: "users"
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'song', groups: 'root' }
- { name: 'shufeng', groups: 'wheel' }
[[email protected] ~]# ansible-playbook user.yaml --syntax-check
playbook: user.yaml
[[email protected] ~]# ansible-playbook user.yaml
PLAY [all] ************************************************************************
TASK [Gathering Facts] ************************************************************
ok: [192.168.188.20]
ok: [192.168.188.30]
TASK [users] **********************************************************************
changed: [192.168.188.30] => (item={u'name': u'song', u'groups': u'root'})
changed: [192.168.188.20] => (item={u'name': u'song', u'groups': u'root'})
changed: [192.168.188.30] => (item={u'name': u'shufeng', u'groups': u'wheel'})
changed: [192.168.188.20] => (item={u'name': u'shufeng', u'groups': u'wheel'})
PLAY RECAP ************************************************************************
192.168.188.20 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.188.30 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[[email protected] ~]# id song
uid=1002(song) gid=1002(song) 組=1002(song),0(root)
[[email protected] ~]# id shufeng
uid=1003(shufeng) gid=1003(shufeng) 組=1003(shufeng),10(wheel)
[[email protected] ~]# id song
uid=1003(song) gid=1003(song) 組=1003(song),0(root)
[[email protected] ~]# id shufeng
uid=1004(shufeng) gid=1004(shufeng) 組=1004(shufeng),10(wheel)