ansible運維工具(二)
ansible playbook(二)
運行palybook時 要使用ansible-playbook命令
palybook執行任務的順序是,在第一個主機上完成第一個任務,然後在第二個主機上完成第一個任務
而不是在第一個主機上完成所有任務,然後再在第二個主機上完成所有任務,以任務為中心,在所有主機上執行
如何構建ansible的playbook
Inventory
Modules
Ad Hoc Commands
PlayBooks
Tasks 任務,及調用某模塊所完成的操作
Variable 變量
Templates 模版
Handlers 處理器,通常指的是在某條件滿足時觸發執行的操作
Roles 角色
如果想說清楚的playbooks,還要額外的了解一些基礎概念
Ansible中使用的YAML基礎元素:
變量
Inventory
條件判斷
叠代
基本結構
- hosts: websrvs
remote_user:
tasks:
- name: task1
module_name:
- name: task2
module_name:
- hosts: dbsrvs
簡單示例1:
- hosts: websrvs remote_user: root tasks: - name: create nginx group group: name=nginx system=yes gid=208 - name: create nginx user user: name=nginx uid=208 system=yes group=nginx - hosts: dbsrvs remote_user: root tasks: - name: copy file to dbsrvs copy: src=/etc/inittab dest=/tmp/inittab.ansible
簡單實例2:
- hosts: websrvs remote_user: root tasks: - name: install httpd packege yum: name=httpd state=latest - name: install configuration file for httpd copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf - name: start httpd service service: enabled=true name=httpd state=started
簡單實例3-handler:
當配置文件發生改變時,應該讓服務重啟。那麽重啟服務就要用handler,當這個服務發生變化時使用notify屬性通知要執行的handler裏定義的任務如下:
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd packege
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
~
簡單實例4-定義變量:
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd packege
yum: name={{ package }} state=latest
- name: install configuration file for httpd
copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
簡單示例5-使用facts變量:
- hosts: websrvs
remote_user: root
tasks:
- name: copy file
copy: content= "{{ ansible_all_ipv4_addresses }}" dest=/tmp/vars.ans
同樣在inventory 中為主機 或者主機組定義的變量也可以通過 {{ 變量名 }}直接調用。
簡單示例6-條件判斷語句when:
- hosts: all
remote_user: root
vars:
- username: user10
tasks:
- name: create {{ username }} user
user: name= {{username}}
when: ansible_fqdn == ‘node1.my.com‘
簡單示例7-叠代
重復執行同類task時使用
定義循環列表:with_items
- name: add serveral users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
要安裝多個程序包的時候使用很方便,定義yum
- apache
- php
- mysql-server
註意: with_item中的列表值也可以是字典
- name add serveral users
user: name= {{ itesm.name }} state=present groups= {{ item.groups }}
with_items:
- { name: ‘testuser1‘, groups: ‘wheel‘ }
- { name: ‘testuser2‘, groups: ‘root‘ }
比較是用的是,一個tasks下安裝程序包,定義配置文件就可以用yum,和copy
with_items:
- { name: apache, conf: conffiles/httpd.conf }
- { name: php, conf: conffiles/php.ini }
- { name: mysql-server, conf: conffiles/my.cnf }
模版template 的使用,常用於靜態配置文件中定義變量以及條件語句,一般在ansible中模版文件後綴名為.j2因為使用的是jinjia2模版語言。同時也要安裝python的jinjia2擴展包,對於我們來將最常用的就是變量。
使用舉例:
inventory中定義如下:
[websrvs]
172.16.100.7 http_port=80 maxClients=100
172.16.100.8 http_port=8080 maxClients=200
假如有一個配置文件中關於端口和maxClients配置項更改如下
Server Name {{ ansible_fqdn }}
Listen {{ http_port }}
maxClients {{ maxClients }}
一般都會創建一個名為templates/httpd.conf.j2
接著我們在playbooks就把之前使用copy模塊定義配置文件的地方改用template模塊,如下:
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd packege
yum: name={{ package }} state=latest
- name: install configuration file for httpd
template: src=/root/templates/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
tags的使用
我們前面定義的playbook中有多個tasks,如果我們想單獨運行這個playbook中的某一個task就需要通過tabs來實現。
- hosts: websrvs
remote_user: root
vars:
- package: httpd
- service: httpd
tasks:
- name: install httpd packege
yum: name={{ package }} state=latest
- name: install configuration file for httpd
template: src=/root/templates/httpd.conf dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
handlers:
- name: restart httpd
service: name={{ service }} state=restarted
使用下面命令,只運行tags為conf的任務
ansible-playbook apache.yml --tags=‘conf‘
當然可以--tage=‘aa,bb,cc‘指明多個tag
特殊tags
假如有的任務你想只要運行這個playbook(即使指定--tags)就需要執行這個task,那麽就可以使用
tags: always
以上內容就可以滿足我們對ansible的使用了,接來下了解角色的定義,讓我們更方便的使用ansible
我們想讓一批主機完成 一批任務就可以使用playbook進行配置執行。那麽我們想那為什麽還要有role角色這個東西的存在。存在的意義是什麽。這裏我們在playbook已經可以實現為一批主機執行一批任務了,為什麽還要有role角色這個玩意。 那好我們來舉個例子,假如一臺服務器上安裝nginx又安裝了php還安裝了mysql。那麽你可以寫一個playbook的yaml文件,但是我們現在又有一臺主機想只執行 nginx 和php,那麽你怎麽實現。當然可以再次更改playbook,為其添加一個play,但這違背了開發的盡量不寫重復代碼的宗旨。所以你實現的方式很low。那麽這時候你如果想,事先定義了三個角色,一個nginx,php,mysql 在應用到主機上就完美了,那就是roles。
roles的應用
ansible 自1.2版本引入的新特性,用於層次性、結構化地組織playbook,roles能夠根據層次型結構自動裝載變量文件、tasks以及handles等,要使用roles只需要在playbook中使用include指令即可,簡單來講,roles就是通過分別將變量、文件、任務、模塊及處理器放置於單獨的目錄中,並可以便捷地include他們的一種機制,角色一般用於基於主機的構建服務的場景中,但也可以適用於構建守護進程等場景中:
一個roles的案例如下所示:
site.yml
webservers.yml
fooservers.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
meta/
webservers/
files/
templates/
tasks/
handlers/
vars/
meta/
而在playbook中,也可以這樣使用roles:
...
- hosts: webservers
roles:
- common
- webservers
也可以向roles傳遞參數,例如:
...
- hosts: webservers
roles:
- common
- { role: foo_app_instance, dir: ‘/opt/a‘, port: 5000}
- { role: foo_app_instance, dir: ‘/opt/b‘, port: 5001}
設置也可以條件式地使用roles, 例如:
...
- hosts: webservers
roles:
- {role: some_role, when: "ansible_os_family == ‘redhat‘"}
8.1創建role的步驟
(1) 創建以roles命名的目錄;
(2) 在roles目錄中分別創建以各種角色名稱命名的目錄,如 webservers等;
(3) 在每一個角色命名的目錄中分別創建 files,handlers,meta, tasks,templates 和vars目錄:用不到的目錄可以創建為空目錄,也可以不創建;
(4) 在playbook文件中,調用各角色
8.2 role內各目錄匯總可用的文件
tasks目錄: 至少應該包含一個名為main.yml的文件,其定義來此角色的任務列表;此文件可以使用include包含其它的位於此目錄中的task文件;
files目錄: 存放又copy或script等模塊調用的文件;
templates目錄: template模塊會自動在此目錄中尋找jinjia2模版文件;
handlers目錄: 此目錄中應當包含一個mian.yml文件,用於定義此角色用到的handler,在handler中使用include包含的其它的handler文件也應該位於此目錄;
vars目錄:應當包含一個mian.yml文件,用於定義此角色用到的變量;
meta目錄:應當包含一個main.yml文件,用於定義此角色的特殊設定及其依賴關系,ansible 1.3及其以後的版本才支持;
default目錄: 為當前角色設定變量時使用此目錄,應當包含一個main.yml文件
示例:
1.創建roles目錄
mkdir /root/ansible_playbooks/roles
mkidr -pv /root/ansible_playbooks/roles/{webservers, dbservers}/{tasks, files, templates, handlers, vars, meta}
2. 把要用到的文件放到 files目錄下,把要用到的template文件放到 templates目錄下
3. 在tasks目錄中編輯main.yml
vim /root/ansible_playbooks/roles/webservers/tasks/main.yml
- name: install httpd packeg
yum: name=httpd
- name: install configuration file for httpd
template: src=httpd.conf dest=/etc/httpd/conf/httpd.conf
tags:
- conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name={{ service }} state=started
這裏指定模版文件的時候,就不用指定目錄來,它會自己去找角色目錄下的template目錄下的文件
4. 這裏我們用到了notify,也就是說我們需要定義handlers,接下來
vim /root/ansible_playbooks/roles/webservers/handlers/main.yml
- name: restart httpd
service: name={{ service }} state=restarted
5. 如果想定義變量
vim /root/ansible_playbooks/roles/webservers/vars/main.yml
- http_port: 80
- service: httpd
- maxclients: 200
6. 這樣我們就定義了webservers 這個角色,將來我們想要調用這個角色,需要在roles這個目錄的同級目錄下有site.yml文件
vim site.yml
- hosts: websrvs
remote_user: root
roles:
- webservers
至此 我們ansible-playbook site.yml
為了體現這個roles的靈活性:
vim site.yml
- hosts: 172.16.100.7
remote_user: root
roles:
- webservers
- hosts: 172.16.100.8
remote_user: root
roles:
- dbservers
- hosts: 172.16.100.9
remote_user: root
roles:
- webservers
- dbservers
4.1 YAML 簡介
YAML是一個可讀性高的用來表達資料序列的格式。YAML在設計時參考了其他多種語言,包括:XML、C語言、PYTHON、Perl以及電子郵件格式的RFC2882等,Clark Evans 在2001年首次發表了這種語言,另外Ingy dot Net 與 Ben-Kiki 也是這語言的共同設計者。
YAML Ain‘t Markup Language, 即YAML不是XML,不過,在開發的這種語言是,YAML的意思其實是: “Yet Another Markup Language"(仍是一種標記語言),其特性:
也是用於在不同主機之間共享數據時,能夠通過某種特定形式描述數據本身結構的一種數據組織形式。不同xml的是,yaml通過使用鍵值對+縮進的形式表示的
YAML 的可讀性好
YAML 和腳本語言的交互性好
YAML 使用實現語言的數據類型
YAML 又一個一直的信息模型
YAML 易於實現
YAML 可以基於流來處理
YAML 表達能力強,擴展性好
更多的內容及規範參見http://www.yaml.org/
4.2 YAML 語法
YAML的語法和其他高階語言類似,並且可以簡單表達清單、散列表、標量等數據結構,其結構(Structure) 通過空格來展示, 序列(sequence)裏的項用"-"來代表,Map裏的鍵值對用":"分隔。下面是一個事例
name: John Smith
age: 41
gender: Male
spouse:
name: Jane Smith
age:37
gender: Female
children:
- name: Jimmy Smith
age :17
gender : Male
- name: Jenny Smith
age: 13
gender:female
YAML 文件擴展名通常為.yaml, 如 example.yaml.
4.2.1 list
列表的所有元素均使用"-"大頭,例如:
# A list of tasty fruits
- Apple
- Orange
- strawberry
- mango
4.2.2 dictionay
字典通過key與value進行標示, 例如:
---
# An employee record
name: Examle Developer
job: Developer
skill: Elite
也可以將key:value 放置於{}中進行表示,例如:
---
# An employee record
{name: Examle Developer, job: Developer, skill: Elite}
五、Ansible基礎元素
5.1 變量
5.1.1 變量命名
變量名僅能由字母、數字和下劃線組成,且只能以字母開頭
5.1.2 facts
facts 是由正在通信的遠程目標主機發回的信息,這些信息被保存在ansible變量中,要獲取指定的遠程主機所支持的所有facts,可使用如下命令進行:
# ansible hostname -m setup
5.1.3 register
把任務的輸出定義為變量,然後用於其他任務,示例如下:
tasks:
- shell: /usr/bin/foo
- register: foo_result
- ignore_errors:True
5.1.4 通過命令行傳遞變量
在運行playbook的時候也可以傳遞一些變量供playbook使用:示例如下:
ansible-playbook test.yml --extra-vars "hosts=www user=mageedu"
5.1.5 通過role傳遞變量
當給一個主機應用角色的時候可以傳遞變量, 然後在角色內使用這些變量,示例如下:
- hosts: webservers
roles:
- common
- {role: foo_app_instance, dir:‘/web/htdocs/a.com‘, port:8080}
5.2 Inventory
ansible 的主要作用在於批量主機操作, 為了便捷地使用其中的部分主機, 可以在inventory file 中將其分組命名, 默認的inventory file為/etc/ansible/hosts.
inventory file 可以有多個,且也可以通過 Dynamic Inventory來動態生成。
5.2.1 inventory文件格式
inventory 文件遵循INI文件風格, 中括號中的字符為組名,可以將同一個主機同時歸到多個不同的組中;此外,當如若目標主機使用了非默認的SSH端口,還可以在主機名稱之後使用冒號來標明。
ntp.mageedu.com
[webserver]
www1.my.com:2222
www2.my.com
[dbserver]
db1.my.com
db2.my.com
db3.my.com
如果主機名遵循相似的命名模式,還可以使用列表的方式標識各主機,例如:
[webservers]
www[01:10].my.com
[databases]
db-[a:f].my.com
5.2.2主機變量
可以在inventory中定義主機時為其添加主機變量以便與在playbook中使用,例如:
[webservers]
www1.my.com http_port=80 maxRequestsPerChild=808
www1.my.com http_port=8080 maxRequestsPerChild=909
5.2.3組變量
組變量是指賦予給指定組內所有主機上的palybook中可用的變量,例如:
[webservers]
www1.my.com
www2.my.com
[webservers:vars]
ntp_server=ntp.my.com
nfs_server=nfs.my.com
5.2.4 組嵌套
inventory 中,組還可以包含其他組,並且也可以向組中的主機指定變量,不過,這些變量只能在ansible-playbook中使用,而ansible不支持,例如:
[apache]
http1.my.com
http2.my.com
[nginx]
ngx1.my.com
ngx2.my.com
[webservers:children]
apache
nginx
[webservers:vars]
ntp_server=ntp.my.com
5.2.5 inventory參數
ansible基於ssh連接inventory中指定的遠程主機時,還可以通過參數指定其交互方式;這些參數如下所示:
[webservers]
172.16.100.7 ansible_ssh_user=root ansible_ssh_pass=mypasswd ansible_ssh_port=12008
5.3 條件測試
在task後添加when子句即可使用條件測試;when語句支持jinjia2表達式語法,例如:
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == ‘Debian‘
when語句中還可以使用jinjia2的大多"filter", 例如要忽略此前某語句的錯誤並基於其結果<failed或者sucess> 運行後面指定的語句,可使用類似如下形式:
tasks:
- command: /bin/false
register: result
ignore_errors; True
- command: /bin/something
when: result|failed
- command: /bin/somethin_else
when: result|skipped
此外,when 語句中還可以使用facts或playbook中定義的變量
5.4 叠代,其實就表示循環
當有需要重復性執行的任務時,可以使用叠代機制,其使用格式為將需要叠代的內容定義為item變量引用,並通過with_items 語句來指明叠代的元素列表即可
- 例如:
- name: add serveral users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
上面語句的功能等同於下面的語句:
- name: add user testuser1
user: name=testuser1 state=present groups=wheel
- name: add user testuser2
user: name=testuser2 state=present groups=wheel
事實上,with_items中可以使用元素還可以為hashes, 例如:
- name add serveral users
user: name= {{ itesm.name }} state=present groups= {{ item.groups }}
with_items:
- { name: ‘testuser1‘, groups: ‘wheel‘ }
- { name: ‘testuser2‘, groups: ‘root‘ }
ansible的循環機制還有更多的高級功能, 具體請參見官方文檔(http://docs.ansible.com/playbooks_loops.html)
七. 如何編寫playbook
ansible playbooks
playbook是由一個或多個‘play‘組成的列表,play的主要功能在於將事先歸並為一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講,所謂task無非是調用ansible的一個module.將多個play組織在一個palybook中,即可以讓他們聯同起來按事先編排的機制同唱一臺大戲,下面是一個簡單示例。
- hosts: webnodes
vars:
http_port: 80
max_clients: 256
remote_user:root
tasks:
- name: ensure apache is at the latest version
yum : name=httpd state=latest
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: retart apache
service: name=httpd state=restarted
7.1 palybook的基礎組件
7.1.1 Hosts和Users
playbook中的每一個play的目的都是為了讓某個或某些主機以某個指定的用戶身份執行任務。hosts 用於指定要執行任務的主機,其可以是一個或多個由某好分隔主機組;remote_user 則用於指定遠程主機上的執行任務的用戶,如上圖示例中的
- hosts: webnodes
remote_user: root
不過,remote_user也可用於各task中,也可以通過指定其通過sudo的方式在遠程主機上執行任務,其可用於play全局或某任務,此外,甚至可以在sudo時使用sudo_user指定sudo時切換的用戶。
- hosts: webnodes
remote_user: ted1
tasks:
- name: test connection
ping:
remote_user: ted2
sudo : yes
7.1.2 任務列表和action
play的主體部分石task list.task list中的各任務按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個任務後在開始第二個。在運行自上而下某playbook時,如果中途發生錯誤,所有已執行任務都可能會回滾,因此,在更正playbook後重新執行一次即可。
task的目的是使用指定的參數執行模塊,而在模塊參數中可以使用變量,模塊執行時冪等的,這意味著多次執行時安全的,因為其結果均一致。
每個task都應該有其name, 用於playbook的執行結果輸出,建議其內容盡可能清晰地描述任務執行步驟,如果未提供name,則action的結果用於輸出。
定義task的可以使用"action: module options"或"module:
options"的格式, 推薦使用後者以實現向後兼容。如果action一行的內容過多,也可在行首使用幾個空白字符進行換行。
tasks:
- name: make sure apache is running
service: name=httpd state=running
在眾多模塊匯總,只有command和shell模塊僅需要給定一個列表而無需使用"key=value"格式,例如:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
如果命令或者腳本的退出碼不為零,可以使用如下方式替代:
tasks:
- name: run this command and ignore the result
sehll: /usr/bin/somecommand|| /bin/true
或者使用ignore_errors來忽略錯誤信息:(即使運行有錯誤,不管他繼續執行其他tasks)
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
7.1.3 handlers
用於當天關註的資源發生變化時采取一定的操作。
‘notify‘這個action可用於在每個play的最後被觸發。 這樣可以避免多次由改變發生時每次都執行指定的操作,取而代之,僅在所有的變化發生完成後一次性執行指定操作。在notify中列出的操作成為handler,也即notify中調用handler中定義的操作。
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
handler是task列表,這些task與前述的task並沒有本質上的不同。
handlers:
- name: restart memcached
service: name=mamcached state=restarted
- name: restart apache
service: name=apache state=restarted
示例:
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd packege
yum: name=httpd state=latest
- name: install configuration file for httpd
copy: src=conf/httpd.conf dest=/etc/httpd/conf/httpd.conf
notify:
- restart httpd
- name: start httpd service
service: enabled=true name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
ansible運維工具(二)