Playbooks 介紹¶
Playbooks 簡介¶
Playbooks 與 adhoc 相比,是一種完全不同的運用 ansible 的方式,是非常之強大的.
簡單來說,playbooks 是一種簡單的配置管理系統與多機器部署系統的基礎.與現有的其他系統有不同之處,且非常適合於複雜應用的部署.
Playbooks 可用於聲明配置,更強大的地方在於,在 playbooks 中可以編排有序的執行過程,甚至於做到在多組機器間,來回有序的執行特別指定的步驟.並且可以同步或非同步的發起任務.
我們使用 adhoc 時,主要是使用 /usr/bin/ansible 程式執行任務.而使用 playbooks 時,更多是將之放入源碼控制之中,用之推送你的配置或是用於確認你的遠端系統的配置是否符合配置規範.
在如右的連線中: ansible-examples repository ,有一些整套的playbooks,它們闡明瞭上述的這些技巧.我們建議你在另一個標籤頁中開啟它看看,配合本章節一起看.
即便學完 playbooks 這個章節,仍有許多知識點只是入門的級別,完成本章的學習後,可回到文件索引繼續學習.
Playbook 語言的示例¶
Playbooks 的格式是YAML(詳見:YAML 語法),語法做到最小化,意在避免 playbooks 成為一種程式語言或是指令碼,但它也並不是一個配置模型或過程的模型.
playbook 由一個或多個 ‘plays’ 組成.它的內容是一個以 ‘plays’ 為元素的列表.
在 play 之中,一組機器被對映為定義好的角色.在 ansible 中,play 的內容,被稱為 tasks,即任務.在基本層次的應用中,一個任務是一個對 ansible 模組的呼叫,這在前面章節學習過.
‘plays’ 好似音符,playbook 好似由 ‘plays’ 構成的曲譜,通過 playbook,可以編排步驟進行多機器的部署,比如在 webservers 組的所有機器上執行一定的步驟, 然後在 database server 組執行一些步驟,最後回到 webservers 組,再執行一些步驟,諸如此類.
“plays” 算是一個體育方面的類比,你可以通過多個 plays 告訴你的系統做不同的事情,不僅是定義一種特定的狀態或模型.你可以在不同時間執行不同的 plays.
對初學者,這裡有一個 playbook,其中僅包含一個 play:
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=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
handlers:
- name: restart apache
service: name=httpd state=restarted
在下面,我們將分別講解 playbook 語言的多個特性.
playbook基礎¶
主機與使用者¶
你可以為 playbook 中的每一個 play,個別地選擇操作的目標機器是哪些,以哪個使用者身份去完成要執行的步驟(called tasks).
- hosts 行的內容是一個或多個組或主機的 patterns,以逗號為分隔符,詳見 Patterns 章節.
remote_user 就是賬戶名:
--- - hosts: webservers remote_user: root
Note
參數 remote_user 以前寫做 user,在 Ansible 1.4 以後才改為 remote_user.主要為了不跟 user 模組混淆(user 模組用於在遠端系統上建立使用者).
再者,在每一個 task 中,可以定義自己的遠端使用者:
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
Note
task 中的 remote_user 參數在 1.4 版本以後新增.
也支援從 sudo 執行命令:
---
- hosts: webservers
remote_user: yourname
sudo: yes
同樣的,你可以僅在一個 task 中,使用 sudo 執行命令,而不是在整個 play 中使用 sudo:
---
- hosts: webservers
remote_user: yourname
tasks:
- service: name=nginx state=started
sudo: yes
你也可以登陸後,sudo 到不同的使用者身份,而不是使用 root:
---
- hosts: webservers
remote_user: yourname
sudo: yes
sudo_user: postgres
如果你需要在使用 sudo 時指定密碼,可在執行 ansible-playbook 命令時加上選項 --ask-sudo-pass
(-K).
如果使用 sudo 時,playbook 疑似被掛起,可能是在 sudo prompt 處被卡住,這時可執行 Control-C 殺死卡住的任務,再重新執行一次.
Important
當使用 sudo_user 切換到 非root 使用者時,模組的參數會暫時寫入 /tmp 目錄下的一個隨機臨時檔案. 當命令執行結束後,臨時檔案立即刪除.這種情況發生在普通使用者的切換時,比如從 ‘bob’ 切換到 ‘timmy’, 切換到 root 賬戶時,不會發生,如從 ‘bob’ 切換到 ‘root’,直接以普通使用者或root身份登入也不會發生. 如果你不希望這些資料在短暫的時間內可以被讀取(不可寫),請避免在 sudo_user 中傳遞未加密的密碼. 其他情況下,’/tmp’ 目錄不被使用,這種情況不會發生.Ansible 也有意識的在日誌中不記錄密碼參數.
Tasks 列表¶
每一個 play 包含了一個 task 列表(任務列表).一個 task 在其所對應的所有主機上(通過 host pattern 匹配的所有主機)執行完畢之後,下一個 task 才會執行.有一點需要明白的是(很重要),在一個 play 之中,所有 hosts 會獲取相同的任務指令,這是 play 的一個目的所在,也就是將一組選出的 hosts 對映到 task.(注:此處翻譯未必準確,暫時保留原文)
在執行 playbook 時(從上到下執行),如果一個 host 執行 task 失敗,這個 host 將會從整個 playbook 的 rotation 中移除. 如果發生執行失敗的情況,請修正 playbook 中的錯誤,然後重新執行即可.
每個 task 的目標在於執行一個 moudle, 通常是帶有特定的參數來執行.在參數中可以使用變數(variables).
modules 具有”冪等”性,意思是如果你再一次地執行 moudle(譯者注:比如遇到遠端系統被意外改動,需要恢復原狀),moudle 只會執行必要的改動,只會改變需要改變的地方.所以重複多次執行 playbook 也很安全.
對於 command module 和 shell module,重複執行 playbook,實際上是重複運行同樣的命令.如果執行的命令類似於 ‘chmod’ 或者 ‘setsebool’ 這種命令,這沒有任何問題.也可以使用一個叫做 ‘creates’ 的 flag 使得這兩個 module 變得具有”冪等”特性 (不是必要的).
每一個 task 必須有一個名稱 name,這樣在執行 playbook 時,從其輸出的任務執行資訊中可以很好的辨別出是屬於哪一個 task 的. 如果沒有定義 name,‘action’ 的值將會用作輸出資訊中標記特定的 task.
如果要聲明一個 task,以前有一種格式: “action: module options” (可能在一些老的 playbooks 中還能見到).現在推薦使用更常見的格式:”module: options” ,本文件使用的就是這種格式.
下面是一種基本的 task 的定義,service moudle 使用 key=value 格式的參數,這也是大多數 module 使用的參數格式:
tasks:
- name: make sure apache is running
service: name=httpd state=running
比較特別的兩個 modudle 是 command 和 shell ,它們不使用 key=value 格式的參數,而是這樣:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
使用 command module 和 shell module 時,我們需要關心返回碼資訊,如果有一條命令,它的成功執行的返回碼不是0, 你或許希望這樣做:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者是這樣:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
如果 action 行看起來太長,你可以使用 space(空格) 或者 indent(縮排) 隔開連續的一行:
tasks:
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
在 action 行中可以使用變數.假設在 ‘vars’ 那裡定義了一個變數 ‘vhost’ ,可以這樣使用它:
tasks:
- name: create a virtual host file for {{ vhost }}
template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
這些變數在 tempates 中也是可用的,稍後會講到.
在一個基礎的 playbook 中,所有的 task 都是在一個 play 中列出,稍後將介紹一種更合理的安排 task 的方式:使用 ‘include:’ 指令.
Action Shorthand¶
New in version 0.8.
在 0.8 及以後的版本中,ansible 更喜歡使用如下的格式列出 modules:
template: src=templates/foo.j2 dest=/etc/foo.conf
在早期的版本中,使用以下的格式:
action: template src=templates/foo.j2 dest=/etc/foo.conf
早期的格式在新版本中仍然可用,並且沒有計劃將這種舊的格式棄用.
Handlers: 在發生改變時執行的操作¶
上面我們曾提到過,module 具有”冪等”性,所以當遠端系統被人改動時,可以重放 playbooks 達到恢復的目的. playbooks 本身可以識別這種改動,並且有一個基本的 event system(事件系統),可以響應這種改動.
(當發生改動時)’notify’ actions 會在 playbook 的每一個 task 結束時被觸發,而且即使有多個不同的 task 通知改動的發生, ‘notify’ actions 只會被觸發一次.
舉例來說,比如多個 resources 指出因為一個配置檔案被改動,所以 apache 需要重新啟動,但是重新啟動的操作只會被執行一次.
這裡有一個例子,當一個檔案的內容被改動時,重啟兩個 services:
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
‘notify’ 下列出的即是 handlers.
Handlers 也是一些 task 的列表,通過名字來引用,它們和一般的 task 並沒有什麼區別.Handlers 是由通知者進行 notify, 如果沒有被 notify,handlers 不會執行.不管有多少個通知者進行了 notify,等到 play 中的所有 task 執行完成之後,handlers 也只會被執行一次.
這裡是一個 handlers 的示例:
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
Handlers 最佳的應用場景是用來重啟服務,或者觸發系統重啟操作.除此以外很少用到了.
Note
handlers 會按照聲明的順序執行
Roles 將在下一章節講述.值得指出的是,handlers 會在 ‘pre_tasks’, ‘roles’, ‘tasks’, 和 ‘post_tasks’ 之間自動執行. 如果你想立即執行所有的 handler 命令,在1.2及以後的版本,你可以這樣做:
tasks:
- shell: some tasks go here
- meta: flush_handlers
- shell: some other tasks
在以上的例子中,任何在排隊等候的 handlers 會在執行到 ‘meta’ 部分時,優先執行.這個技巧在有些時候也能派上用場.
執行一個 playbook¶
既然現在你已經學習了 playbook 的語法,那要如何執行一個 playbook 呢?這很簡單,這裡的示例是並行的執行 playbook,並行的級別 是10(譯者注:是10個併發的程序?):
ansible-playbook playbook.yml -f 10
Ansible-Pull(拉取配置而非推送配置)¶
我們可不可以將 ansible 的體系架構顛倒過來,讓託管節點從一個 central location 做 check in 獲取配置資訊,而不是 推送配置資訊到所有的託管節點?是可以的.
Ansible-pull 是一個小指令碼,它從 git 上 checkout 一個關於配置指令的 repo,然後以這個配置指令來執行 ansible-playbook.
假設你對你的 checkout location 做負載均衡,ansible-pull 基本上可以無限的提升規模.
可執行 ansible-pull --help
獲取詳細的幫助資訊.
也有一個叫做 clever playbook 的東西: clever playbook . 這個可以通過 crontab 來配置 ansible-pull(from push mode).
提示與技巧¶
在 playbook 執行輸出資訊的底部,可以找到關於託管節點的資訊.也可看到一般的失敗資訊,和嚴重的 “unreachable” 資訊. 這兩個是分開計數的.
如果你想看到執行成功的 modules 的輸出資訊,使用 --verbose
flag(否則只有執行失敗的才會有輸出資訊).這在 0.5 及以後的版本中可用.
如果安裝了 cowsay 軟體包,ansible playbook 的輸出已經進行了廣泛的升級.可以嘗試一下!
在執行一個 playbook 之前,想看看這個 playbook 的執行會影響到哪些 hosts,你可以這樣做:
ansible-playbook playbook.yml --list-hosts
See also
- YAML 語法
- Learn about YAML syntax
- 最佳實踐
- Various tips about managing playbooks in the real world
- Ansible 文件
- Hop back to the documentation index for a lot of special topics about playbooks
- 模組相關
- Learn about available modules
- Developing Modules
- Learn how to extend Ansible by writing your own modules
- Patterns
- Learn about how to select hosts
- Github examples directory
- Complete end-to-end playbook examples
- Mailing List
- Questions? Help? Ideas? Stop by the list on Google Groups