一米间、簡介
Ansible is a radically simple configuration-management, application deployment, task-execution, and multinode orchestration engine.
Design Principles
Have a dead simple setup process and a minimal learning curve
Be super fast & parallel by default
Require no server or client daemons; use existing SSHd
Use a language that is both machine and human friendly
Focus on security and easy auditability/review/rewriting of content
Manage remote machines instantly, without bootstrapping
Allow module development in any dynamic language, not just Python
Be usable as non-root
Be the easiest IT automation system to use, ever.
二崖面、安裝
ansible依賴于Python 2.6或更高的版本掌唾、paramiko能颁、PyYAML及Jinja2。
2.1 編譯安裝
解決依賴關系
# yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
# tar xf ansible-xxx.tar.gz
# cd ansible-xxx
# python setup.py build
# python setup.py install
# mkdir /etc/ansible
# cp -r examples/* /etc/ansible
2.2 rpm包安裝
# yum install ansible
注意:不同版本的ansible的功能差異可能較大。
三、簡單應用
ansible通過ssh實現(xiàn)配置管理薄榛、應用部署、任務執(zhí)行等功能让歼,因此敞恋,需要事先配置ansible端能基于密鑰認證的方式聯(lián)系各被管理節(jié)點。
ansible <host-pattern> [-f forks] [-m module_name] [-a args]
-m module:默認為command
ansible-doc: Show Ansible module documentation
-l, --list List available modules
-s, --snippet Show playbook snippet for specified module(s)
四谋右、YAML
4.1 YAML介紹
YAML是一個可讀性高的用來表達資料序列的格式硬猫。YAML參考了其他多種語言,包括:XML改执、C語言啸蜜、 Python、Perl以及電子郵件格式RFC2822等辈挂。Clark Evans在2001年在首次發(fā)表了這種語言衬横,另外 Ingy d?t Net與Oren Ben-Kiki也是這語言的共同設計者。
YAML Ain't Markup Language终蒂,即YAML不是XML蜂林。不過遥诉,在開發(fā)的這種語言時,YAML的意思其實 是:"Yet Another Markup Language"(仍是一種標記語言)噪叙。其特性:
YAML的可讀性好
YAML和腳本語言的交互性好
YAML使用實現(xiàn)語言的數據類型
YAML有一個一致的信息模型
YAML易于實現(xiàn)
YAML可以基于流來處理
YAML表達能力強矮锈,擴展性好
更多的內容及規(guī)范參見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 dictionary
字典通過key與value進行標識,例如:
---
\# An employee record
name: Example Developer
job: Developer
skill: Elite
也可以將key:value放置于{}中進行表示将塑,例如:
---
\# An employee record
{name: Example Developer, job: Developer, skill: Elite}
五脉顿、Ansible基礎元素
5.1 變量
5.1.1 變量命名
變量名僅能由字母、數字和下劃線組成点寥,且只能以字母開頭艾疟。
5.1.2 facts
facts是由正在通信的遠程目標主機發(fā)回的信息,這些信息被保存在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 通過roles傳遞變量
當給一個主機應用角色的時候可以傳遞變量,然后在角色內使用這些變量同廉,示例如下:
- 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來動態(tài)生成咒程。
5.2.1 inventory文件格式
inventory文件遵循INI文件風格鸠天,中括號中的字符為組名≌室觯可以將同一個主機同時歸并到多個不同的組中稠集;此外奶段,當如若目標主機使用了非默認的SSH端口,還可以在主機名稱之后使用冒號加端口號來標明剥纷。
ntp.magedu.com
[webservers]
www1.magedu.com:2222
www2.magedu.com
[dbservers]
db1.magedu.com
db2.magedu.com
db3.magedu.com
如果主機名稱遵循相似的命名模式痹籍,還可以使用列表的方式標識各主機,例如:
[webservers]
www[01:50].example.com
[databases]
db-[a:f].example.com
5.2.2 主機變量
可以在inventory中定義主機時為其添加主機變量以便于在playbook中使用晦鞋。例如:
[webservers]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
5.2.3 組變量
組變量是指賦予給指定組內所有主機上的在playboo中可用的變量蹲缠。例如:
[webservers]
www1.magedu.com
www2.magedu.com
[webservers:vars]
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com
5.2.4 組嵌套
inventory中,組還可以包含其它的組悠垛,并且也可以向組中的主機指定變量线定。不過,這些變量只能在ansible-playbook中使用确买,而ansible不支持斤讥。例如:
[apache]
httpd1.magedu.com
httpd2.magedu.com
[nginx]
ngx1.magedu.com
ngx2.magedu.com
[webservers:children]
apache
nginx
[webservers:vars]
ntp_server=ntp.magedu.com
5.2.5 inventory參數
ansible基于ssh連接inventory中指定的遠程主機時,還可以通過參數指定其交互方式湾趾;這些參數如下所示:
ansible_ssh_host
The name of the host to connect to, if different from the alias you wish to give to it.
ansible_ssh_port
The ssh port number, if not 22
ansible_ssh_user
The default ssh user name to use.
ansible_ssh_pass
The ssh password to use (this is insecure, we strongly recommend using --ask-pass or SSH keys)
ansible_sudo_pass
The sudo password to use (this is insecure, we strongly recommend using --ask-sudo-pass)
ansible_connection
Connection type of the host. Candidates are local, ssh or paramiko. The default is paramiko before Ansible 1.2, and 'smart' afterwards which detects whether usage of 'ssh' would be feasible based on whether ControlPersist is supported.
ansible_ssh_private_key_file
Private key file used by ssh. Useful if using multiple keys and you don't want to use SSH agent.
ansible_shell_type
The shell type of the target system. By default commands are formatted using 'sh'-style syntax by default. Setting this to 'csh' or 'fish' will cause commands executed on target systems to follow those shell's syntax instead.
ansible_python_interpreter
The target host python path. This is useful for systems with more
than one Python or not located at "/usr/bin/python" such as \*BSD, or where /usr/bin/python
is not a 2.X series Python. We do not use the "/usr/bin/env" mechanism as that requires the remote user's
path to be set right and also assumes the "python" executable is named python, where the executable might
be named something like "python26".
ansible\_\*\_interpreter
Works for anything such as ruby or perl and works just like ansible_python_interpreter.
This replaces shebang of modules which will run on that host.
5.3 條件測試
如果需要根據變量芭商、facts或此前任務的執(zhí)行結果來做為某task執(zhí)行與否的前提時要用到條件測試。
5.3.1 when語句
在task后添加when子句即可使用條件測試搀缠;when語句支持Jinja2表達式語法铛楣。例如:
tasks:
- name: "shutdown Debian flavored systems"
command: /sbin/shutdown -h now
when: ansible_os_family == "Debian"
when語句中還可以使用Jinja2的大多“filter”,例如要忽略此前某語句的錯誤并基于其結果(failed或者sucess)運行后面指定的語句艺普,可使用類似如下形式:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
此外蛉艾,when語句中還可以使用facts或playbook中定義的變量。
5.4 迭代
當有需要重復性執(zhí)行的任務時衷敌,可以使用迭代機制。其使用格式為將需要迭代的內容定義為item變量引用拓瞪,并通過with_items語句來指明迭代的元素列表即可缴罗。例如:
- name: add several 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 several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
ansible的循環(huán)機制還有更多的高級功能面氓,具體請參見官方文檔(http://docs.ansible.com/playbooks_loops.html)。
七蛆橡、ansible playbooks
playbook是由一個或多個“play”組成的列表舌界。play的主要功能在于將事先歸并為一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講泰演,所謂task無非是調用ansible的一個module呻拌。將多個play組織在一個playbook中,即可以讓它們聯(lián)同起來按事先編排的機制同唱一臺大戲睦焕。下面是一個簡單示例藐握。
- 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: restart apache
service: name=httpd state=restarted
7.1 playbook基礎組件
7.1.1 Hosts和Users
playbook中的每一個play的目的都是為了讓某個或某些主機以某個指定的用戶身份執(zhí)行任務靴拱。hosts用于指定要執(zhí)行指定任務的主機,其可以是一個或多個由冒號分隔主機組猾普;remote_user則用于指定遠程主機上的執(zhí)行任務的用戶袜炕。如上面示例中的
-hosts: webnodes
remote_user: root
不過,remote_user也可用于各task中初家。也可以通過指定其通過sudo的方式在遠程主機上執(zhí)行任務偎窘,其可用于play全局或某任務;此外溜在,甚至可以在sudo時使用sudo_user指定sudo時切換的用戶陌知。
- hosts: webnodes
remote_user: mageedu
tasks:
- name: test connection
ping:
remote_user: mageedu
sudo: yes
7.1.2 任務列表和action
play的主體部分是task list。task list中的各任務按次序逐個在hosts中指定的所有主機上執(zhí)行炕泳,即在所有主機上完成第一個任務后再開始第二個纵诞。在運行自下而下某playbook時,如果中途發(fā)生錯誤培遵,所有已執(zhí)行任務都將回滾浙芙,因此,在更正playbook后重新執(zhí)行一次即可籽腕。
task的目的是使用指定的參數執(zhí)行模塊嗡呼,而在模塊參數中可以使用變量。模塊執(zhí)行是冪等的皇耗,這意味著多次執(zhí)行是安全的南窗,因為其結果均一致。
每個task都應該有其name郎楼,用于playbook的執(zhí)行結果輸出万伤,建議其內容盡可能清晰地描述任務執(zhí)行步驟。如果未提供name呜袁,則action的結果將用于輸出敌买。
定義task的可以使用“action: module options”或“module: options”的格式,推薦使用后者以實現(xiàn)向后兼容阶界。如果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
shell: /usr/bin/somecommand || /bin/true
或者使用ignore_errors來忽略錯誤信息:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
7.1.3 handlers
用于當關注的資源發(fā)生變化時采取一定的操作氧映。
“notify”這個action可用于在每個play的最后被觸發(fā)春畔,這樣可以避免多次有改變發(fā)生時每次都執(zhí)行指定的操作,取而代之,僅在所有的變化發(fā)生完成后一次性地執(zhí)行指定操作拐迁。在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=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
案例:
heartbeat.yaml
- hosts: hbhosts
remote_user: root
tasks:
- name: ensure heartbeat latest version
yum: name=heartbeat state=present
- name: authkeys configure file
copy: src=/root/hb_conf/authkeys dest=/etc/ha.d/authkeys
- name: authkeys mode 600
file: path=/etc/ha.d/authkeys mode=600
notify:
- restart heartbeat
- name: ha.cf configure file
copy: src=/root/hb_conf/ha.cf dest=/etc/ha.d/ha.cf
notify:
- restart heartbeat
handlers:
- name: restart heartbeat
service: name=heartbeat state=restarted
八、roles
ansilbe自1.2版本引入的新特性缓淹,用于層次性哈打、結構化地組織playbook。roles能夠根據層次型結構自動裝載變量文件讯壶、tasks以及handlers等料仗。要使用roles只需要在playbook中使用include指令即可。簡單來講伏蚊,roles就是通過分別將變量立轧、文件、任務躏吊、模板及處理器放置于單獨的目錄中氛改,并可以便捷地include它們的一種機制。角色一般用于基于主機構建服務的場景中比伏,但也可以是用于構建守護進程等場景中胜卤。
一個roles的案例如下所示:
site.yml
webservers.yml
dbservers.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 創(chuàng)建role的步驟
(1) 創(chuàng)建以roles命名的目錄;
(2) 在roles目錄中分別創(chuàng)建以各角色名稱命名的目錄悠菜,如webservers等舰攒;
(3) 在每個角色命名的目錄中分別創(chuàng)建files、handlers悔醋、meta芒率、tasks、templates和vars目錄篙顺;用不到的目錄可以創(chuàng)建為空目錄,也可以不創(chuàng)建充择;
(4) 在playbook文件中德玫,調用各角色;
8.2 role內各目錄中可用的文件
tasks目錄:至少應該包含一個名為main.yml的文件椎麦,其定義了此角色的任務列表宰僧;此文件可以使用 include包含其它的位于此目錄中的task文件;
files目錄:存放由copy或script等模塊調用的文件观挎;
templates目錄:template模塊會自動在此目錄中尋找Jinja2模板文件琴儿;
handlers目錄:此目錄中應當包含一個main.yml文件段化,用于定義此角色用到的各handler;在handler中使用include包含的其它的handler文件也應該位于此目錄中造成;
vars目錄:應當包含一個main.yml文件显熏,用于定義此角色用到的變量;
meta目錄:應當包含一個main.yml文件晒屎,用于定義此角色的特殊設定及其依賴關系喘蟆;ansible 1.3及其以后的版本才支持;
default目錄:為當前角色設定默認變量時使用此目錄鼓鲁;應當包含一個main.yml文件蕴轨;
九、Tags
tags用于讓用戶選擇運行playbook中的部分代碼骇吭。ansible具有冪等性橙弱,因此會自動跳過沒有變化的部分溃槐,即便如此胡控,有些代碼為測試其確實沒有發(fā)生變化的時間依然會非常地長产镐。此時绘搞,如果確信其沒有變化宜狐,就可以通過tags跳過此些代碼片斷蛇尚。
十啼肩、Jinja2相關
10.1 字面量
表達式最簡單的形式就是字面量亿笤。字面量表示諸如字符串和數值的 Python 對象净当。下面 的字面量是可用的:
“Hello World”:
雙引號或單引號中間的一切都是字符串内斯。無論何時你需要在模板中使用一個字 符串(比如函數調用、過濾器或只是包含或繼承一個模板的參數)像啼,它們都是 有用的俘闯。
42 / 42.23:
直接寫下數值就可以創(chuàng)建整數和浮點數。如果有小數點忽冻,則為浮點數真朗,否則為 整數。記住在 Python 里僧诚, 42 和 42.0 是不一樣的遮婶。
[‘list’, ‘of’, ‘objects’]:
一對中括號括起來的東西是一個列表。列表用于存儲和迭代序列化的數據湖笨。例如 你可以容易地在 for 循環(huán)中用列表和元組創(chuàng)建一個鏈接的列表:
<ul>
{% for href, caption in [('index.html', 'Index'), ('about.html', 'About'),
('downloads.html', 'Downloads')] %}
<li><a href="{{ href }}">{{ caption }}</a></li>
{% endfor %}
</ul>
(‘tuple’, ‘of’, ‘values’):
元組與列表類似旗扑,只是你不能修改元組。如果元組中只有一個項慈省,你需要以逗號 結尾它臀防。元組通常用于表示兩個或更多元素的項。更多細節(jié)見上面的例子。
{‘dict’: ‘of’, ‘key’: ‘and’, ‘value’: ‘pairs’}:
Python 中的字典是一種關聯(lián)鍵和值的結構袱衷。鍵必須是唯一的捎废,并且鍵必須只有一個 值。字典在模板中很少使用致燥,罕用于諸如 xmlattr() 過濾器之類登疗。
true / false:
true 永遠是 true ,而 false 始終是 false 篡悟。
10.2 算術運算
Jinja 允許你用計算值谜叹。這在模板中很少用到,但是為了完整性允許其存在搬葬。支持下面的 運算符:
+
把兩個對象加到一起荷腊。通常對象是素質,但是如果兩者是字符串或列表急凰,你可以用這 種方式來銜接它們女仰。無論如何這不是首選的連接字符串的方式!連接字符串見 ~ 運算符抡锈。 {{ 1 + 1 }} 等于 2 疾忍。
-
用第一個數減去第二個數。 {{ 3 - 2 }} 等于 1 床三。
/
對兩個數做除法一罩。返回值會是一個浮點數。 {{ 1 / 2 }} 等于 {{ 0.5 }} 撇簿。
//
對兩個數做除法聂渊,返回整數商。 {{ 20 // 7 }} 等于 2 四瘫。
%
計算整數除法的余數汉嗽。 {{ 11 % 7 }} 等于 4 。
*
用右邊的數乘左邊的操作數找蜜。 {{ 2 * 2 }} 會返回 4 饼暑。也可以用于重 復一個字符串多次。 {{ ‘=’ * 80 }} 會打印 80 個等號的橫條洗做。
**
取左操作數的右操作數次冪弓叛。 {{ 2**3 }} 會返回 8 。
10.3 比較操作符
==
比較兩個對象是否相等诚纸。
!=
比較兩個對象是否不等邪码。
>
如果左邊大于右邊,返回 true 咬清。
>=
如果左邊大于等于右邊,返回 true 。
<
如果左邊小于右邊旧烧,返回 true 影钉。
<=
如果左邊小于等于右邊,返回 true 掘剪。
10.4 邏輯運算符
對于 if 語句平委,在 for 過濾或 if 表達式中,它可以用于聯(lián)合多個表達式:
and
如果左操作數和右操作數同為真夺谁,返回 true 廉赔。
or
如果左操作數和右操作數有一個為真,返回 true 匾鸥。
not
對一個表達式取反(見下)蜡塌。
(expr)
表達式組。