1、Playbook的介紹php
Playbook是Ansible的配置,部署,編排語言。他們能夠被描述爲一個須要但願遠程主機執行命令的方案,或者一組IT程序運行的命令集合。mysql
當執行一些簡單的改動時ansible命令是很是有用的,然而它真的做用在於它的腳本能力。當對一臺機器作環境初始化的時候每每須要不止作一件事情,這時使用playbook會更加適合。經過playbook你能夠一次在多臺機器執行多個指令。經過這種預先設計的配置保持了機器的配置統一,並很簡單的執行平常任務。linux
Playbook還開創了不少特性,它能夠容許你傳輸某個命令的狀態到後面的指令,如你能夠從一臺機器的文件中抓取內容並附爲變量,而後在另外一臺機器中使用,這使得你能夠實現一些複雜的部署機制,這是ansible命令沒法實現的。nginx
2、YAML介紹web
Ansible使用標準的YAML解析器,使用YAML文件語法便可書寫playbook。sql
YAML是一個可讀性高的用來表達資料序列的格式,YAML參考了其餘多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。Clark Evans在2001首次發表了這種語言。shell
Playbook組成結構apache
Inventory #定義管理主機(清單文件)centos
Modules #定義模塊安全
Ad Hot Commands
Playbooks
Variables #變量元素,可傳遞給Tasks/Templates使用;
Tasks #任務元素,即調用模塊完成任務;
Templates #模板元素,可根據變量動態生成配置文件;
Hadlers #處理器元素,一般指在某條件知足時觸發的操做;
Roles #角色元素
執行一個Playbook
使用Playbook時經過ansible-playbook命令使用,它的參數和ansible命令相似,如參數-k(–ask-pass) 和-K (–ask-sudo) 來詢問ssh密碼和sudo密碼,-u指定用戶,這些指令也能夠經過規定的單元寫在playbook裏。ansible-playbook的簡單使用方法:
ansible-playbook /etc/ansible/roles/sites.yml
也能夠並行執行playbook,這裏的示例是並行的運行playbook,並行的級別是10個進程:
ansible-playbook /etc/ansible/roles/sites.yml -f 10
playbook的寫法例子:
分別講解playbook語言的多個特性:
2、Playbook基礎組件
主機(hosts)和用戶(users)
Playbook中的每個play的目的都是爲了讓某個或某些主機以某個指定的用戶的身份執行任務,hosts用於指定要執行任務的主機,其能夠是一個或者多個有冒號分割主機組,這和前面的ansible命令提到的hosts使用同樣的語法,remote_user則用於指定遠程主機上的執行任務的用戶,如上面實例中:
不過,remote_user也能夠用於task中:
- hosts: web
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
也能夠經過指定其經過sudo的方式遠程主機上執行任務,其可用於play全局或某task,此外,甚至能夠在sudo時使用sudo_user指定sudo時切換的用戶。
- hosts: web
remote_user: root
sudo:yes
sudo_user:yourname
若是須要在使用sudo時指定密碼,可在運行ansible-playbook命令時加上--ask-sudo-pass(-K).若是使用sudo時,playbook疑似被掛起,多是在sudo prompt處被卡主了,這時可執行Control-C殺死卡住的任務,從新運行一次。
Tasks列表
play的主體部分是task列表,task列表中的各任務按次序逐個在hosts中指定的主機上執行,即在全部主機上完成第一個任務後再開始第二個任務,在運行playbook時(從上到下執行),若是一個hosts執行task失敗,這個host將會從整個playbook的rotation中移除,若是發生執行失敗的狀況,請修正playbook中的錯誤,而後從新執行便可。
Task的目的是使用指定的參數執行模塊,而在模塊參數中可使用變量,模塊執行是冪等的,這意味着屢次執行是安全的,由於其結果一致。
對於command 模塊和shell 模塊,重複執行playbook,其實是重複運行一樣的命令。若是執行的命令相似於‘chmod’或者‘setsebool’這種命令,這沒有任何問題,也可使用一個叫作‘creates’的flag使得這兩個module變得具備‘冪等’特性(不是必要的。)
每個task必須有一個名稱name,這樣在運行playbook時,從其輸出的任務信息中能夠很好的辨別出是屬於哪個task的,若是沒有定義name,‘action’的值將會用做輸出信息中的標記特定的task。
定義一個task,之前有一種格式:‘action:module options’ (可能在一些老的playbook中還能見到),如今推薦使用常見的格式:「module:options」,本文檔使用的就是這種格式。
- hosts: web
vars: #定義變量
http_port: 80
max_client: 200 #定義變量是使用兩個花括號括起來,中間最好有空格,{{ http_port }}
remote_user: root
task:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
意思是:針對web組執行一個task使用root用戶執行,而這個task任務是「ensure apache is at the latest version」,而後調用yum模塊進行httpd的檢測,這裏的模塊參數的含義都跟前面說的經常使用模塊介紹時是同樣的,詳情查看前面的經常使用模塊介紹
在衆多模塊中,只有command和shell模塊僅須要給定一個列表無需使用key-value格式,例如:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
在使用command和shell模塊時,咱們須要關心返回碼信息,若是有一條命令,它的成功執行的返回碼不是0(ansible會終止運行),咱們可使用以下方式替代,強制返回成功:
tasks:
- name: run this command and ignore the result
shell: /usr/sbin/somecommand || /bin/true
或者使用ignore_error來忽略錯誤信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
變量(variables)和模板(template)
在Playbook中能夠直接定義變量(固然前面咱們也在inventory中添加變量),以下所示:
- hosts: web
vars:
- package:httpd
其中vars是固定格式,而package就是變量名,httpd就是變量值。
定義變量名的時候注意一些規範,變量名能夠是字母、下劃線、數字,但必須是以字母開頭,變量名包含中線、空格、點和以數字開頭的變量名都是不規範的。
對於定義好的變量能夠在task或者template中使用,但通常playbook中定義的變量都是給模板使用的,Ansible使用jijia2模板框架,這個後面講,如今只須要知道變量能夠在task和template中使用便可,以下在task中調用變量:
tasks:
- name: ensure apache is at the lastest version
yum: name={{ package }} state=latest
在task或template中引用變量都是使用雙花括號,中間引入變量名便可,如:{{ VAR_NAME }}.
另外說明,在playbook中調用的變量不只僅是在play中自定義的變量,也能夠是ansible中所定義的全部變量,好比說在ansible中有一個setup模塊,就是用來獲取客戶端全部的信息,如內存、CPU、IP、主機名、磁盤等信息,這些信息都是key-value格式的,每當咱們執行playbook時首先會須要執行setup模塊,也就意味着task或template中引用setup模塊輸出的變量。如:ansible_all_ipv4_addresses均可以在task或者template使用{{}}去引用。
引用變量的方法除了上述的方式外,還能夠在hosts中定義變量,此外還能夠在命令行使用ansible-playbook -e 指定變量 playbook.yml,例如:
ansible-playbook -e http_port=80 ceshi.yml
最後能夠在roles中定義變量
Handlers和notify
Handlers其實挺好理解的就是發生改變時執行提早定義好的操做。
上面咱們提到過,模塊具備冪等性,因此當遠端系統被人改動時,能夠重放playbook達到恢復的目的,playbook自己能夠識別這種改動,而且有一個基本的event system(系統事件),能夠響應這種改動。
(當發生改動時)'notify' 動做會在playbook的每個task結束時被觸發,並且即便有多個不一樣的task通知改動的發生'notify' 動做只會觸發一次。
這裏有一個例子,當一個文件的內容被改動時,重啓兩個services:
- name: write the apache config file
copy: src=/srv/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
"notify"下列出的便是handlers。
handlers也是一些task的列表,經過名字來引用,它們和通常的task並無什麼區別,Handlers是由通知者進行notify,若是沒有被notify,handlers不會執行,無論有多少個通知者進行了notify,等到play中的全部task執行完成以後,handlers也只會被執行一次。
這裏是一個handlers的示例:
handlers:
- name: restart apache #這裏和notify保持一致
service: name=httpd state=restarted
下面給一個安裝服務而後使用Handlers的例子:
- hosts:web
remote_user:root
task:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
copy: src=/srv/httpd.conf dest=/etc/httpd/conf/httpd.conf
- name: ensure apache is running
service: name=httpd state=started
這個play就作了三個task,第一是檢測httpd是不是最新版,若是不是就進行安裝,第二就是從服務器copy一份定義好的配置文件到目標主機;第三就是啓動httpd服務器。
首先須要在ansible服務器上提供一個/srv/httpd.conf配置文件,否則執行時就會報錯,而後使用ansible-playbook執行。
ansible-playbook sites.yml
若是修改了配置文件,是否是須要reload或restart後你的配置文件才能生效。可是上面的配置就算你改完 配置文件再次執行playbook,配置文件雖然過去了,可是ansible冪等性,配置文件是沒法生效的,而handlers就是爲了解決此類問題而生的,咱們能夠給copy文件的那個task定義一個handlers,一旦由配置文件改動就調用提早定義的handlers進行處理,以下:
- hosts: test
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
copy: src=/srv/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
這個時候再次修改配置文件而後執行playbook,當執行到第二個任務後檢測到定義了notify,當整個play的task都執行完畢後,就會找handlers,匹配到名稱後就會執行對應的模塊。
注意:notify定義的restart httpd 必須與handlers定義的name名稱相同,否則會報:not found in any of the known handlers
Register
常常在playbook中,存儲某個命令的結果在變量中,以備往後訪問是頗有用的,而‘register’就是用來決定把結果存儲在哪一個變量中,結果參數能夠用在模板中,動做條目,或者when語句,像下面的例子:
- name: test play
hosts: all
tasks:
- shell: cat /etc/motd
register: motd_contents
- shell: echo "motd contains the word hi"
when: motd_contents.stdout.find('hi') != -1
就像上面展現的那樣,這個註冊後的參數的內容爲字符串’stdout’是能夠訪問。這個註冊了之後的結果,若是像上面展現的,能夠轉化爲一個list(或者已是一個list),就能夠在任務中的」with_items」中使用,「stdout_lines」在對象中已經能夠訪問了,固然若是你喜歡也能夠調用「home_dirs.stdout.split()」 , 也能夠用其它字段切割:
- name: registered variable usage as a with_items list
hosts: all
tasks:
- name: retrieve the list of home directories
command: ls /home
register: home_dirs
- name: add home dirs to the backup spooler
file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
with_items: home_dirs.stdout_lines
# same as with_items: home_dirs.stdout.split()
提示與技巧:
在playbook執行輸出信息的底部,能夠找到關於託管節點的信息。
其中:
ok:表示執行成功但沒作過任何變更的任務;
changed:表示執行成功但作過變更的任務;
unreachable:表示沒法到達的任務;
failed:表示執行失敗的任務。
若是你想看到執行成功的模塊輸出信息,使用--verbose便可,(不然只有執行失敗的纔會由輸出信息)
ansible-playbook paaybook.yml --verbose
若是安裝了cowsay軟件包,ansible playbook的輸出已經進行普遍的升級,能夠嘗試一下!
在執行一個playbook以前,想看看這個playbook的執行會影響到哪些hosts,你能夠這樣作:
ansible-playbook paybook.yml --list-hosts
在執行一個playbook以前,想看看這個playbook是否有語法錯誤,能夠這樣作:
ansible-playbook -C playbook.yml 或
ansible-playbook playbook.yml --check 這樣不會執行結果,只會查看playbook是否有語法錯誤。
3、Playbook的其它特性
條件測試
若是須要根據變量、facts(setup)或此前任務的執行結果來做爲某task執行與否的前提時要用到條件測試,在Playbook中條件測試使用when子句,在task後添加when子句便可使用條件測試:when子句支持jinjia2表達式或句法,例如:
tasks:
- name: "shutdown Debian"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"
或者多條件判斷:
tasks:
- name: 「shutdown Centos6 system」
command: /sbin/shutdown -t now
when:
- ansible_distribution == "Centos"
- ansible_distribution_major_version == "6"
意思就是若是對方的系統是centos而且版本是6就進行關機處理,ansible_os_family這個變量是從facts中提取的。
也可使用組名條件判斷:
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or
(ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
再如:
- host: web
remote_user: root
vars:
- http_port: 80
tasks:
- name: install package
yum: name=nginx
- name: copy template for centos7
template: src=/etc/ansible/httpd.conf dest=/etc/httpd/conf/httpd.conf #template通常在playbook.yml同級目錄中建立一個templates目錄,這樣的話在這裏就能夠直接寫文件template文件名不用再添加路徑,固然若是沒有template目錄的話這裏也能夠寫template文件所在的絕對路徑。
when: ansible_distribution_major_version == "7"
notify: restart service
- name: copy template for centos6
template: src=/etc/ansible/httpd.conf6.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "6"
notify: restart service
- name: start service
service: name=httpd state=started enabled=yes
handlers:
- name: restart service
service: name=httpd state=restarted
另外也能夠自定義變量,當值爲某某時執行什麼動做,以下:
- hosts: all
vars:
exist: "True"
tasks:
- name: creaet file
command: touch /tmp/test.txt
when: exist | match("True")
- name: delete file
command: rm -rf /tmp/test.txt
when: exist | match("False")
意思是,當exist變量值爲True時就建立文件,當值爲False時就刪除文件。
迭代:
當有須要重複性執行的任務時,可使用迭代機制,其使用格式爲:"將須要迭代的內容定義爲item變量引用,並經過with_items語句指明迭代的元素列表便可",例如:
tasks:
- name: "Install Packages"
yum: name={{ item }} state=latest
with_items:
- httpd
- mysql-server
- php
事實上,with_items中可使用元素還能夠爲hashes,例如添加用戶和組:
tasks:
- name: "Add users"
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name:'test1', groups:'wheel'}
- { name:'test2', groups:'root'}
其中引用變量時前綴item變量是固定的,而item後跟的鍵名就是在with_items中定義的字典鍵名。
迭代功能在作批量處理時很是有用,好比系統初始化時通常要安裝不少初始化的包就可使用迭代了。
更多功能查看官網。
tags
在一個playbook中,咱們通常會定義不少個task,若是咱們只想執行某個task或多個task時就可使用tags標籤功能了,格式以下:
cat ceshi.yml
- hosts: web
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
tags:
- hosts
handlers:
- name: restart apache
service: name=httpd state=restarted
爲複製hosts文件定義了一個tags,tags爲hosts。那麼在執行此playbook時可經過ansible-playbook命令使用–tags選項能實現僅運行指定的tasks而非全部的,以下:
查看tags
事實上,不光能夠爲單個或多個task指定同一個tags。playbook還提供了一個特殊的tags爲always。做用就是當使用always當tags的task時,不管執行哪個tags時,定義有always的tags都會執行。
cat ceshi.yml
- hosts: web
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
tags:
- copy
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
tags:
- always
handlers:
- name: restart apache
service: name=httpd state=restarted
當你瞭解了Playbook的以上基礎知識後基本可使用playbook來編排一些自動化任務了,上面介紹了playbook的Host、user、task、variables、template等基本組成元素的使用,以及條件測試、迭代、tags等特性,下面就開始介紹playbook中很是重要的一個概念roles,另外對於playbook的template元素,不光能夠簡單的調用變量,而且支持各類操做符,在使用playbook時,模板也是一個不可或缺的功能。
ansible-playbook的shell模塊中的管道符‘|’的使用方法
ansibl下的
- name: Run expect to wait for a successful PXE boot via out-of-band CIMC
shell: | #在另外一個解釋器下執行
set timeout 300
spawn ssh admin@{{ cimc_host }}
expect "password:"
send "{{ cimc_password }}\n"
expect "\n{{ cimc_name }}"
send "connect host\n"
expect "pxeboot.n12"
send "\n"
exit 0
args:
executable: /usr/bin/expect
delegate_to: localhost