playbook:
playbook 由一個或多個 ‘plays’ 組成.它的內容是一個以 ‘plays’ 為元素的列表.
在 play 之中,一組機器被映射為定義好的角色.在 ansible 中,play 的內容,被稱為 tasks,即任務.在基本層次的應用中,一個任務是一個對 ansible 模塊的調用
Playbooks 的格式是YAML,語法做到最小化. 首先來介紹下YAML語法
YAML:
每一個 YAML 文件都是從一個列表開始. 列表中的每一項都是一個鍵值對, 通常它們被稱為一個 “哈希” 或 “字典”. 所以, 我們需要知道如何在 YAML 中編寫列表和字典. YAML 還有一個比較奇怪的地方. 所有的 YAML 文件(無論和 Ansible 有沒有關系)開始行都應該是 ---. 這是 YAML 格式的一部分, 表明一個文件的開始.
列表中的所有成員都開始於相同的縮進級別, 並且使用一個 "- " 作為開頭(一個橫杠和一個空格):
---
#一個關於變成語言的列表
- python
- c++
- java
對應的Python 結果為:[‘python’,’c++’,’java’]
再來看一個塊結構的表示方法
-
- python
- c++
- java
-
- mysql
- mongodb
對應的python結果:
[[‘python’,’c++’,’java’],[‘mysql’,’mongodb’]]
一個字典是由一個簡單的 鍵: 值 的形式組成(這個冒號后面必須是一個空格):
---
# 一個出版書籍的記錄
publish:
name: Publisher
city: chengdu
province: sichuan
author:
name: zhf
age: 32
對應的python結果:
{‘publish’:{‘name’: ’Publisher’,’city’: ’chengdu’,’province’: ’sichuan’},’author’:{‘name’: ‘zhf’,’age’: 32}}
字典也可以使用縮進形式來表示, 如果你喜歡這樣的話:
{name: Publisher,city: chengdu,province: sichuan}
從上面這些可以看出,YAML其實和JSON的格式很接近
回到playbook我們來看下tasks列表
每一個 play 包含了一個 task 列表(任務列表).一個 task 在其所對應的所有主機上(通過 host pattern 匹配的所有主機)執行完畢之后,下一個 task 才會執行.有一點需要明白的是(很重要),在一個 play 之中,所有 hosts 會獲取相同的任務指令,這是 play 的一個目的所在,也就是將一組選出的 hosts 映射到 task
在運行 playbook 時(從上到下執行),如果一個 host 執行 task 失敗,這個 host 將會從整個 playbook 的 rotation 中移除. 如果發生執行失敗的情況,請修正 playbook 中的錯誤,然后重新執行即可.
下面我們來看一個task的具體例子:
---
- hosts: webservers
remote_user: root
tasks:
- name: for playbook test
apt: name=curl state=latest
在這個例子中,host的地址為webservers中定義的主機IP。remote_user: root代表已root用戶執行
tasks:就是具體的任務 其中name為任務的名稱, apt 就是ansible的遠程命令模塊 其中包含2個參數。name=curl代表要下載的軟件名稱,state=latest表示下載最新的
運行結果如下:任務成功執行並且在192.168.0.9上安裝了curl軟件包。其中TASK[for playbook test]就是我們這個任務的名稱
root@zhf-linux:/home/zhf/zhf/python_prj/auto_manintance# ansible-playbook test.yml -f 10
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [192.168.0.9]
TASK [for playbook test] *******************************************************
changed: [192.168.0.9]
PLAY RECAP *********************************************************************
192.168.0.9 : ok=2 changed=1 unreachable=0 failed=0
我們再來看另外一個例子:在這個yml文件中。task中采用了command模塊。command模塊和shell模塊比較特殊,它們不使用key=value的格式 而是直接使用命令。但是還是帶有自有的一些參數。比如chdi/home/zhf/zhf就是指定切換到的目錄。后面直接跟上rm tcpdumpresult.txt的命令刪除文件
---
- hosts: webservers
remote_user: root
tasks:
- name: for playbook test
command: chdir=/home/zhf/zhf rm tcpdumpresult.txt
運行結果:
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [192.168.0.9]
TASK [for playbook test] *******************************************************
changed: [192.168.0.9]
[WARNING]: Consider using file module with state=absent rather than running rm
PLAY RECAP *********************************************************************
192.168.0.9 : ok=2 changed=1 unreachable=0 failed=0
在這個提示中,有一個warning:Consider using file module with state=absent rather than running rm
這個的意思是讓我們使用file模塊 然后設置state=absent就可以刪除文件。如果改成file模塊使用的話yaml改成如下:
file: path=/home/zhf/zhf state=absent
我們再看一個template的模塊調用方法。在做很多功能配置的時候,涉及到大量的配置文件的修改和替換。template就是用來完成這一功能的。官方翻譯:template使用了Jinjia2格式作為文件模版,進行文檔內變量的替換的模塊。它的每次使用都會被ansible標記為”changed”狀態。
例子:這個講實現將本端的test1.yml文件內容渲染到遠端主機的test1.yml文件中去
---
- hosts: webservers
remote_user: root
tasks:
- name: use template function
template: src=/home/zhf/zhf/python_prj/auto_manintance/test1.yml dst=/home/zhf/zhf/test1.yml
其實在task中都是調用ansible中的命令模塊來觸發操作的。ansible有很多模塊。如果在主機上查詢的花可以使用ansible-doc -s file的方式進行查詢。 ansible-doc是查詢命令。 -s后面接的是模塊命令
或者也可以到網上查詢網址是:http://docs.ansible.com/ansible/latest/modules_by_category.html
這里面有所有的ansible命令介紹。
在YAML中還可以使用變量。通過vars:定義變量。在具體使用變量的過程中兩個雙括號包含變量。例子如下:
---
- hosts: webservers
vars:
filename: tcpdumpresult.txt
remote_user: root
tasks:
- name: for playbook test
command: chdir=/home/zhf/zhf rm {{ filename }}
下面將介紹下handlers;
當我們再完成一些服務配置的時候往往會重啟服務或者進行恢復。所以當遠端系統被人改動時,可以重放 playbooks 達到恢復的目的。當發生改動時’notify’ actions 會在 playbook 的每一個 task 結束時被觸發
下面的這個例子是在安裝vsftpd后重啟動這個服務。類似的只要執行結果中changed=1的都會觸發notify操作。
---
- hosts: webservers
remote_user: root
tasks:
- name: for notify function test
apt: name=vsftpd state=latest
notify:
- restart vsftpd
include語句和角色:
首先來看下include語句,在用playbook實現一個很復雜的功能的時候,有可能會寫一個很大的文件。而且這些文件的某些task在其他yml文件中也是被重用的。這樣就沒必要在每個yml中都去實現這些功能,這樣效率也很低,我們應該想在編寫軟件代碼的時候去組織這些文件。這里就需要用到include語句。include可以引用其他yml文件中的play。這種方式也被稱為封裝,將某些具體的功能給封裝起來。我們來看一個例子,以前面刪除文件的play來做示例。
首先來看test.yml。在task里面沒有實現具體的操作。而是包含了test1.yml文件
---
- hosts: webservers
remote_user: root
tasks:
- name: to verify include function
include: test1.yml
再來看下test1.yml文件。里面沒有了hosts和remote_user等配置,而只是由普通的task列表組成。
---
- name: test1.yml to delete the file
command: rm /home/zhf/test2.txt
來看下執行結果:
root@zhf-linux:/home/zhf/zhf/python_prj/auto_manintance# ansible-playbook test.yml -f 10
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [192.168.0.9]
TASK [to verify include function] **********************************************
included: /home/zhf/zhf/python_prj/auto_manintance/test1.yml for 192.168.0.9
TASK [test1.yml to delete the file] ********************************************
changed: [192.168.0.9]
[WARNING]: Consider using file module with state=absent rather than running rm
PLAY RECAP *********************************************************************
192.168.0.9 : ok=3 changed=1 unreachable=0 failed=0
從task的name來看,先執行test.yml. 然后調用test1.yml文件執行
我們在include的時候還可以往里面傳遞參數
tasks:
- name: to verify include function
include: test1.yml path=/home/zhf/
然后在test1.yml中通過{{ path }}來使用path. 同樣的你也可以在handler中去引用文件
notify:
- include: test1.yml
Role(角色):
現在已經學過 tasks 和 handlers,那怎樣組織 playbook 才是最好的方式呢?簡單的回答就是:使用 roles ! Roles 基於一個已知的文件結構,去自動的加載某些 vars_files,tasks 以及 handlers。基於 roles 對內容進行分組,使得我們可以容易地與其他用戶分享 roles 。
我們來看一個例子: 在一個工程里面有2個角色。一個是dele 一個是添加。分別實現刪除文件和添加文件。我們建立如下文件目錄:
1 group_vars: 其中定義全局變量,所有的角色都可以使用
2 hosts定義主機的參數,否則默認使用/etc/ansible/hosts的參數。自定義參數通過ansible-playbook -i hosts來調用
3 role: 角色文件夾。其中包含2個角色 add和dele. 在個2角色下分別有handlers, tasks,templates和vars文件夾。里面包含了各自的yml文件。角色中的vasrs里面的變量優先級高於group_vars中的變量
4 test.yml為整個程序的入口。從test.yml中引用具體的角色
一 首先我們來定義hosts文件。在里面添加主機IP
[webservers]
192.168.0.9
二 全局配置文件 test.yml. 在里面定義了2個角色分別是add和dele. 將分別對這個2角色進行調用
---
- name: add function for role test
hosts: webservers
roles:
- add
- name: dele function for dele test
hosts: webservers
roles:
- dele
三 角色add的定義:
[handers/main.yml]
- name: restart ftp
service: name=vsftpd state=restarted
[tasks/main.yml]
首先新建一個ftp_confg.conf文件。然后通過template命令將本段的ftp配置渲染到主機上的新建的文件
其中template中的src不用制定路徑,默認在上級的templates目錄中去尋找. 這里有一點很奇怪。template和command不能寫在同一個任務下面。否則會報錯。提示語法錯誤
- name: add the configration of FTP
command: chdir=/home/zhf touch ftp_config.conf.j2
- name: to template the file
template: src=ftp.conf.j2 dest=/home/zhf/ftp_config.conf.j2
[vars/main.yml]
定義FTP服務主機IP
---
ftpserver: 192.168.0.9
定義模板文件
[templates/ftp.conf.j2]
server {{ ftpserver }}
四 角色dele的定義:
task中刪除掉之前建立的ftp_config.conf.j2
[task/main.yml]
- name: dele the configration of FTP
command: chdir=/home/zhf rm ftp_config.conf.j2
[handlers/main.yml]
- name: after dele the conf then restart FTP
service: name=vsftpd state=restarted
運行結果如下:
root@zhf-linux:/home/zhf/zhf/python_prj/role_test# ansible-playbook -i hosts test.yml -f 10
PLAY [add function for role test] **********************************************
TASK [setup] *******************************************************************
ok: [192.168.0.9]
TASK [add : add the configration of FTP] ***************************************
changed: [192.168.0.9]
[WARNING]: Consider using file module with state=touch rather than running
touch
TASK [add : to template the file] **********************************************
changed: [192.168.0.9]
PLAY [dele function for dele test] *********************************************
TASK [setup] *******************************************************************
ok: [192.168.0.9]
TASK [dele : dele the configration of FTP] *************************************
changed: [192.168.0.9]
[WARNING]: Consider using file module with state=absent rather than running rm
PLAY RECAP *********************************************************************
192.168.0.9 : ok=5 changed=3 unreachable=0 failed=0
最后來介紹下playbook的循環和條件執行方法:
通常一個任務會做很多事情。如創建大量的用戶和文件。安裝很多包等。通過with_items方法可以幫助我們循環執行任務。參考下面的例子:
command: chdir=/home/zhf touch {{ item }}.txt 這句中的item來自與with_items中的變量分別是test4和test5
root@zhf-linux:/home/zhf/zhf/python_prj/auto_manintance# cat test2.yml
---
- hosts: webservers
remote_user: root
tasks:
- name: create file by batch
command: chdir=/home/zhf touch {{ item }}.txt
with_items:
- test4
- test5
這個示例與下面是等價的:
- name: create file by batch
command: chdir=/home/zhf touch test4.txt
- name: create file by batch
command: chdir=/home/zhf touch test5.txt
另外還可以嵌套循環:
- name: create file by batch
command: chdir=/home/zhf touch {{ item[0] }}.txt rm {{ item[1] }}
with_nested:
- [‘test3’,’test4’]
- [‘test5’]
對哈希使用循環:
假如你有以下變量:
--- users: alice: name: Alice Appleworth telephone: 123-456-7890 bob: name: Bob Bananarama telephone: 987-654-3210
你想打印出每個用戶的名稱和電話號碼.你可以使用 with_dict
來循環哈希表中的元素:
tasks: - name: Print phone records debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }})" with_dict: "{{users}}"
對文件列表使用循環:
--- - hosts: all tasks: # first ensure our target directory exists - file: dest=/etc/fooapp state=directory # copy each file over that matches the given pattern - copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600 with_fileglob: - /playbooks/files/fooapp/* 其他循環方式可以參考:http://ansible-tran.readthedocs.io/en/latest/docs/playbooks_loops.html#looping-over-hashes