自動化運維Ansible之Playbook劇本(持續更新)
自動化運維之Ansible概述及Ansible部署
Ansible命令應用之常用模塊
Playbook簡介
playbook是ansible用於配置,部署,和管理被控節點的劇本。
通過playbook的詳細描述,執行其中的一系列tasks,可以讓遠端主機達到預期的狀態。playbook就像Ansible控制器給被控節點列出的的一系列to-do-list,而被控節點必須要完成。
也可以這麽理解,playbook 字面意思,即劇本,現實中由演員按照劇本表演,在Ansible中,這次由計算機進行表演,由計算機安裝,部署應用,提供對外服務,以及組織計算機處理各種各樣的事情。
Playbook的使用場景
執行一些簡單的任務,使用ad-hoc命令可以方便的解決問題,但是有時一個設施過於復雜,需要大量的操作時候,執行的ad-hoc命令是不適合的,這時最好使用playbook。
就像執行shell命令與寫shell腳本一樣,也可以理解為批處理任務,不過playbook有自己的語法格式。
使用playbook你可以方便的重用這些代碼,可以移植到不同的機器上面,像函數一樣,最大化的利用代碼。在你使用Ansible的過程中,你也會發現,你所處理的大部分操作都是編寫playbook。可以把常見的應用都編寫成playbook,之後管理服務器會變得十分簡單。
Playbook格式介紹
playbook由YMAL語言編寫。YAML( /?j?m?l/ )參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822,Clark Evans在2001年5月在首次發表了這種語言,另外Ingy d?t Net與Oren Ben-Kiki也是這語言的共同設計者。
YMAL格式是類似於JSON的文件格式,便於人理解和閱讀,同時便於書寫。首先學習了解一下YMAL的格式,對我們後面書寫playbook很有幫助。以下為playbook常用到的YMAL格式。
文件的第一行應該以 ”—” (三個連字符)開始,表明YMAL文件的開始。
在同一行中,#之後的內容表示註釋,類似於shell,python和ruby。
- apple - banana - orange等價於JSON的這種格式
[ “apple”, “banana”, “orange” ]
同一個列表中的元素應該保持相同的縮進。否則會被當做錯誤處理。
Playbook本身由以下各部分組成:
- Tasks:任務,即調用模板完成某操作;
- Variables:變量;
- Templates:模板;
- Handlers:處理器,當某條件滿足時,觸發執行的操作;
- Roles:角色。
playbook中hosts,variables,roles,tasks等對象的表示方法都是鍵值中間以”:”分隔表示,”:”後面還要增加一個空格。
house:
family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] }
address: { number: 34, street: Main Street, city: Nowheretown, zipcode: 12345 }
Ansible-playbook執行playbook文件
使用ansible-playbook運行playbook文件,得到如下輸出信息,輸出內容為JSON格式。並且由不同顏色組成,便於識別。一般而言
| 綠色代表執行成功,系統保持原樣
| ×××代表系統代表系統狀態發生改變
| 紅色代表執行失敗,顯示錯誤輸出。
執行有三個步驟:1、收集facts 2、執行tasks 3、報告結果
[root@CentOS7-master ~]# ansible-playbook mariadb.yml
---------------------------1、收集facts------------------------------------------
PLAY [webservers] **************************************************************
TASK [setup] *******************************************************************
ok: [172.17.254.165]
ok: [172.17.254.180]
---------------------------2、執行tasks------------------------------------------
TASK [Install mariadb-server package] ******************************************
changed: [172.17.254.165]
changed: [172.17.254.180]
TASK [Starting mysqld service] *************************************************
changed: [172.17.254.165]
changed: [172.17.254.180]
---------------------------3、報告結果-------------------------------------------
PLAY RECAP *********************************************************************
172.17.254.165 : ok=3 changed=2 unreachable=0 failed=0
172.17.254.180 : ok=3 changed=2 unreachable=0 failed=0
Playbook的基礎組件
1.Hosts和Users
Playbook的設計目的是為了讓某個或某些主機以某個用戶的身份去執行相應的任務。其中用於指定要執行指定任務的主機用hosts定義,可以是一個主機也可以是由冒號分隔的多個主機組;用於指定被管理主機上執行任務的用戶用remote_user來定義。
remote_user也可定義指定用戶通過sudo的方法在被管理主機上運行指令,甚至可以在使用sudo時用sudo_user指定sudo切換的用戶。
Hosts:運行指定任務的目標主機;
remoute_user: 在遠程主機上執行任務的用戶;
sudo_user:指定sudo切換的用戶
tasks:任務列表
模塊,模塊參數;
格式:
(1) action: module arguments
(2) module: arguments
2.任務列表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
或者是這樣:
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 中也是可用的,稍後會講到。
3.Handlers
Handlers用於當關註的資源發生變化時所采取的操作。在notify中列出的操作便稱為handler,也就是在notify中需要調用handler中定義的操作。而notify這個動作在每個play的最後被觸發,僅在所有的變化發生完成後一次性的執行指定操作。
tasks:
– name: TASK_NAME
module: arguments
notify: HANDLER_NAME
handlers:
– name: HANDLER_NAME
module: arguments
這裏是一個handlers的示例:
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
handler也是task列表格式,如:
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
簡單示例如下:
[root@CentOS7-master ~]# vim mariadb.yml
- hosts: webservers
remote_user: root
tasks:
- name: Install mariadb-server package
yum: name=mariadb-server state=present
- name: copy my.cnf
copy: src=/etc/my.cnf dest=/etc/ backup=yes
notify: start
tags: startmariadb
- name: Stopping mysqld service
service: name=mariadb state=stopped
tags: stopmariadb
handlers:
- name: start
service: name=mariadb state=started
4.Variables:
(1) facts:可直接調用;
註意:可使用setup模塊直接獲取目標主機的facters;
(2) 用戶自定義變量:
(a) ansible-playbook命令的命令行中的
-e VARS, --extra-vars=VARS
(b) 在playbook中定義變量的方法:
vars:
- var1: value1
- - var2: value2
(3) 通過roles傳遞變量;
(4) Host Inventory
(a) 用戶自定義變量
(i) 向不同的主機傳遞不同的變量;
IP/HOSTNAME varaiable=value var2=value2
(ii) 向組中的主機傳遞相同的變量;
[groupname:vars]
variable=value
eg:
[web]
172.17.251.188
172.17.250.209
[web:vars]
rpmname=samba
5.Templates
Jinja是基於Python的模板引擎。Template類是Jinja的另一個重要組件,可以看作是一個編譯過的模板文件,用來產生目標文本,傳遞Python的變量給模板去替換模板中的標記。
Jinja:Jinja2是python的一種模板語言,以Django的模板語言為原本。 Jinja文件的創建可以直接將自己創建好的文本文件的後綴改成以“.j2”結尾的即可! 下面用到的nginx.conf.j2文件就是將nginx.conf文件修改好後將其重命名為nginx.conf.j2的! 支持: 字符串:使用單引號或雙引號; 數字:整數,浮點數; 列表:[item1, item2, ...] 元組:(item1, item2, ...) 字典:{key1:value1, key2:value2, ...} 布爾型:true/false 算術運算: +, -, *, /, //, %, ** 比較操作: ==, !=, >, >=, <, <= 邏輯運算: and, or, not
示例:
[root@CentOS7-master ~]# vim nginx.yml
- hosts: webservers
remote_user: root
vars:
- rpmname: nginx
nginxport: 8888
tasks:
- name: yum install {{ rpmname }}
yum: name={{ rpmname }} state=present
- name: copy {{ rpmname }}.conf
template: src=/tmp/{{ rpmname }}.conf.j2 dest=/etc/nginx/{{ rpmname }}.c
onf backup=yes
notify: reload
tags: reload{{ rpmname }}
- name: start service
service: name={{ rpmname }} state=started
tags: start{{ rpmname }}
handlers:
- name: reload
service: name={{ rpmname }} state=restarted
模板配置文件:
[root@CentOS7-master ~]# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.j2
[root@CentOS7-master ~]# vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};
listen {{ http_port }};
6.Tags
如果多次執行修改Playbook會涉及到一些沒有變化的代碼,可以使用tags讓用戶選擇跳過沒有變化的代碼,只運行Playbook中發生變化的部分代碼。可以在Playbook中為某個或某些任務定義“標簽”,在執行此Playbook時通過ansible-playbook命令使用--tags選項能實現僅運行指定的tasks。
簡單示例如下:
[root@CentOS7-master ~]# vi hosts.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: Copy hosts file
copy: src=/etc/hosts dest=/etc/hosts
tags:
- only
- name: touch file
file: path=/opt/hosts state=touch
分別執行ansible-playbook hosts.yml --tags="only"和ansible-playbook hosts.yml可以發現,有--tags="only"的命令只運行了Copy hosts file部分。
事實上,不光可以為單個或多個task指定同一個tags。playbook還提供了一個特殊的tags為always。作用就是當使用always當tags的task時,無論執行哪一個tags時,定義有always的tags都會執行。
vi hosts.yml
---
- hosts: webserver
remote_user: root
tasks:
- name: Copy hosts file
copy: src=/etc/hosts dest=/etc/hosts
tags:
- only
- name: touch file
file: path=/opt/hosts state=touch
tags:
- always
自動化運維Ansible之Playbook劇本(持續更新)