1 介紹
ansible是一種自動(dòng)化運(yùn)維工具,基于paramiko開發(fā)的,并且基于模塊化工作怯屉,Ansible是一種集成IT系統(tǒng)的配置管理抛猫、應(yīng)用部署贼陶、執(zhí)行特定任務(wù)的開源平臺(tái)刃泡,它是基于python語(yǔ)言,由Paramiko和PyYAML兩個(gè)關(guān)鍵模塊構(gòu)建碉怔。集合了眾多運(yùn)維工具的優(yōu)點(diǎn)烘贴,實(shí)現(xiàn)了批量系統(tǒng)配置、批量程序部署撮胧、批量運(yùn)行命令等功能.ansible是基于模塊工作的,本身沒(méi)有批量部署的能力.真正具有批量部署的是ansible所運(yùn)行的模塊桨踪,ansible只是提供一種框架.ansible不需要在遠(yuǎn)程主機(jī)上安裝client/agents,因?yàn)樗鼈兪腔趕sh來(lái)和遠(yuǎn)程主機(jī)通訊的.
ansible被定義為配置管理工具,配置管理工具通常具有以下功能:
- 確保所依賴的軟件包已經(jīng)被安裝
- 配置文件包含正確的內(nèi)容和正確的權(quán)限
- 相關(guān)服務(wù)被正確運(yùn)行
常用的自動(dòng)化運(yùn)維工具技術(shù)特性比較:
項(xiàng)目 | Puppet | SaltStack | Ansible |
---|---|---|---|
開發(fā)語(yǔ)言 | Ruby | Python | Python |
是否有客戶端 | 有 | 有 | 無(wú) |
是否支持二次開發(fā) | 不支持 | 支持 | 支持 |
服務(wù)器與遠(yuǎn)程機(jī)器是否相互驗(yàn)證 | 是 | 是 | 是 |
服務(wù)器與遠(yuǎn)程機(jī)器的通信是否加密 | 是芹啥,標(biāo)準(zhǔn)的SSL協(xié)議 | 是锻离,使用AES加密 | 是,使用OpenSSH |
平臺(tái)支持 | AIX , BSD, HP-UX, Linux , Mac OSX , Solaris, Windows | BSD, Linux , Mac OS X , Solaris, Windows | AIX , BSD , HP-UX , Linux , Mac OS X , Solaris |
是否提供Web UI | 提供 | 提供 | 提供墓怀,但是是商業(yè)版本 |
配置文件格式 | Ruby 語(yǔ)法格式 | YAML | YAML |
命令行執(zhí)行 | 不支持汽纠,大師可以通過(guò)配置模塊實(shí)現(xiàn) | 支持 | 支持 |
1.1 ansible基本架構(gòu)
ansible系統(tǒng)由控制主機(jī)和被管理主機(jī)組成,控制主機(jī)不支持windows平臺(tái)
- 核心: ansible
- Core Modules: ansible自帶的模塊
- Custom Modules: 核心模塊功能不足時(shí),用戶可以添加擴(kuò)展模塊
- Plugins: 通過(guò)插件來(lái)實(shí)現(xiàn)記錄日志,發(fā)送郵件或其他功能
- Playbooks: 劇本,YAML格式文件,多個(gè)任務(wù)定義在一個(gè)文件中傀履,定義主機(jī)需要調(diào)用哪些模塊來(lái)完成的功能
- Connectior Plugins: ansible基于連接插件連接到各個(gè)主機(jī)上,默認(rèn)是使用ssh
- Host Inventory: 記錄由Ansible管理的主機(jī)信息虱朵,包括端口、密碼钓账、ip等
1.2 ansible特點(diǎn)
部署簡(jiǎn)單, 只需要在控制主機(jī)上部署ansible環(huán)境,被控制端上只要求安裝ssh和python 2.5以上版本,這個(gè)對(duì)于類unix系統(tǒng)來(lái)說(shuō)相當(dāng)與無(wú)需配置.
- no angents: 被管控節(jié)點(diǎn)無(wú)需安裝agent
- no server: 無(wú)服務(wù)端,使用是直接調(diào)用命名
- modules in any languages: 基于模塊工作, 可以使用任意語(yǔ)言開發(fā)模塊
- 易讀的語(yǔ)法: 基于yaml語(yǔ)法編寫playbook
- 基于推送模式: 不同于puppet的拉取模式,直接由調(diào)用者控制變更在服務(wù)器上發(fā)生的時(shí)間
- 模塊是冪等性的:定義的任務(wù)已存在則不會(huì)做任何事情,意味著在同一臺(tái)服務(wù)器上多次執(zhí)行同一個(gè)playbook是安全的
1.3 ansible程序目錄結(jié)構(gòu):
- 配置文件:
/etc/ansible/
- 執(zhí)行文件目錄:
/usr/bin/
- lib依賴庫(kù):
/usr/lib/python2.7/site-packages/ansible/
- help文件:
/usr/lib/python2.7/site-packages/ansible
2. ansible任務(wù)執(zhí)行
2.1 ansible任務(wù)執(zhí)行模式
Ansible任務(wù)執(zhí)行模式分為以下兩種:
-
ad-hoc模式(點(diǎn)對(duì)點(diǎn)模塊)
使用單個(gè)模塊,支持批量執(zhí)行單條命令,相當(dāng)與在bash中執(zhí)行一句shell命令 -
playbook模式(劇本模式)
ansible主要的管理方式,通過(guò)多個(gè)task的集合完成一類功能,可以理解為多個(gè)ad-hoc的配置文件
2.2 ansible執(zhí)行流程:
3. ansible使用實(shí)例
3.1 安裝
- 編譯安裝
ansible依賴于Python 2.6或更高的版本碴犬、paramiko、PyYAML及Jinja2梆暮。
# yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
# tar xf ansible-1.5.4.tar.gz
# cd ansible-1.5.4
# python setup.py build
# python setup.py install
# mkdir /etc/ansible
# cp -r examples/* /etc/ansible
- rpm包安裝
# yum install ansible
3.2 修改配置文件
ansible配置文件查找順序
- 檢查環(huán)境變量
ANSIBLE_CONFIG
指向的路徑文件(export ANSIBLE_CONFIG=/etc/ansible.cfg
)服协; -
~/.ansible.cfg
,檢查當(dāng)前目錄下的ansible.cfg配置文件惕蹄; -
/etc/ansible.cfg
檢查etc目錄的配置文件蚯涮。
ansible配置文件
ansible 有許多參數(shù),下面我們列出一些常見的參數(shù):
inventory = /etc/ansible/hosts #這個(gè)參數(shù)表示資源清單inventory文件的位置
library = /usr/share/ansible #指向存放Ansible模塊的目錄卖陵,支持多個(gè)目錄方式遭顶,只要用冒號(hào)(:)隔開就可以
forks = 5 #并發(fā)連接數(shù),默認(rèn)為5
sudo_user = root #設(shè)置默認(rèn)執(zhí)行命令的用戶
remote_port = 22 #指定連接被管節(jié)點(diǎn)的管理端口泪蔫,默認(rèn)為22端口棒旗,建議修改,能夠更加安全
host_key_checking = False #設(shè)置是否檢查SSH主機(jī)的密鑰,值為True/False铣揉。關(guān)閉后第一次連接不會(huì)提示配置實(shí)例
timeout = 60 #設(shè)置SSH連接的超時(shí)時(shí)間饶深,單位為秒
log_path = /var/log/ansible.log #指定一個(gè)存儲(chǔ)ansible日志的文件(默認(rèn)不記錄日志)
3.3 定義Inventory(主機(jī)列表)
ansible的主要功用在于批量主機(jī)操作,為了便捷地使用其中的部分主機(jī)逛拱,可以在inventory file中將其分組命名敌厘。默認(rèn)的inventory file為/etc/ansible/hosts。
inventory file可以有多個(gè)朽合,且也可以通過(guò)Dynamic Inventory來(lái)動(dòng)態(tài)生成俱两。
Inventory文件格式:
- inventory文件遵循INI文件風(fēng)格,中括號(hào)中的字符為組名曹步∠懿剩可以將同一個(gè)主機(jī)同時(shí)歸并到多個(gè)不同的組中;此外讲婚,當(dāng)如若目標(biāo)主機(jī)使用了非默認(rèn)的SSH端口尿孔,還可以在主機(jī)名稱之后使用冒號(hào)加端口號(hào)來(lái)標(biāo)明。
ntp.com
[webservers]
www1.com:2222
www2.com
[dbservers]
db1.com
db2.com
db3.com
- 如果主機(jī)名稱遵循相似的命名模式筹麸,還可以使用列表的方式標(biāo)識(shí)各主機(jī)活合,例如:
[webservers]
www[01:50].example.com
[databases]
db-[a:f].example.com
- 主機(jī)變量: 可以在inventory中定義主機(jī)時(shí)為其添加主機(jī)變量以便于在playbook中使用。例如:
[webservers]
www1.com http_port=80 maxRequestsPerChild=808
www2.com http_port=8080 maxRequestsPerChild=909
- 組變量
[webservers]
www1.com
www2.com
[webservers:vars]
ntp_server=ntp.com
nfs_server=nfs.com
inventory其他的參數(shù)
- ansible基于ssh連接inventory中指定的遠(yuǎn)程主機(jī)時(shí)物赶,還可以通過(guò)參數(shù)指定其交互方式芜辕;這些參數(shù)如下所示:
ansible_ssh_host # 遠(yuǎn)程主機(jī)
ansible_ssh_port # 指定遠(yuǎn)程主機(jī)ssh端口
ansible_ssh_user # ssh連接遠(yuǎn)程主機(jī)的用戶,默認(rèn)root
ansible_ssh_pass # 連接遠(yuǎn)程主機(jī)使用的密碼,在文件中明文,建議使用--ask-pass或者使用SSH keys
ansible_sudo_pass # sudo密碼, 建議使用--ask-sudo-pass
ansible_connection # 指定連接類型: local, ssh, paramiko
ansible_ssh_private_key_file # ssh 連接使用的私鑰
ansible_shell_type # 指定連接對(duì)端的shell類型, 默認(rèn)sh,支持csh,fish
ansible_python_interpreter # 指定對(duì)端使用的python編譯器的路徑
3.4 基于ad-hoc模式運(yùn)行
ansible通過(guò)ssh實(shí)現(xiàn)配置管理、應(yīng)用部署块差、任務(wù)執(zhí)行等功能,因此倔丈,需要事先配置ansible端能基于密鑰認(rèn)證的方式聯(lián)系各被管理節(jié)點(diǎn)憨闰。
ansible命令使用語(yǔ)法:
ansible <host-pattern> [-f forks] [-m module_name] [-a args]
-m module:默認(rèn)為command
例如:
- 定義好inventory后可以調(diào)用
ping
模塊來(lái)檢測(cè)網(wǎng)絡(luò)是否可達(dá)
# ansible all -m ping
192.168.57.22 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.57.11 | SUCCESS => {
"changed": false,
"ping": "pong"
}
- 使用
command
模塊遠(yuǎn)程執(zhí)行命令:
# 如果/etc/passwd文件存在就執(zhí)行g(shù)rep命令
# ansible all -m command -a 'removes=/etc/passwd grep root /etc/passwd'
192.168.57.22 | SUCCESS | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
192.168.57.11 | SUCCESS | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
可以通過(guò)ansible-doc -l
列出所有可用的module,常用的module有:
ping # 主機(jī)連通性測(cè)試
command # 在遠(yuǎn)程主機(jī)上執(zhí)行命令,不支持管道
shell # 在遠(yuǎn)程主機(jī)上調(diào)用shell解析器,支持管道命令個(gè)
copy # 用于將文件復(fù)制到遠(yuǎn)程主機(jī),支持設(shè)定內(nèi)容和修改權(quán)限.
file # 創(chuàng)建文件,創(chuàng)建連接文件,刪除文件等
fetch # 從遠(yuǎn)程復(fù)制文件到本地
cron # 管理cron計(jì)劃任務(wù)
yum # 用于模塊的安裝
service # 管理服務(wù)
user # 管理用戶賬號(hào)
group # 用戶組管理
script # 將本地的腳本在遠(yuǎn)端服務(wù)器運(yùn)行
setup # 該模塊主要用于收集信息,是通過(guò)調(diào)用facts組件來(lái)實(shí)現(xiàn)的,以變量形式存儲(chǔ)主機(jī)上的信息
ansible -s <module-name>
可以查看指定module的用法,或者參看官方幫助文檔:
# ansible-doc -s service
- name: Manage services
service:
arguments: # Additional arguments provided on the command line
enabled: # Whether the service should start on boot. *At least one of state and enabled are required.*
name: # (required) Name of the service.
pattern: # If the service does not respond to the status command, name a substring to look for as would be
found in the output of the `ps' command as a stand-in for a
status result. If the string is found, the service will be
assumed to be running.
runlevel: # For OpenRC init scripts (ex: Gentoo) only. The runlevel that this service belongs to.
sleep: # If the service is being `restarted' then sleep this many seconds between the stop and start
command. This helps to workaround badly behaving init scripts
that exit immediately after signaling a process to stop.
state: # `started'/`stopped' are idempotent actions that will not run commands unless necessary.
`restarted' will always bounce the service. `reloaded' will
always reload. *At least one of state and enabled are required.*
Note that reloaded will start the service if it is not already
started, even if your chosen init system wouldn't normally.
use: # The service module actually uses system specific modules, normally through auto detection, this
setting can force a specific module. Normally it uses the value
of the 'ansible_service_mgr' fact and falls back to the old
'service' module when none matching is found.
3.5 基于playbook執(zhí)行
playbook是由一個(gè)或多個(gè)“play”組成的列表需五。play的主要功能在于將事先歸并為一組的主機(jī)裝扮成事先通過(guò)ansible中的task定義好的角色鹉动。從根本上來(lái)講,所謂task無(wú)非是調(diào)用ansible的一個(gè)module宏邮。將多個(gè)play組織在一個(gè)playbook中泽示,即可以讓它們聯(lián)同起來(lái)按事先編排的機(jī)制同唱一臺(tái)大戲。
下面是一個(gè)簡(jiǎn)單示例:
- hosts: master
user: root
vars:
- motd_warning: 'WARNING: Use by master ONLY'
tasks:
- name: setup a MOTD
copy: dest=/etc/motd content="{{ motd_warning }}"
notify: say something
handlers:
- name: say something
command: echo "copy OK"
playbooks的組成部分
- Target section: 定義要運(yùn)行playbook的遠(yuǎn)程主機(jī)組
- hosts: hosts用于指定要執(zhí)行指定任務(wù)的主機(jī)蜜氨,其可以是一個(gè)或多個(gè)由冒號(hào)分隔主機(jī)組
- user: 指定遠(yuǎn)程主機(jī)上的執(zhí)行任務(wù)的用戶,還可以指定sudo用戶等
- Variable section: 定義playbook運(yùn)行時(shí)使用的變量
- Task section: 定義要在遠(yuǎn)程主機(jī)上運(yùn)行的任務(wù)列表
- name: 每個(gè)任務(wù)都有name,建議描述任務(wù)執(zhí)行步驟,未通過(guò)name會(huì)用執(zhí)行結(jié)果作為name
- 'module:options': 調(diào)用的module和傳入的參數(shù)args
- Handler section: 定義task完成后需要調(diào)用的任務(wù)
- notify: 在Task Section在每個(gè)play的最后觸發(fā),調(diào)用在hendler中定義的操作
- handler: 也是task的列表
執(zhí)行過(guò)程:
[root@localhost ansible]# ansible-playbook set_motd.yaml
PLAY [master] ******************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************
ok: [192.168.57.11]
TASK [setup a MOTD] ************************************************************************************************************
changed: [192.168.57.11]
RUNNING HANDLER [say something] ************************************************************************************************
changed: [192.168.57.11]
PLAY RECAP *********************************************************************************************************************
192.168.57.11 : ok=3 changed=2 unreachable=0 failed=0
# cat /etc/motd
WARNING: Use by master ONLY
playbook安裝配置apache實(shí)戰(zhàn)
- 編寫playbook:
install_httpd.yaml
---
- hosts: slave
vars:
http_port: 8080
user: root
tasks:
- name: ensure apache is at the latest version
yum: name=httpd state=latest
- name: write the apache config file
template:
src: template/httpd.j2
dest: /etc/httpd/conf/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service:
name: httpd
state: restarted
- 生成apache配置文件jinja2模板,將服務(wù)端口配置為變量
Listen {{ http_port }}
- 執(zhí)行playbook并檢查遠(yuǎn)端服務(wù)端口
[root@localhost ansible]# ansible-playbook install_httpd.yaml
PLAY [slave] *******************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************
ok: [192.168.57.22]
TASK [ensure apache is at the latest version] **********************************************************************************
changed: [192.168.57.22]
TASK [write the apache config file] ********************************************************************************************
changed: [192.168.57.22]
TASK [ensure apache is running] ************************************************************************************************
changed: [192.168.57.22]
RUNNING HANDLER [restart apache] ***********************************************************************************************
changed: [192.168.57.22]
PLAY RECAP *********************************************************************************************************************
192.168.57.22 : ok=5 changed=4 unreachable=0 failed=0
[root@localhost ansible]# ansible slave -m shell -a 'ss -lntp | grep 8080'
192.168.57.22 | SUCCESS | rc=0 >>
LISTEN 0 128 :::8080 :::* users:(("httpd",pid=29187,fd=4),("httpd",pid=29185,fd=4),("httpd",pid=29184,fd=4),("httpd",pid=29183,fd=4),("httpd",pid=29182,fd=4),("httpd",pid=29181,fd=4))
3.6 roles
ansilbe自1.2版本引入的新特性械筛,用于層次性、結(jié)構(gòu)化地組織playbook飒炎。roles能夠根據(jù)層次型結(jié)構(gòu)自動(dòng)裝載變量文件埋哟、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可郎汪。簡(jiǎn)單來(lái)講赤赊,roles就是通過(guò)分別將變量闯狱、文件、任務(wù)抛计、模塊及處理器放置于單獨(dú)的目錄中哄孤,并可以便捷地include它們的一種機(jī)制。角色一般用于基于主機(jī)構(gòu)建服務(wù)的場(chǎng)景中吹截,但也可以是用于構(gòu)建守護(hù)進(jìn)程等場(chǎng)景中瘦陈。
一個(gè)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傳遞參數(shù):
---
- hosts: webservers
- common
- { role: foo_app_instance, dir: '/opt/a', port: 5000 }
- { role: foo_app_instance, dir: '/opt/b', port: 5001 }
也可以用條件來(lái)使用roles:
---
- hosts: webservers
- { role: some_role, when: "ansible_os_family == 'RedHat'" }
3.6.1 創(chuàng)建roles步驟:
- 創(chuàng)建以roles命名的目錄;
- 在roles目錄中分別創(chuàng)建以各角色名稱命名的目錄饭弓,如webservers等双饥;
- 在每個(gè)角色命名的目錄中分別創(chuàng)建files、handlers弟断、meta咏花、tasks、templates和vars目錄阀趴;用不到的目錄可以創(chuàng)建為空目錄昏翰,也可以不創(chuàng)建;
- 在playbook文件中刘急,調(diào)用各角色棚菊;
4. ansible速度優(yōu)化
4.1 SSH Multiplexing
ansible運(yùn)行playbook時(shí)會(huì)啟動(dòng)很多ssh連接來(lái)執(zhí)行復(fù)制文件,運(yùn)行命令這樣的操作.openssh支持這樣一個(gè)優(yōu)化,叫做ssh Multiplexing,當(dāng)使用這個(gè)ssh Multiplexing的時(shí)候,多個(gè)連接到相同主機(jī)的ssh回話會(huì)共享相同的TCP連接,這樣就只有第一次連接的時(shí)候需要進(jìn)行TCP三次握手.
ansible會(huì)默認(rèn)使用ssh Multiplexing特性,一般不需要更改配置,相關(guān)的配置項(xiàng)為:
[ssh_connection]
control_master = auto # 套接字不存在的情況下自動(dòng)創(chuàng)建
control_path = $HOME/.ansible/cp/ansible-ssh-%h-%p-%r # 連接套接字存放的位置
control_persist = 60s # 60s沒(méi)有ssh連接就關(guān)閉主連接
4.2 pipelining
ansible執(zhí)行過(guò)程中,他會(huì)基于調(diào)用的模塊生成一個(gè)python腳本,然后將python腳本復(fù)制到主機(jī)上,最后執(zhí)行腳本.ansible支持一個(gè)優(yōu)化,叫做pipelining,在這個(gè)模式下ansible執(zhí)行腳本時(shí)并不會(huì)去復(fù)制它,而是通過(guò)管道傳遞給ssh會(huì)話,這會(huì)讓ansible的ssh會(huì)話從2個(gè)減少到1個(gè),從而節(jié)省時(shí)間.
pipelining默認(rèn)是關(guān)閉的, 因?yàn)樗枰_認(rèn)被管理主機(jī)上的/etc/sudoers文件中的requiretty
沒(méi)有啟用, 格式如下:
Defaults: <username> !requiretty
ansible開啟pipelining方法, 修改ansible.cfg配置文件:
[defaults]
pipelining = True
4.3 fact緩存
ansible playbook會(huì)默認(rèn)先收集fact信息,如果不需要fact數(shù)據(jù)可以在playbook中禁用fact采集:
- name: not need facts
hosts: myhosts
gather_facts: False
tasks:
...
也可以全局禁用fact采集:
[defaults]
gathering = explicit
另一種解決方案就是使用fact緩存,目前ansible支持下面幾種fact緩存:
- JSON文件
- Redis
- memcached
JSON文件做fact緩存示例
ansible把采集到的fact寫入控制主機(jī)的json文件中,如果文件已經(jīng)存在,那么ansible不會(huì)再去主機(jī)上采集fact
啟用JSON文件緩存,修改ansible.cfg文件:
[defaults]
gathering = smart
# 設(shè)置超時(shí)時(shí)間
face_caching_timeout = 86400
# 使用JSON文件做為緩存后端
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_fact_cache
4.4 并發(fā)數(shù)
ansible默認(rèn)并發(fā)數(shù)是5,可以用下面兩種方法修改并發(fā)數(shù):
- 環(huán)境變量方式
export ANSIBLE_FORKS=20
- 設(shè)置ansible.cfg
[defaults]
forks = 20
5. ansible 與 docker
ansible內(nèi)置多種云計(jì)算相關(guān)模塊,如aws,openstack,docker等,下圖是ansible與docker相關(guān)的模塊:
5.1 使用ansible創(chuàng)建docker鏡像
通過(guò)playbook和dockerfile相結(jié)合的方式生成鏡像, 示例如下:
FROM ansible/ubuntu14.04-ansible:stable
MAINTAINER xxx
ADD ansible /srv/ansible
WORKDIR /srv/ansible
RUN ansible-playbook web-app.yaml -c local
VOLUME /srv/project/static
WORKDIR /srv/project
EXPOSE 8000
CMD ["gunicorn_django", "-c", "gunicorn.conf.py"]
5.2 啟動(dòng)容器
ansible可以通過(guò)docker模塊來(lái)操作容器,示例如下:
- name: start the postgres container
docker:
image: postgres:9.4
name: postgres
public_all_ports: True
env:
POSTGRES_USER: "{{ database_user }}"
POSTFRES_PASSWORD: "{{ database_password }}"