Ansible 不完全手冊(cè)
Ansible
認(rèn)識(shí) andsible
最早是 厄休拉*勒古恩 在 1966 年的小說(shuō) 《羅卡農(nóng)的星球》中創(chuàng)造了 Ansible 這個(gè)詞捅厂,用于表示一種能在浩瀚宇宙中即時(shí)通信的裝置官帘。
Ansible 的創(chuàng)始人 Michael DeHaan 想用這個(gè)詞來(lái)比喻能控制遠(yuǎn)端大量主機(jī)的服務(wù)器。
特點(diǎn)
- 安裝部署簡(jiǎn)單
- 學(xué)習(xí)曲線很平坦
- 支持多臺(tái)主機(jī)并行管理
- 無(wú)代理靴姿,無(wú)需在客戶機(jī)上安裝額外軟件力麸,使用的是 SSH 協(xié)議通信
- 非 root 賬戶也可運(yùn)行
- 不僅僅支持 python 涯冠,也可運(yùn)行使用任何動(dòng)態(tài)語(yǔ)言開(kāi)發(fā)的模塊
ansible 是以款自動(dòng)化管理工具炉奴,ansible 公司,同時(shí)在 ansible 的基礎(chǔ)之上蛇更,開(kāi)發(fā)了基于 Web 界面友好的 Ansible Tower IT 自動(dòng)化管理工具瞻赶。
管理方式和架構(gòu)
管理方式
Ansible 管理系統(tǒng)由控制主機(jī)和一組被管理的節(jié)點(diǎn)組成赛糟。
控制主機(jī)通過(guò) SSH 控制被控節(jié)點(diǎn),被管節(jié)點(diǎn)的 IP 等信息砸逊,在控制主機(jī)的 Ansible 的資源清單(inventory)里進(jìn)行分組管理
Ansible 通常使用 Ansible 的腳本文件來(lái)進(jìn)行具體的管理配置璧南。這個(gè)腳本文件稱為 playbook(劇本), playbook 里存放著被作用的主機(jī)和這些主機(jī)需要執(zhí)行的任務(wù)列表师逸,任務(wù)列表是順序執(zhí)行的司倚。
ansible
1. ansible 只是一個(gè)運(yùn)維管理工具而已,這個(gè)工具需要依賴操作系統(tǒng)的 ssh
所以想使用 這個(gè)工具 篓像,必須先讓 ansible 這個(gè)工具的主機(jī)和 被控制(機(jī)器)節(jié)點(diǎn) 的 ssh 連通性动知。
a. ansible 這臺(tái)主機(jī)必須有 自己的 密鑰對(duì)兒
ssh-keygen
b. 需要 ansible 這臺(tái)主機(jī)和被控制節(jié)點(diǎn)的免密登錄
ssh-copy-id 被控制節(jié)點(diǎn)的用戶@被控制節(jié)點(diǎn)的ip
ansible 的操作
2. 把被控制節(jié)點(diǎn)的相關(guān)信息(IP、 可被解析的主機(jī)名) 添加到 ansible 的資源清單中
資源清單文件 默認(rèn)是
yum 安裝的方式
/etc/ansible/hosts
3. 讓誰(shuí) 用什么模塊 干什么事/ 達(dá)到某種狀態(tài)
ansible host1 -m shell -a "ls /tmp"
## 安裝
[Ansible 官方文檔安裝指南](https://links.jianshu.com/go?to=http%3A%2F%2Fdocs.ansible.com%2Fansible%2Flatest%2Fintro_installation.html)
- 生產(chǎn)環(huán)境推薦:
yum install ansible
- 測(cè)試環(huán)境推薦
python2.6 及以上版本
控制主機(jī)應(yīng)該有這些模塊
paramiko / PyYAML / Jinja2 / httplib2
$ git clone https://github.com/ansible/ansible.git
$ cd ./ansible
$ make rpm
$ sudo rpm -Uvh ./rpm-build/ansible-*.noarch.rpm
可以能需要安裝一些軟件依賴包
報(bào)錯(cuò)信息:
AsciiDoc 'a2x' command is not installed but is required to build
解決辦法:
yum install asciidoc
File not found by glob:
這種報(bào)錯(cuò)和可能的原因是目前系統(tǒng)使用的默認(rèn)版本和 rpm 使用的 python 版本不一致员辩,建議放棄盒粮,或者使其一致。
任務(wù)執(zhí)行模式
兩種: ad-hoc 和 playbook
ad-hoc 模式奠滑,是使用單個(gè)模塊丹皱,支持批量執(zhí)行單條命令
-
playbook 模式,是 Ansible 的主要管理方式宋税,也是 Ansible 功能強(qiáng)大的關(guān)鍵
playbook 是通過(guò)多個(gè) task 集合完成的一類功能摊崭,如 Web 服務(wù)部署,數(shù)據(jù)庫(kù)批量備份等杰赛。其實(shí)可以把它看做是組合了多個(gè)模塊和多條 ad-hoc 操作的配置文件呢簸。基于推送(push)的方式執(zhí)行任務(wù)
Ansible 內(nèi)置模塊都是等冪的。
同一個(gè)任務(wù)執(zhí)行都此淆攻,得到的效果會(huì)是一樣的阔墩。比如說(shuō)嘿架,創(chuàng)建一個(gè)用戶或這目錄瓶珊,被控主機(jī)假如沒(méi)有則創(chuàng)建,假如已存在耸彪,ansible 則什么也不做伞芹。
==工作中最后自己編排適用于自己環(huán)境的 playbook,而不是嘗試重用通用的 playbook蝉娜。學(xué)習(xí)別人的 playbook唱较,主要是看別人是如何實(shí)現(xiàn)的==
配置 Ansible 環(huán)境
Ansible 執(zhí)行命令時(shí),會(huì)按照預(yù)定配置的順序查找以下配置文件
- ANSIBLE_CONFIG 先檢查環(huán)境變量召川,以及這個(gè)環(huán)境變量指向的配置文件
- ./ansible.cfg 接著會(huì)檢查執(zhí)行命令的當(dāng)前目錄下的 ansible.cfg 配置文件
- ~/.ansible.cfg 之后會(huì)檢查當(dāng)前用戶家目錄下的 .ansible.cfg 這個(gè)隱藏文件
- /etc/ansible/ansible.cfg 最后才會(huì)檢查用軟件包管理工具安裝 ansible 時(shí)自動(dòng)產(chǎn)生的配置文件
假如你是通過(guò) GitHub 安裝的南缓,ansible.cfg 配置文件會(huì)在 example 目錄下,把它拷貝到 /etc/ansbile 目錄下即可荧呐。
ansible.cfg 配置文件常用參數(shù)
# 配置資源清單文件的路徑
inventory = /etc/ansible/hosts
# 存放 Ansible 模塊的目錄
library = /usr/share/ansible/
# 默認(rèn)進(jìn)程數(shù)
forks = 5
# 默認(rèn)執(zhí)行命令的用戶汉形,這個(gè)參數(shù)也可以在 playbook 中重新設(shè)置
sudo_user = root
# 被管主機(jī)的端口
remote_port = 22
# SSH 連接超時(shí)時(shí)間纸镊,單位是 秒
timeout = 60
# Ansible 自己的日志文件完整路徑,記錄 Ansible 輸出的內(nèi)容概疆。Ansible 默認(rèn)不記錄日志
log_path = /var/log/ansible.log
==指定注意的是: 執(zhí)行 ansible 的用戶要有在被控主機(jī)上寫(xiě)入日志的權(quán)限逗威,模塊會(huì)調(diào)用被管主機(jī)的 syslog 來(lái)記錄日志。==
使用公鑰認(rèn)證
假如第一次連接被控節(jié)點(diǎn)岔冀,控制主機(jī)默認(rèn)會(huì)檢查被控節(jié)點(diǎn)的公鑰凯旭。想禁用的話設(shè)置如下配置項(xiàng),兩種方式任選一種:
- 在 ansible.cfg 配置文件中配置
# 在 defaults 域下配置
[defaults]
host_key_checking = False
- 直接在控制主機(jī)上配置 環(huán)境變量
export ANSIBLE_HOST_KEY_CHECKING=False
配置 Linux 主機(jī) SSH 無(wú)密碼訪問(wèn)
# ssh-keygen -f ~/.ssh/id_rsa -N ""
# ssh-copy-id -i ~/.ssh/id_rsa.pub root@172.16.153.129
172.16.153.129 是被控節(jié)點(diǎn)
蜻蜓點(diǎn)水
測(cè)試連通性和 ansible 可用性
- 先在 /etc/ansible/hosts 文件中配置 被控主機(jī)
# 單個(gè)主機(jī)
172.16.153.129
# 主機(jī)組
[openstack]
192.168.2.10
192.168.2.20
192.168.2.30
192.168.2.40
- 配置 SSH 證書(shū)信任的情況下
由于是第一次和這些主機(jī)建立連接使套,我在 ansible.cfg 配置文件中設(shè)置了不檢測(cè)它們的 密鑰
? ~ grep host_key_checking /etc/ansible/ansible.cfg
host_key_checking = False
- 開(kāi)始使用 ping 模塊測(cè)試罐呼,測(cè)試了 openstack 組的主機(jī)連通性
? ~ ansible openstack -m ping
192.168.2.10 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.2.40 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.2.30 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.2.20 | SUCCESS => {
"changed": false,
"ping": "pong"
}
測(cè)完后,我把檢查密鑰的配置項(xiàng)進(jìn)行了注釋
? ~ grep host_key_checking /etc/ansible/ansible.cfg
#host_key_checking = False
這樣就檢查第一次連接的主機(jī)侦高,但是我們?cè)俅芜B接剛才我們測(cè)試的主機(jī)就不會(huì)再次檢查了弄贿。
因?yàn)閯偛旁诮⑦B接的過(guò)程中,被控主機(jī)的公鑰已經(jīng)存放到我們控制主機(jī)的一個(gè)文件里了矫膨。
~/.ssh/known_hosts # 這里存放了受信任的公鑰
-
也可以使用普通用戶進(jìn)行連接差凹,并通過(guò) --sudo 參數(shù)實(shí)現(xiàn) root 權(quán)限
前提條件是: 這個(gè)普通用戶是 sudo 用戶
-u 指定普通用戶
ansible openstack -m ping -u ansible --sudo
獲取幫助
- Ansible 的每個(gè)工具,都可以在其后面加上 -h 或者 --help 直接獲取幫助信息
[ansible@ansible ~]$ ansible-doc -h
Usage: ansible-doc [options] [module...]
Options:
-a, --all Show documentation for all modules
-h, --help show this help message and exit
-l, --list List available modules
-M MODULE_PATH, --module-path=MODULE_PATH
specify path(s) to module library (default=None)
-s, --snippet Show playbook snippet for specified module(s)
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
- 其中 -l 可以列出支持的模塊
[ansible@ansible ~]$ ansible-doc --version
ansible-doc 2.3.2.0
[ansible@ansible ~]$ ansible-doc -l |wc -l
1039 # 太過(guò)分了2嘞凇ND颉! 2.3.2 已經(jīng)支持一千多個(gè)模塊了馁痴。
- ansible-doc 模塊名谊娇,可以列出這個(gè)模塊的描述和使用示例
ansible-doc yum
- 用 -s 參數(shù)列出模塊所支持的動(dòng)作或者說(shuō)參數(shù)
ansible-doc yum -s
命令行的調(diào)試
使用 -v 或者 -vvv 會(huì)輸出更詳細(xì)的信息
ansible openstack -m ping -vvv -u ansible --sudo
Ansible 組件介紹
Inventory (資源清單)
是存放被控節(jié)點(diǎn)主機(jī)的信息的一個(gè)文件
文件格式: INI
默認(rèn)是 /etc/ansible/hosts
在命令行里執(zhí)行命令 ansbile 和命令 ansible-playbook 時(shí),可以使用 -i 參數(shù)臨時(shí)指定:
[ansible@ansible ~]$ ansible openstack -m ping -i ./inventory.file
當(dāng)然也可以定義環(huán)境變量: ANSIBLE_HOSTS 聲明
定義被控主機(jī)和主機(jī)組
# 單個(gè)主機(jī)ip 和這個(gè)主機(jī)的 ssh 密碼
172.16.153.129 ansible_ssh_pass='ansible'
# 單個(gè)主機(jī)罗晕,指定 SSH 端口
badwolf.example.com:5309
# 也可以使用變量來(lái)指定济欢,其中 jumper 是這個(gè)主機(jī)的別名,可以使用這個(gè)別名對(duì)其操作
jumper ansible_port=5555 ansible_host=192.0.2.50
# 主機(jī)名或者FQDN小渊,主機(jī)名和 FQDN 必須要可以被控制主機(jī)解析
ansible
# 定義了一個(gè) openstack 組法褥,成員 ip 是 192.168.2.10,20酬屉,30 和 40
[openstack]
192.168.2.[10:40]
# 定義一個(gè)組半等,成員192.168.2.20,21,22
[computes]
192.168.2.[20:22]
# 定義一個(gè)組的變量
[openstack:vars]
ansible_ssh_pass='ansible'
# openstack組下面有個(gè)子組,子組名叫 computes呐萨,注意這個(gè)組必須在此文件中已被定義
[openstack:children]
computes
ansible_ssh_pass 是 Inventory 的內(nèi)置參數(shù)
==雖然可以在資源清單中定義主機(jī)組或者主機(jī)的變量杀饵,但是不建議在這里定義,最佳實(shí)戰(zhàn)是主機(jī)或者主機(jī)組要與它們的變量分開(kāi)文件存放谬擦,這些內(nèi)容安排在后面的變量章節(jié)中==
==Ansible 內(nèi)部有兩個(gè)默認(rèn)組:all(包含所有主機(jī)) and ungrouped(不屬于任何組的主機(jī))==
測(cè)試
使用小寫(xiě)字母 o 參數(shù)可以輸出更漂亮格式的信息
[ansible@ansible ~]$ ansible 192.168.2.21 -m ping -o
192.168.2.21 | SUCCESS => {"changed": false, "ping": "pong"}
[ansible@ansible ~]$ ansible openstack -m ping -o
192.168.2.21 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.22 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.20 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.30 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.10 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.40 | SUCCESS => {"changed": false, "ping": "pong"}
使用多個(gè) Inventory 文件
- 定義一個(gè)文件夾切距,里面存放不同的 inventory 文件
注意此目錄下的文件的擴(kuò)展名僅僅支持:空、.yml惨远、.ymal谜悟、.json
[ansible@ansible ~]$ sudo mkdir /etc/ansible/Inventory
[ansible@ansible ~]$ cat /etc/ansible/Inventory/openstack
[openstack]
192.168.2.10
192.168.2.30
192.168.2.40
[computes]
192.168.2.20
192.168.2.21
192.168.2.22
[openstack:children]
computes
[ansible@ansible ~]$ cat /etc/ansible/Inventory/hosts.yml
172.16.153.129
ansible
- 可以看/出定義多個(gè) inventory 文件的內(nèi)容和定義一個(gè) inventory 文件的格式一樣
- 再在 /etc/ansible/ansible.cfg 文件中的
[defaults]
配置塊中 配置 inventory 的值指向 這個(gè)文件夾
- 驗(yàn)證配置
--list-hosts 列出主機(jī)或者主機(jī)組信息
[ansible@ansible ~]$ ansible computes --list-hosts
hosts (3):
192.168.2.20
192.168.2.21
192.168.2.22
==動(dòng)態(tài) Inventory==
在目前互聯(lián)網(wǎng)環(huán)境下的實(shí)際生產(chǎn)環(huán)境中饵沧,inventory 更多的是動(dòng)態(tài)獲取的,比如從 CMDB 系統(tǒng)或者 Zabbix 監(jiān)控系統(tǒng)中拉取所有的主機(jī)信息赌躺,之后使用 Ansible 進(jìn)行管理狼牺。
動(dòng)態(tài) inventory 配置
- 在 ansible.cfg 文件中的 inventory 值定義為一個(gè)可執(zhí)行腳本,這個(gè)腳本可以是任何編程言編寫(xiě)的礼患。
[ansible@ansible ~]$ grep ^inventory /etc/ansible/ansible.cfg
inventory = /etc/ansible/hosts.py
但是這個(gè)腳本必須支持以下參數(shù):
- --list 或者 -l (小寫(xiě)英文字母) 參數(shù)功能:顯示所有的主機(jī)以及主機(jī)組信息(JSON格式)
- --host 或者 -H 這個(gè)參數(shù)后面需要指定一個(gè) host是钥,運(yùn)行結(jié)果會(huì)返回這臺(tái)主機(jī)的所有信息(包括認(rèn)證信息、主機(jī)變量等)缅叠,也是 JSON 格式悄泥。
- 編輯這個(gè)腳本
- 這里只是一個(gè)簡(jiǎn)單的腳本模板
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
import argparse
def lists():
"""
indent 定義輸出時(shí)的格式縮進(jìn)的空格數(shù)
"""
dic = {}
host_list = [ '192.168.2.{}'.format(str(i) ) for i in range(20,23) ]
hosts_dict = {'hosts': host_list}
dic['openstack'] = hosts_dict
return json.dumps(dic,indent=4)
def hosts(name):
dic = {'ansibl_ssh_pass': '12345'}
return json.dumps(dic)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-l', '--list', help='host list', action='store_true')
parser.add_argument('-H', '--host', help='hosts vars')
args = vars(parser.parse_args())
if args['list']:
print( lists() )
elif args['host']:
print( hosts(args['host']) )
else:
parser.print_help()
- 改變文件權(quán)限為可執(zhí)行
[ansible@ansible ~]$ sudo chmod 655 /etc/ansible/hosts.py
- 測(cè)試一下
先使用 -i 參數(shù)指定測(cè)試試試
[ansible@ansible ~]$ ansible -i /etc/ansible/hosts.py openstack -m ping -o
192.168.2.30 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.20 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.10 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.40 | SUCCESS => {"changed": false, "ping": "pong"}
由于前面我們?cè)O(shè)定好了 ansible.cfg 文件中的 inventory 的值為一個(gè)資源池(可動(dòng)態(tài)獲取主機(jī)信息的可執(zhí)行文件),所以可以直接執(zhí)行肤粱。
[ansible@ansible ~]$ ansible openstack -m ping -o
192.168.2.30 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.20 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.10 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.40 | SUCCESS => {"changed": false, "ping": "pong"}
使用混合模式的 inventory
如果在 Ansible 中 -i 給出的位置是一個(gè)目錄弹囚,或者像上一節(jié) 使用多個(gè) Inventory 文件
中的情況,在 ansible.cfg 中這樣配置了 inventory 的值是一個(gè)資源池领曼。
- 在清單目錄中鸥鹉,可執(zhí)行文件將被視為動(dòng)態(tài)清單來(lái)源,而大多數(shù)其他文件則被視為靜態(tài)來(lái)源庶骄。
這樣使用的就是混合云了
- 在清單目錄中毁渗,以下結(jié)尾的文件將被忽略
~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo
這個(gè)忽略的列表可以在 ansible.cfg 文件中配置,或者使用此項(xiàng) ANSIBLE_INVENTORY_IGNORE
配置環(huán)境變量单刁。
inventory_ignore_extensions
- 配置 /etc/ansible/ansible.cfg
[ansible@ansible ~]$ grep ^inventory /etc/ansible/ansible.cfg
inventory = /etc/ansible/Inventory/
- 靜態(tài) inventory 文件
[ansible@ansible ~]$ cat /etc/ansible/Inventory/openstack
[openstack]
192.168.2.10
192.168.2.30
192.168.2.40
[openstack:children]
computes
# 注意這里定義的組名灸异,并沒(méi)有在這個(gè)文件中定義此組的主機(jī),我將會(huì)在動(dòng)態(tài) inventory 文件中定義羔飞。
# 關(guān)注驗(yàn)證結(jié)果肺樟,會(huì)是正常的,這樣證明了使用了混合 inventory 是成功的逻淌。
- 動(dòng)態(tài) inventory 腳本文件
[ansible@ansible ~]$ ls -l /etc/ansible/Inventory/hosts.py
-rw-r-xr-x 1 root root 840 Nov 18 14:19 /etc/ansible/Inventory/hosts.py
[ansible@ansible ~]$ cat /etc/ansible/Inventory/hosts.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
import argparse
def lists():
"""
indent 定義輸出時(shí)的格式縮進(jìn)的空格數(shù)
"""
dic = {}
host_list = [ '192.168.2.{}'.format(str(i) ) for i in range(20,23) ]
hosts_dict = {'hosts': host_list}
dic['computes'] = hosts_dict # 靜態(tài)文件中的組么伯,在這里定義了主機(jī)信息
return json.dumps(dic,indent=4)
def hosts(name):
dic = {'ansibl_ssh_pass': '12345'}
return json.dumps(dic)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-l', '--list', help='host list', action='store_true')
parser.add_argument('-H', '--host', help='hosts vars')
args = vars(parser.parse_args())
if args['list']:
print( lists() )
elif args['host']:
print( hosts(args['host']) )
else:
parser.print_help()
- 驗(yàn)證配置
[ansible@ansible ~]$ ansible openstack -m ping -o
192.168.2.20 | SUCCESS => {"changed": false, "ping": "pong"} # 動(dòng)態(tài) inventory 腳本文件獲取的主機(jī)
192.168.2.22 | SUCCESS => {"changed": false, "ping": "pong"} # 動(dòng)態(tài) inventory 腳本文件獲取的主機(jī)
192.168.2.30 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.10 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.21 | SUCCESS => {"changed": false, "ping": "pong"} # 動(dòng)態(tài) inventory 腳本文件獲取的主機(jī)
192.168.2.40 | SUCCESS => {"changed": false, "ping": "pong"}
[ansible@ansible ~]$ ansible computes -m ping -o
192.168.2.21 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.22 | SUCCESS => {"changed": false, "ping": "pong"}
192.168.2.20 | SUCCESS => {"changed": false, "ping": "pong"}
動(dòng)態(tài)組和靜態(tài)組
- When defining groups of groups in the static inventory file, the child groups must also be defined in the static inventory file, or ansible will return an error.
在靜態(tài)庫(kù)存文件中定義一些子組時(shí),這個(gè)些子組是有一些限制的:
- 假如聲明的子組是靜態(tài)組恍风,還必須在靜態(tài)庫(kù)存文件中定義這些子組蹦狂,就是需要包含具體的 host,否則將返回一個(gè)錯(cuò)誤朋贬。下面是一個(gè)錯(cuò)誤的例子,我在靜態(tài) inventory 文件為組 opentack 定義了一個(gè)子組 networks 窜骄,但是我沒(méi)有在這個(gè)靜態(tài) inventory 文件中定義這個(gè)子組 networks 及其成員锦募。也沒(méi)有在動(dòng)態(tài)腳本中定義它
[ansible@ansible Inventory]$ cat openstack
[openstack]
192.168.2.10
192.168.2.30
192.168.2.40
[openstack:children]
networks
computes
* 所以 ansible 報(bào)錯(cuò)了。
[ansible@ansible Inventory]$ ansible openstack -m ping -o
ERROR! Attempted to read "/etc/ansible/Inventory/openstack" as YAML: 'AnsibleUnicode' object has no attribute 'keys'
Attempted to read "/etc/ansible/Inventory/openstack" as ini file: /etc/ansible/Inventory/openstack:7: Section [openstack:children] includes undefined group: networks
==經(jīng)過(guò)驗(yàn)證邻遏,在靜態(tài) inventory 文件中定義這個(gè)子組為空糠亩,也不會(huì)報(bào)錯(cuò)==
[圖片上傳失敗...(image-29f9c3-1543815968457)]
- If you want to define a static group of dynamic child groups, define the dynamic groups as empty in the static inventory file.
如果要定義的靜態(tài)組是動(dòng)態(tài)組的子組虐骑,請(qǐng)?jiān)陟o態(tài)庫(kù)存文件中將動(dòng)態(tài)組定義為空。
For example:
# 這里是靜態(tài) inventory 文件
[tag_Name_staging_foo]
[tag_Name_staging_bar]
[staging:children]
tag_Name_staging_foo
tag_Name_staging_bar
Ad-Hoc 命令
所謂 ad-hoc 命令是什么呢?
這其實(shí)是一個(gè)概念性的名字,是相對(duì)于寫(xiě) Ansible playbook 來(lái)說(shuō)的赎线。兩者之間的關(guān)系類似于在命令行敲入shell命令和 寫(xiě)shell scripts兩者之間的關(guān)系
Ansible 命令都是并發(fā)執(zhí)行的廷没,默認(rèn)的并發(fā)數(shù)是 ansible.cfg 中的 forks 值來(lái)控制的。
運(yùn)行 ansible 命令行時(shí)可以用 -f 指定并發(fā)數(shù)垂寥。
基本格式:
ansible <pattern_goes_here> -m <module_name> -a <arguments>
- patterm_goes_here 是主機(jī)名颠黎、IP、或者已定義的主機(jī)組名
- module_name 模塊名
- arguments 參數(shù)
示例:
ansible computes -m shell -a "ls /tmp" -f 10
ansible有許多模塊,默認(rèn)是 command
,也就是命令模塊,我們可以通過(guò) -m 選項(xiàng)來(lái)指定不同的模塊.
在 Ad-Hoc 中使用默認(rèn)的 command
模塊執(zhí)行命令時(shí)滞项,-m 參數(shù) 可省略狭归,但是不支持管道。想支持的話就是用 shell
模塊文判。
使用異步模式
- 使用異步功能过椎,請(qǐng)使用 -P 參數(shù)
-P 0 會(huì)直接返回 job_id,然后可以根據(jù)主機(jī)的 job_id 查詢執(zhí)行結(jié)果
==2.3.2 版本沒(méi)有返回 job_id==
File Transfer
- 把控制主機(jī)本地文件拷貝到遠(yuǎn)端被控主機(jī)
copy
ansible test -m copy -a "src=/path/to/sourcefile dest=/path/to/destinationfile"
==在 playbook 里也可以用 template==
- 可以添加一些可選選項(xiàng)
[ansible@ansible ~]$ ansible test -m copy -a "src=./add_ip.sh dest=/home/elk/add_ip_3.sh owner=elk group=elk mode=444" -o --sudo
[ansible@ansible ~]$ sudo ls -l /home/elk/
total 4
-r--r--r-- 1 elk elk 354 Nov 20 08:29 add_ip_3.sh
- 直接更改遠(yuǎn)程被控主機(jī)的文件權(quán)限等信息
file
[ansible@ansible ~]$ ansible test -m file -a "dest=/home/elk/add_ip_3.sh owner=ansible mode=644 group=ansible" -o --sudo
172.16.153.129 | SUCCESS => {"changed": true, "gid": 501, "group": "ansible", "mode": "0644", "owner": "ansible", "path": "/home/elk/add_ip_3.sh", "size": 354, "state": "file", "uid": 501}
[ansible@ansible ~]$ sudo ls -l /home/elk/
total 4
-rw-r--r-- 1 ansible ansible 354 Nov 20 08:29 add_ip_3.sh
-
file
模塊也可以創(chuàng)建和刪除目錄戏仓,支持遞歸
[ansible@ansible ~]$ ansible test -m file -a "dest=/home/elk/a/b/c/ state=directory" -o --sudo
state=file 代表拷貝后是文件疚宇;
state=link 代表最終是個(gè)軟鏈接;
state=directory 代表文件夾赏殃;
state=hard 代表硬鏈接灰嫉;
state=touch 代表生成一個(gè)空文件;
state=absent 代表刪除
Managing Packages
- 安裝軟件包
假如軟件包安裝了嗓奢,則不做任何操作讼撒;沒(méi)安裝,則安裝:
$ ansible webservers -m yum -a "name=httpd state=present" --sudo -o
- 指定版本安裝:
$ ansible webservers -m yum -a "name=httpd-2.2.15 state=present" --sudo -o
- 卸載軟件包:
$ ansible webservers -m yum -a "name=acme state=absent" --sudo -o
Users and Groups
使用 user
模塊可以方便的創(chuàng)建賬戶,刪除賬戶,或是管理現(xiàn)有的賬戶:
# 創(chuàng)建用戶
## 首先應(yīng)該創(chuàng)建一個(gè) MD5 加密的密文股耽,ansible 的 user 模塊的 password 不接收明文密碼
$ [ansible@ansible ~]$ echo test |openssl passwd -1 -stdin
$1$QzUtKCgG$q8jXR8iaImWNjk5DKtnYf1 # 把輸出的密文復(fù)制給下面的命令
$ ansible test -m user -a 'name=test password="$1$QzUtKCgG$q8jXR8iaImWNjk5DKtnYf1" ' --sudo -o
# 刪除用戶
$ ansible all -m user -a "name=foo state=absent" --sudo -o
Managing Services
# 啟動(dòng)服務(wù)
$ ansible webservers -m service -a "name=httpd state=started" --sudo -o
# 重啟服務(wù)
$ ansible webservers -m service -a "name=httpd state=restarted" --sudo -o
# 停止服務(wù)
$ ansible webservers -m service -a "name=httpd state=stopped" --sudo -o
獲取主機(jī)的信息
- facts
# 獲取全部信息
$ ansible test -m setup
# 獲取指定信息根盒,下面是獲取 綁定網(wǎng)卡的地址
$ ansible test -m setup |grep bond
- facter 獲取主機(jī)的靜態(tài)信息(Puppet)
[ansible@ansible ~]$ ansible test -m yum -a "name=ruby-json,facter state=installed" --sudo -o
[ansible@ansible ~]$ ansible test -m facter
- python 實(shí)現(xiàn)
import json
import subprocess
res = subprocess.getoutput("ansible 172.16.153.130 -m setup")
if 'SUCCESS' in res:
res_dic_str = s.split('SUCCESS =>')[1]
res_dic_obj = json.loads(res_dic_str)
for k,v in res_dic_obj['ansible_facts'].items():
print(k,'==',v)
Playbook 詳解
Ansible 的 playbook 文件格式使用的是 YAML 語(yǔ)法。
YAML 語(yǔ)法參考 -->> 官網(wǎng)
簡(jiǎn)單來(lái)說(shuō),playbooks 是一種簡(jiǎn)單的配置管理系統(tǒng)與多機(jī)器部署系統(tǒng)的基礎(chǔ).與現(xiàn)有的其他系統(tǒng)有不同之處,且非常適合于復(fù)雜應(yīng)用的部署.
Playbooks 可用于聲明配置,更強(qiáng)大的地方在于,在 playbooks 中可以編排有序的執(zhí)行過(guò)程,甚至于做到在多組機(jī)器間,來(lái)回有序的執(zhí)行特別指定的步驟.并且可以同步或異步的發(fā)起任務(wù)
基本的 YAML 語(yǔ)法
對(duì)于 Ansible, 每一個(gè) YAML 文件都是從一個(gè)列表開(kāi)始. 列表中的每一項(xiàng)都是一個(gè)鍵值對(duì), 通常它們被稱為一個(gè) “哈衔矧” 或 “字典”. 所以, 我們需要知道如何在 YAML 中編寫(xiě)列表和字典.
所有的 YAML 文件(無(wú)論和 Ansible 有沒(méi)有關(guān)系)首行都應(yīng)該是 ---. 這是 YAML 格式的一部分, 表明一個(gè) YAML 文件的開(kāi)始.
- 列表 中的所有成員都開(kāi)始于相同的縮進(jìn)級(jí)別, 并且使用一個(gè) "- " 作為開(kāi)頭(一個(gè)橫杠和一個(gè)空格):
---
# 一個(gè)美味水果的列表
- Apple
- Orange
- Strawberry
- Mango
- 一個(gè)字典是由一個(gè)簡(jiǎn)單的 鍵: 值 的形式組成(這個(gè)冒號(hào)后面必須是一個(gè)空格):
---
# 一位職工的記錄
name: Example Developer
job: Developer
skill: Elite
- 指定一個(gè)布爾值(true/fase)
---
create_key: yes
needs_agent: no
knows_oop: True
likes_emacs: TRUE
uses_cvs: false
- 組合在一起的示例
---
# 一位職工記錄
name: Example Developer
job: Developer
skill: Elite
employed: True
foods:
- Apple
- Orange
languages:
ruby: Elite
python: Elite
# 相當(dāng)于 {'name': "Example Developer",'job': 'Developer', 'skill': 'Elite', 'employed': True, 'foods': ['Apple', 'Orange'], 'languages': {'ruby': 'Elite', 'python': 'Elite'}}
需要額外注意的地方
- 用引號(hào)把含有冒號(hào)的值包含起來(lái)
foo: ""somebody said I should put a colon here: so I did""
- 用 "{{ var }}" 來(lái)對(duì)變量進(jìn)行引用
foo: "{{ variable }}"
編寫(xiě) Ansible playbooks 掌握以上 YAML 基本的語(yǔ)法就可以了炎滞,下面就來(lái)討論一下 playbook 的語(yǔ)法
Playbook 基本語(yǔ)法
Playbook 其實(shí)并不是那么神秘,要理解 playbook 很簡(jiǎn)單诬乞。
想理解 playbook 册赛,首先需要懂得 Ansible 的命令行模式,即 Ad-Hoc 命令震嫉。
對(duì)于 ansible 來(lái)說(shuō)記住 3 句話森瘪,對(duì)應(yīng)了 ansible 實(shí)現(xiàn)功能的基本組成部分
- 針對(duì)的目標(biāo)是誰(shuí)?
- 讓目標(biāo)做什么票堵,其中包含了具體怎么做扼睬?
- 假如在做的過(guò)程中,有變化了悴势,再做什么窗宇?
下面看一個(gè) Ad-Hoc 命令的示例:
ansible webservers -m copy -a "src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf"
# webservers 就是目標(biāo)
# -m copy 就是做什么
# -a "src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf" 就是具體怎么做
對(duì)于第 3 項(xiàng)措伐,在命令行里,是用再此執(zhí)行另外一條命令來(lái)實(shí)現(xiàn)的
ansible webservers -m service -a "name=httpd state=restarted"
想象一下這種情況军俊,當(dāng)你想對(duì)目標(biāo)主機(jī)安裝一個(gè)服務(wù)侥加,并且配置一下這個(gè)服務(wù)的配置文件,之后啟動(dòng)這個(gè)服務(wù)時(shí)粪躬。你會(huì)發(fā)現(xiàn)担败,你需要在命令行里執(zhí)行一系列的 Ad-Hoc 命令。
于是你會(huì)想要有一種方法把這些整合在其一短蜕,一起執(zhí)行氢架,并且在執(zhí)行的過(guò)程中加入一些邏輯判斷,就像是寫(xiě) shell 腳本一樣朋魔。這種方法就是 playbook岖研。
在 ansible 中,playbook 的內(nèi)容,一般有三部分組成:
* hosts
* tasks
* handlers
hosts 就是目標(biāo)
tasks(任務(wù)列表) 就是讓目標(biāo)做什么以及怎么做;一個(gè) task 也稱為一個(gè) play警检,本質(zhì)是對(duì) ansible 一個(gè)模塊的調(diào)用孙援。
handlers 就是當(dāng)執(zhí)行過(guò)程中,目標(biāo)的某些方面發(fā)生了改變扇雕,就會(huì)被觸發(fā)的動(dòng)作拓售,這些動(dòng)作也是一個(gè)一個(gè)的 task
下面通過(guò)一個(gè)簡(jiǎn)單的 playbook 來(lái)具體說(shuō)明一下基本的語(yǔ)法
--- # 表示這個(gè)文件是 YMAL 文件
- hosts: webservers # 指定了 webservers 這個(gè)主機(jī)組為 這個(gè) playbook 的目標(biāo)主機(jī),也可以用 all 表示所有主機(jī)镶奉,其實(shí)支持 Ad-Hoc 模式的所有參數(shù)
vars: # 表示下面是目標(biāo)主機(jī)的變量
http_port: 80
max_clients: 200
remote_user: root # 遠(yuǎn)程被控主機(jī)的用戶名铃拇,用這個(gè)用戶去執(zhí)行下面所用的 tasks
tasks: # 表示下面是這個(gè) playbook 的一個(gè)或者多個(gè)任務(wù)的集合
- name: ensure apache is at the latest version # 給每個(gè)具體任務(wù)起的名字
yum: pkg=httpd state=latest # 第一個(gè)具體的任務(wù)端考,是安裝最新版的 httpd 軟件包边篮,調(diào)用了 Ansible 的 yum 模塊
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf # 第二個(gè)具體的任務(wù)拷貝配置文件
notify: # 觸發(fā)的意思篮赢,假如 httpd.conf 配置文件的 MD5 值有變化,就會(huì)觸發(fā)下面定義的 handlers
- restart apache # 這個(gè)是觸發(fā)的具體事件名字
- name: ensure apache is running
service: name=httpd state=started # 第三個(gè)具體的任務(wù)建峭,啟動(dòng) httpd 服務(wù)
handlers:
- name: restart apache # 這個(gè) name 的值需要和上面 notify 的值一致
service: name=httpd state=restarted # 定義具體 handlers 的狀態(tài)玻侥,重啟 httpd 服務(wù)
Playbook 基本結(jié)構(gòu)分解
一個(gè)基本的 playbook 的機(jī)構(gòu)包括:
- hosts(主機(jī)和用戶) 用于指明 playbook 作用的目標(biāo)
- tasks(任務(wù)列表 ) 用于定義 playbook 所要執(zhí)行的操作,比如安裝軟件亿蒸,拷貝文件等
- handlers (在發(fā)生改變時(shí)會(huì)被觸發(fā)的操作)
Hosts
- hosts 一行的值可以是一個(gè)或者多個(gè)主機(jī)凑兰,也可以一個(gè)或者多個(gè)主機(jī)組,之間用逗號(hào)分隔边锁;
---
- hosts: 172.16.153.129,ansible # 這些主機(jī)是必須在資源配置文件(Inventory)中定義好了
- 用 remote_user 設(shè)置對(duì)遠(yuǎn)程被控主機(jī)執(zhí)行操作的用戶
---
- hosts: 172.16.153.129,ansible
remote_user: root
- 也可以這對(duì)每個(gè) task 設(shè)置用戶
---
- hosts: 172.16.153.129,ansible
remote_user: root
tasks:
- name: ping cmd
ping:
remote_user: ansible # ansible 是遠(yuǎn)程被控主機(jī)的用戶名
- 支持 sudo
---
- hosts: webservers
remote_user: yourname
sudo: yes
tasks:
- service: name=nginx state=started
remote_user: yourname
sudo: yes
- sudo 為指定的用戶
---
- hosts: webservers
remote_user: yourname
sudo: yes
sudo_user: postgres
Tasks 列表
每個(gè) playbook 都會(huì)有一個(gè) tasks 列表姑食,列表中的每個(gè) task 會(huì)作用于所有的 hosts 值中聲明的主機(jī)。
每個(gè) task 的目標(biāo)是執(zhí)行一個(gè) ansible 的模塊砚蓬。
tasks 列表中的 task 執(zhí)行是按照從上向下順序執(zhí)行的矢门。
假如在 hosts 中的某一個(gè) host 執(zhí)行某一個(gè) task 失敗,此 host 將會(huì)從整個(gè) playbook 的 rotation(循環(huán)) 中移除. 如果發(fā)生執(zhí)行失敗的情況,請(qǐng)修正 playbook 中的錯(cuò)誤,然后重新執(zhí)行即可.
每一個(gè) task 必須有一個(gè)名稱 name,這樣在運(yùn)行 playbook 時(shí),從其輸出的任務(wù)執(zhí)行信息中可以很好的辨別出是屬于哪一個(gè) task 的灰蛙。
聲明一個(gè) task 使用格式:”module: options”
基本的 task 的定義,service moudle 使用 key=value 格式的來(lái)表示 moudle 的參數(shù),這也是大多數(shù) moudle 使用的參數(shù)格式:
tasks:
- name: make sure apache is running
service: name=httpd state=running
- 特殊的 moudle
command 和 shell
tasks:
- name: disable selinux
command: /sbin/setenforce 0
- name: test shell moudle
shell: /bin/ls /
在執(zhí)行命令時(shí)祟剔,可以忽略執(zhí)行命令中的錯(cuò)誤
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
- 可以使用 space(空格) 或者 indent(縮進(jìn)) 隔開(kāi)連續(xù)的一行
tasks:
- name: Copy ansible inventory file to client
copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
owner=root group=root mode=0644
- 使用變量
tasks:
- name: create a virtual host file for {{ vhost }}
template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
變量需要提前在 vars 里定義,后面會(huì)講到如何定義變量
- notify 設(shè)定觸發(fā)的事件
notify 在每一個(gè)任務(wù)執(zhí)行結(jié)束時(shí)會(huì)被觸發(fā)摩梧,并且即使多個(gè) task 指定了同一個(gè) notify action 物延,觸發(fā)條件達(dá)到時(shí), notify action 只會(huì)被執(zhí)行一次仅父。
下面示例中是當(dāng)文件有改變時(shí)叛薯,重啟 2 個(gè)服務(wù)
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
==ntify 列表中每個(gè)值,需要和 Handlers 中的 name 值相同笙纤。==
Handlers: 在發(fā)生改變時(shí)執(zhí)行的操作
Handlers 也是一些 task 的列表,通過(guò)名字來(lái)引用,如果沒(méi)有被 notify,handlers 不會(huì)執(zhí)行.不管有多少個(gè)通知者進(jìn)行了 notify,等到 play 中的所有 task 執(zhí)行完成之后,handlers 也只會(huì)被執(zhí)行一次.
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
==Handlers 最佳的應(yīng)用場(chǎng)景是用來(lái)重啟服務(wù),或者觸發(fā)系統(tǒng)重啟操作.除此以外很少用到.==
==handlers 會(huì)按照聲明的順序執(zhí)行==
- 立刻執(zhí)行正在排隊(duì)的 handler 命令
默認(rèn) handlers 會(huì)在 ‘pre_tasks’, ‘roles’, ‘tasks’, 和 ‘post_tasks’ 之間自動(dòng)執(zhí)行.
tasks:
- shell: some tasks go here
- meta: flush_handlers
- shell: some other tasks
執(zhí)行 playbook
- 并發(fā) 10 個(gè)進(jìn)程執(zhí)行
ansible-playbook playbook.yml -f 10
- 指定一個(gè) Inventory 執(zhí)行 playbook.yml
ansible-playbook -i /etc/ansible/Inventory/hosts.yml playbook.yml -f 10
- 查看一個(gè) playbook 作用的目標(biāo)主機(jī)信息: --list-host
ansible-playbook -i /etc/ansible/Inventory/hosts.yml test.yaml --list-host
- 使用調(diào)試模式
如果你想看到執(zhí)行成功的 modules 的輸出信息,使用 --verbose 或者 -v(否則只有執(zhí)行失敗的才會(huì)有輸出信息)
ansible-playbook -i /etc/ansible/Inventory/hosts.yml test.yaml -v
==可以使用 -vvv 或者 -vvvv 查看更多的輸出信息==
Playbook 角色(Roles) 和 Include 語(yǔ)句
當(dāng)我們剛開(kāi)始學(xué)習(xí)運(yùn)用 playbook 時(shí)耗溜,可能會(huì)把 playbook 寫(xiě)成一個(gè)很大的文件,到后來(lái)可能你會(huì)希望這些文件是可以方便去重用的省容,就像你在寫(xiě)腳本時(shí)抖拴,會(huì)把 變量寫(xiě)在一個(gè)文件中,靜態(tài)文件放在一個(gè)目錄中腥椒,函數(shù)寫(xiě)在一個(gè)文件中阿宅,所以想管理好 playbook 就需要重新去組織這些文件。
使用 include 語(yǔ)句引用 tasks 是將 tasks 從其他文件拉取過(guò)來(lái)笼蛛。
因?yàn)?handlers 也是 tasks洒放,所以你也可以使用 include 語(yǔ)句去引用 handlers 文件。
Playbook 同樣可以使用 include 引用其他 playbook 文件中的 play滨砍。這時(shí)被引用的 play 會(huì)被插入到當(dāng)前的 playbook 中往湿,當(dāng)前的 playbook 中就有了一個(gè)更長(zhǎng)的的 play 列表。
Roles 的概念來(lái)自于這樣的想法:通過(guò) include 包含文件并將它們組合在一起惋戏,組織成一個(gè)簡(jiǎn)潔领追、可重用的抽象對(duì)象。
可以認(rèn)為主要是用于管理多 playbook,本質(zhì)是對(duì)日常使用的 playbook 的目錄結(jié)構(gòu)進(jìn)行一些規(guī)范日川。
每次你寫(xiě) playbook 的時(shí)候都應(yīng)該使用 Roles蔓腐。
下面先介紹 Include 語(yǔ)句
Inclued
- 一個(gè)被引用的 task 文件一般是這樣子的
---
# possibly saved as tasks/foo.yml
- name: placeholder foo
command: /bin/foo
- name: placeholder bar
command: /bin/bar
- 在一個(gè) playbook 中引用一個(gè) task 文件
tasks:
- include: tasks/foo.yml
- 可以給 include 傳遞變量。稱之為 '參數(shù)化的 include'
tasks:
- include: wordpress.yml wp_user=timmy
- include: wordpress.yml wp_user=alice
- include: wordpress.yml wp_user=bob
- 在一個(gè) playbook 中的 task 里引用一個(gè) 變量文件
假如有這樣的設(shè)定:
---
# file: group_vars/all
asdf: 10
---
# file: group_vars/os_CentOS
asdf: 42
可以這樣引用
- hosts: all
tasks:
- include_vars: "os_{{ ansible_distribution }}.yml"
- debug: var=asdf
- 更精簡(jiǎn)的 include 語(yǔ)法
適用于 1.4 及之后的版本
tasks:
- { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] }
- handlers 的 include
假如你定義了一個(gè)重啟 httpd 服務(wù)的 handlers龄句,并且想要重用他回论,可以這么做
- 先創(chuàng)建這個(gè) handlers 文件,名字叫 handers.yml
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apache state=restarted
- 引用它
然后在你的主 playbook 文件中分歇,在一個(gè) play 的最后使用 include 包含 handlers.yml
handlers:
- include: handlers/handlers.yml
==Include 語(yǔ)句可以和其他非 include 的 tasks 和 handlers 混合使用傀蓉。但是這種情況下,include 的優(yōu)先級(jí)最高==
- 在一個(gè)playbook中引用其他的 playbook 的例子
- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
接下來(lái)职抡,我們就來(lái)談一談如何很好利用 include 語(yǔ)句葬燎,并且更好的來(lái)組織 playbook
Role
- 一個(gè) Roles 項(xiàng)目的目錄結(jié)構(gòu)如下:
.
├── fooserver.yml
├── roles
│ ├── common # 一個(gè) role
│ │ ├── defaults # 放置一個(gè) role 的默認(rèn)變量文件
│ │ ├── files # 一般放置靜態(tài)文件
│ │ ├── handlers # 發(fā)生改變時(shí)做的 handlers 文件
│ │ ├── meta # 放置 role 的依賴文件
│ │ ├── tasks # 放置 task 文件
│ │ ├── templates # 放模板文件
│ │ └── vars # 放置變量文件
│ └── webservers # 另一個(gè) role
│ ├── defaults
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
├── site.yml # Roles 的入口文件,也是一個(gè) playbook
└── webserver.yml
- 一般在 site.yml 這個(gè) playbook 中來(lái)使用這個(gè) roles
---
- hosts: webservers
roles:
- common
- webservers
假如這個(gè) playbook 為 'http' 這個(gè)角色定義的,那么有如下意義:
- 如果 roles/http/tasks/main.yml 存在, 其中列出的 tasks 將被添加到 play 中
- 如果 roles/http/handlers/main.yml 存在, 其中列出的 handlers 將被添加到 play 中
- 如果 roles/http/vars/main.yml 存在, 其中列出的 variables 將被添加到 play 中
- 如果 roles/http/meta/main.yml 存在, 其中列出的 “角色依賴” 將被添加到 roles 列表中 (1.3 and later)
- 所有 copy tasks 可以引用 roles/http/files/ 中的文件谱净,不需要指明文件的路徑窑邦。
- 所有 script tasks 可以引用 roles/http/files/ 中的腳本,不需要指明文件的路徑壕探。
- 所有 template tasks 可以引用 roles/http/templates/ 中的文件冈钦,不需要指明文件的路徑。
- 所有 include tasks 可以引用 roles/http/tasks/ 中的文件李请,不需要指明文件的路徑瞧筛。
如果 roles 目錄下有文件不存在,這些文件將被忽略导盅。比如 roles 目錄下面缺少了 ‘vars/’ 目錄较幌,這也沒(méi)關(guān)系。
- 當(dāng)一些事情不需要頻繁去做時(shí)白翻,你也可以為 roles 設(shè)置觸發(fā)條件乍炉,像下面這樣
---
# This is site.yml file
- hosts: webservers
roles:
- { role: some_role, when: "ansible_os_family == 'RedHat'" }
它的工作方式是:將條件子句應(yīng)用到 role 中的每一個(gè) task 上。
- 定義一些 tasks嘁字,讓它們?cè)?roles 之前以及之后執(zhí)行
---
- hosts: webservers
pre_tasks:
- shell: echo 'hello'
roles:
- { role: some_role }
tasks:
- shell: echo 'still busy'
post_tasks:
- shell: echo 'goodbye'
- 關(guān)于 role 的默認(rèn)變量
要?jiǎng)?chuàng)建默認(rèn)變量恩急,只需在 roles 目錄下添加 defaults/main.yml 文件。這些變量在所有可用變量中擁有最低優(yōu)先級(jí)纪蜒,可能被其他地方定義的變量(包括 inventory 中的變量)所覆蓋衷恭。
角色依賴(Role Dependencies)
New in version 1.3.
“角色依賴” 使你可以自動(dòng)地將其他 roles 拉取到現(xiàn)在使用的 role 中〈啃”角色依賴” 保存在 roles 目錄下的 meta/main.yml 文件中随珠。這個(gè)文件應(yīng)包含一列 roles 和 為之指定的參數(shù),下面是在 roles/myapp/meta/main.yml 文件中的示例:
---
dependencies:
- { role: common, some_parameter: 3 }
- { role: apache, port: 80 }
- { role: postgres, dbname: blarg, other_parameter: 12 }
更多參考 https://ansible-tran.readthedocs.io/en/latest/docs/playbooks_roles.html
Galzxy
Ansible 的 Galaxy 是 Ansible 官方一個(gè)分析 role 的功能平臺(tái)猬错。
網(wǎng)址
https://galaxy.ansible.com/list#/roles
安裝(下載)一個(gè) role
[圖片上傳失敗...(image-45cf85-1543815968457)]
默認(rèn)安裝在以下目錄下
/etc/ansible/roles/
使用方式和自己寫(xiě)的 role 一樣
變量與引用
==In Ansible 1.2 or later the group_vars/ and host_vars/ directories can exist in the playbook directory OR the inventory directory. If both paths exist, variables in the playbook directory will override variables set in the inventory directory.==
假如變量同時(shí)存在于 playbook 目錄和 inventory 目錄窗看,playbook 目錄的變量?jī)?yōu)先
合法的變量名
在使用變量之前最好先知道什么是合法的變量名. 變量名可以為字母,數(shù)字以及下劃線.變量始終應(yīng)該以字母開(kāi)頭. “foo_port”是個(gè)合法的變量名.”foo5”也是. “foo-port”, “foo port”, “foo.port” 和 “12”則不是合法的變量名.
內(nèi)置變量
首先需要了解的是默認(rèn)變量,Ansible 定義了一些在 playbook 中永遠(yuǎn)可以訪問(wèn)的變量倦炒。
hostvars ---> 是一個(gè)字典显沈, key 是 ansible 主機(jī)的名字,value 是這臺(tái)主機(jī)的所有變量名和相應(yīng)的變量值
inventory_hostname ---> 當(dāng)前主機(jī)被 Ansible 識(shí)別的名字
group_names ---> 列表逢唤, 列表中存放了當(dāng)前主機(jī)所屬的所有主機(jī)組名
groups ---> 字典拉讯, key 是 ansible 的主機(jī)組名,value 是這個(gè)主機(jī)組所包含的所有主機(jī)鳖藕,主機(jī)組包含了 all 和 ungrouped 分組魔慷。{"all":[...],"webservers":[...],"ungrouped":[...]}
play_hosts ---> 列表, 元素是當(dāng)前 play 涉及到的目標(biāo)主機(jī)的 inventory 主機(jī)名
ansible_version ---> 字典著恩, Ansible 的版本信息
Ansible 變量?jī)?yōu)先級(jí)
==不要把事情搞復(fù)雜==
但是還是有必要告訴你變量的優(yōu)先級(jí)院尔,以滿足你的好奇心蜻展。
基本原則有高到低是:
- extra vars (在命令行中使用 -e)優(yōu)先級(jí)最高
- 然后是在inventory中定義的連接變量(比如ansible_ssh_user)
- 接著是大多數(shù)的其它變量(命令行轉(zhuǎn)換,play中的變量,included的變量,role中的變量等)
- 然后是在inventory定義的其它變量
- 然后是由系統(tǒng)發(fā)現(xiàn)的facts
- 然后是 "role默認(rèn)變量", 這個(gè)是最默認(rèn)的值,很容易喪失優(yōu)先權(quán)
在哪里定義變量
Ansbile 中定義變量非常靈活
- (局部變量,作用于每個(gè)主機(jī)或主機(jī)組)在 Inventory 文件中,針對(duì) host 和 groups 定義變量
172.16.153.129 key=hosts_value username=ansible
[openstack]
192.168.2.[10:30]
[openstack:vars]
ansbible_python_interpreter=/usr/bin/python3.6
key=openstack
可以編輯一個(gè) playbook 來(lái)驗(yàn)證一下
---
- hosts: all
gather_facts: False
tasks:
- name: display Host Variable from hostfile
debug: msg="The {{ inventory_hostname }} Vaule is [ {{ key }} ], username is [{{ username }} ]"
- (全局變量邀摆,作用于所有的 playbook 目標(biāo)主機(jī))在 playbook 文件中使用 vars 定義變量
---
- hosts: all
gather_facts: False
vars:
key: "openstack_value"
username: "ansible"
tasks:
- name: display Host Variable from hostfile
debug: msg="The {{ inventory_hostname }} Vaule is [ {{ key }} ], username is [{{ username }} ]"
- 用引號(hào)避開(kāi)在 playbook 中定義變量的陷阱
- hosts: app_servers
vars:
app_path: "{{ base_path }}/22"
- (全局變量)在 playbook 中使用 vars_files 引用一個(gè)變量文件
可在一個(gè)文件中存放變量纵顾,之后在 playbook 中使用 vars_files 來(lái)引用它。
這個(gè)文件可以是 YAML 格式或者是 JSON 格式
? ~ head var.{yml,json}
==> var.yml <==
key: "Ansible value"
username: ansible
==> var.json <==
{"key": "josn value","username": "ansible"}
引用
? ~ head variale.yml
---
- hosts: all
gather_facts: False
vars_files:
- var.json
#- var.yml
tasks:
- name: display Host Variable from hostfile
debug: msg="The {{ inventory_hostname }} Vaule is [ {{ key }} ], username is [{{ username }} ]"
- (局部變量)==推薦的方式是通過(guò)專門的文件定義主機(jī)和主機(jī)組的變量==
通過(guò)創(chuàng)建 host_vars 目錄和 group_vars 目錄來(lái)分別對(duì)應(yīng)主機(jī)和主機(jī)組進(jìn)行變量的定義隧熙。
host_vars 目錄下片挂,存放的是以 Asnsible 的每個(gè) inventory 主機(jī)名為文件名的 YAML 格式的文件幻林。
group_vars 目錄下贞盯,存放的是以 Asnsible 的每個(gè)主機(jī)組名為文件名的 YAML 格式的文件。
這兩個(gè)目錄存放的位置:
1\. Asnsible 的 ansible.cfg 配置文件中 inventory 項(xiàng)定義的目錄下
2\. 或者可以建立在 playbook 文件的同級(jí)目錄下
默認(rèn)的情況下沪饺,/etc/ansible/ 目錄下的結(jié)構(gòu)
? ~ tree /etc/ansible
/etc/ansible
├── ansible.cfg
├── group_vars
│ └── http
├── hosts
├── host_vars
│ └── 172.16.153.129 # 在這個(gè)文件中定義針對(duì) 172.16.153.129 這臺(tái)主機(jī)的變量
├── Inventory
├── hosts.py
├── hosts.yml
└── openstack
- (全局變量)在命令行里傳遞變量,優(yōu)先級(jí)最高
? ~ ansible-playbook variale.yml -e "key=KEY username=Ansible"
在命令行里也可以引用文件躏敢,文件格式同樣支持 YAML 和 JSON
? ~ ansible-playbook variale.yml -e "@/root/var.yml"
? ~ ansible-playbook variale.yml -e "@/root/var.json"
- 使用 register 注冊(cè)變量
使用 register 注冊(cè)一個(gè)變量,可以讓這個(gè)變量在 task 之前互相傳遞
? ~ cat register.yml
---
- hosts: all
gather_facts: no
tasks:
- name: register a variable
shell: hostname
register: info
- name: display variable
debug: msg="The variable is {{ info }}"
輸出的部分信息
TASK [display variable] ********************************************************
ok: [172.16.153.129] => {
"msg": "The variable is {'stderr_lines': [], u'changed': True, u'end': u'2017-12-03 11:36:07.667813', u'stdout': u'ansible', u'cmd': u'hostname', u'rc': 0, u'start': u'2017-12-03 11:36:07.598862', u'stderr': u'', u'delta': u'0:00:00.068951', 'stdout_lines': [u'ansible']}"
}
ok: [192.168.2.20] => {
"msg": "The variable is {'stderr_lines': [], u'changed': True, u'end': u'2017-12-03 11:36:07.595477', u'stdout': u'ansible', u'cmd': u'hostname', u'rc': 0, u'start': u'2017-12-03 11:36:07.483411', u'stderr': u'', u'delta': u'0:00:00.112066', 'stdout_lines': [u'ansible']}"
}
可以看出輸出的 info 變量的值是一個(gè)字典整葡,我們想要的信息在 stdout 這個(gè)鍵的值件余,可以使用 python 標(biāo)準(zhǔn)的方式訪問(wèn) info["stdout"],也可以使用點(diǎn)兒的方式 info.stdout
? ~ cat register.yml
***略***
- name: display variable
debug: msg="The variable is {{ info.stdout }}"
#debug: msg="The variable is {{ info['stdout'] }}"
- 使用 vars_prompt
在 playbook 中使用 vars_prompt遭居,可以實(shí)現(xiàn)讓用戶輸入變量的值啼器,并且可以定義某個(gè)變量為私有的,當(dāng)定義一個(gè)變量為私有時(shí)俱萍,用戶輸入此變量的值的時(shí)候端壳,不會(huì)顯示在屏幕上
定義
? ~ cat vars_prompt.yml
---
- hosts: all
gather_facts: no
vars_prompt:
- name: "username" # 變量的 key
prompt: "Please input username" # 提示信息
private: no # 公有屬性
- name: "passwd"
prompt: "Please input password"
default: 'good' # 變量的默認(rèn)值
private: yes # 私有屬性
tasks:
- name: display one value
debug: msg="one value is {{ username }}"
- name: display two value
debug: msg="two value is {{ passwd }}"
測(cè)試使用
? ~ ansible-playbook var_prompt.yml -l 172.16.153.129
Please input username: ansible
Please input password [good]:
PLAY [all] *********************************************************************
TASK [display one value] *******************************************************
ok: [172.16.153.129] => {
"msg": "one value is ansible"
}
TASK [display two value] *******************************************************
ok: [172.16.153.129] => {
"msg": "two value is upsa"
}
PLAY RECAP *********************************************************************
172.16.153.129 : ok=2 changed=0 unreachable=0 failed=0
條件
when 語(yǔ)句
有的 task 的執(zhí)行,是需要某一個(gè)變量的值枪蘑。
比如损谦,假如系統(tǒng)是 RedHat 就使用 yum 模塊安裝軟件包;假如系統(tǒng)是 Ubuntu 就使用 apt 模塊安裝軟件
? ~ cat when.yml
---
- hosts: 172.16.153.129
tasks:
- name: "Install a packge"
yum: name=httpd state=present
when: ansible_os_family == "RedHat"
- name: display os family
debug: var=ansible_os_family
一系列的Jinja2 “過(guò)濾器” 也可以在when語(yǔ)句中使用, 但有些是Ansible中獨(dú)有的. 比如我們想忽略某一錯(cuò)誤,通過(guò)執(zhí)行成功與否來(lái)做決定,我們可以像這樣:
==待進(jìn)一步核實(shí)驗(yàn)證==
# 注意這個(gè)示例中并沒(méi)有使用 name岳颇,而是直接使用模塊
? ~ cat when_filter.yml
---
- hosts: 172.16.153.129
gather_facts: no # 不獲取 facts 信息照捡,默認(rèn)是獲取的
tasks:
- command: /bin/ls /a
register: result
ignore_errors: True # 假如此 task 失敗,繼續(xù)執(zhí)行下面的 task
- shell: /bin/ls /root
when: result|failed # 假如 result 是失敗的话侧,執(zhí)行此 task
- file: dest=/a/b/ state=directory
when: result|success # 假如 result 是成功的栗精,執(zhí)行此 task
- file: dest=/root/yan.txt state=file
when: result|skipped # 假如 result 是被忽略的,執(zhí)行此 task
- debug: msg="Then result is {{ result }}"
- 更完整的示例
---
- hosts: openstack
tasks:
- name: Host 172.16.153.129 run this task
debug: msg="{{ ansible_default_ipv4.address }}"
when: ansible_default_ipv4.address == "192.168.2.10"
- name: memtotal < 128 M and processor_cores == 2 run this task
debug: msg="{{ ansible_fqdn }}"
when: ansible_memtotal_mb < 128 and asible_processor_cores == 2
- name: all host run this task
shell: hostname
register: info
- name: Hostname is ansible Machie run this task
debug: msg="{{ ansible_fqdn }}"
when: info['stdout'] == "ansible"
- name: Hostname is startswith M run this task
debug: msg="{{ ansible_fqdn }}"
when: info.stdout.startswith('M')
執(zhí)行結(jié)果中的 skipping 代表此臺(tái)主機(jī)沒(méi)有執(zhí)行此 task
- 可以使用變量的布爾值來(lái)作為判斷條件
# 定義變量
vars:
epic: true
# 條件判斷
tasks:
- shell: echo "This certainly is epic!"
when: epic
# 或者下面這樣
when: not epic
- 如果一個(gè)變量不存在,你可以使用Jinja2的
defined
命令跳過(guò)或略過(guò)
tasks:
- when: foo is defined
- when: bar is not defined
- 還可以使用 運(yùn)算符號(hào)
tasks:
- command: echo {{ item }}
with_items: [ 0, 2, 4, 6, 8, 10 ]
when: item > 5
- 條件導(dǎo)入
---
- hosts: all
remote_user: root
vars_files:
- "vars/common.yml"
- [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
tasks:
- name: make sure apache is running
service: name={{ apache }} state=running
這個(gè)具體事怎么工作的呢瞻鹏?
如果操作系統(tǒng)是’CentOS’, Ansible導(dǎo)入的第一個(gè)文件將是’vars/CentOS.yml’,緊接著 是’/var/os_defaults.yml’,如果這個(gè)文件不存在.而且在列表中沒(méi)有找到,就會(huì)報(bào)錯(cuò).
如果操作系統(tǒng)是 Debian,最先查看的將是’vars/Debian.yml’而不是’vars/CentOS.yml’, 如果沒(méi)找到,則尋找默認(rèn)文件’vars/os_defaults.yml’ 很簡(jiǎn)單.
如果使用這個(gè)條件性導(dǎo)入特性,你需要在運(yùn)行playbook之前安裝facter 或者 ohai.當(dāng)然如果你喜歡, 你也可以把這個(gè)事情推給Ansible來(lái)做:
# for facter
ansible -m yum -a "pkg=facter state=present"
ansible -m yum -a "pkg=ruby-json state=present"
# for ohai
ansible -m yum -a "pkg=ohai state=present"
- 基于變量選擇文件和模版
下面的例子展示怎樣根據(jù)不同的系統(tǒng),例如CentOS,Debian制作一個(gè)配置文件的模版:
- name: template a file
template: src={{ item }} dest=/etc/myapp/foo.conf
with_first_found:
- files:
- {{ ansible_distribution }}.conf
- default.conf
paths:
- search_location_one/somedir/
- /opt/other_location/somedir/
循環(huán)
標(biāo)準(zhǔn) loops
- 一次安裝多個(gè)軟件包
---
- hosts: all
gather_facts: no
tasks:
- name: Install package
yum: pkg={item} state=latest
with_items:
- httpd
- vim
- 一次創(chuàng)建多個(gè)用戶
---
- hosts: all
gather_facts: no
remote_users: root
tasks:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
with_items 是固定的變量名悲立,是一個(gè)列表的名字,Ansible 默認(rèn)會(huì)對(duì)這個(gè)列表循環(huán)乙漓,循環(huán)的每個(gè)元素變量名是 item级历,可以對(duì) item 的使用來(lái)引用列表里的每個(gè)元素。
- 如果你在變量文件中或者 ‘vars’ 區(qū)域定義了一組YAML列表,你也可以這樣做:
with_items: "{{somelist}}"
- 也支持哈希的列表(字典)
- name: add several users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'testuser1', groups: 'wheel' }
- { name: 'testuser2', groups: 'root' }
==如果同時(shí)使用 when 和 with_items (或其它循環(huán)聲明)叭披,when 會(huì)作用于每個(gè)循環(huán)的元素==
嵌套循環(huán)
主要實(shí)現(xiàn)的是 一個(gè)對(duì)多或者多對(duì)多的合并
在這里我想用一個(gè)更簡(jiǎn)單方式演示寥殖, debug 模塊
---
- hosts: test
gather_facts: no
tasks:
- name: debug log
debug: msg="name ---> {{ item[0] }} vaule ---> {{ item[1] }} vv --> {{item[2]}}"
with_nested:
- ['A','B']
- ['a1','a2','a3']
- ['b1','b2','b3']
上面的嵌套循環(huán)等同于下面的普通 for 嵌套循環(huán)
for item0 in ['A','B']:
for item1 in ['a1','a2','a3']:
for item2 in ['b1','b2','b3']:
print("name ---> {} vaule ---> {} vv --> {}".format(item0,item1,item2))
同樣可以使用預(yù)定義好的變量玩讳。看下面這個(gè)使用的示例:
- name: here, 'users' contains the above list of employees
mysql_user: name={{ item[0] }} priv={{ item[1] }}.*:ALL append_privs=yes password=foo
with_nested:
- "{{users}}"
- [ 'clientdb', 'employeedb', 'providerdb' ]
使用 with_dict
進(jìn)行哈希 loops
with_dict 可以對(duì) python 字典格式(需要 yml.load 之后)的變量進(jìn)行循環(huán)
哈希循環(huán)也叫散列循環(huán)嚼贡,標(biāo)準(zhǔn)的循環(huán)要求熏纯,最外層必須是 python 的 list 數(shù)據(jù)類型
哈希循環(huán)支持更豐富的數(shù)據(jù)結(jié)構(gòu)
比如有這樣的變量
---
users:
alice:
name: Alice Appleworth
shell: bash
telephone: 123-456-7890
bob:
name: Bob Bananarama
shell: zsh
telephone: 987-654-3210
可以這樣循環(huán)使用它
tasks:
- name: Print phone records
debug: msg="User {{ item.key }} is {{ item.value.name }} ({{ item.value.telephone }}), shell is --> {{ item.value.shell }}"
with_dict: "{{users}}"
使用 with_fileglob
對(duì)文件列表使用循環(huán)
with_fileglob 可以以非遞歸的方式對(duì)某個(gè)目錄下的特定文件進(jìn)行循環(huán),所有它是支持模糊匹配的.如下面所示:
---
- hosts: all
tasks:
# first ensure our target directory exists
- file: dest=/etc/fooapp state=directory
# copy each file over that matches the given pattern
- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600
with_fileglob:
# 這里匹配的是目錄下的所有文件粤策,也可以 *.yml 來(lái)匹配 yml 結(jié)尾的文件
- /playbooks/files/fooapp/*
扁平化列表
---
- hosts: ansible
gather_facts: no
vars:
packages_base:
- [ 'foo-package', 'bar-package' ]
packages_apps:
- [ ['one-package', 'two-package' ]]
- [ ['red-package'], ['blue-package']]
tasks:
- name: flattened loop demo
debug: msg="{{ item }}"
with_flattened:
- "{{packages_base}}"
- "{{packages_apps}}"
使用 with_random_choice
進(jìn)行隨機(jī)循環(huán)
---
- hosts: test
gather_facts: no
tasks:
- debug: msg="name ---> {{ item }}"
with_random_choice:
- "ansible1"
- "ansible2"
- "ansible3"
- "ansible4"
使用 until
條件判斷 loops
通過(guò)判斷一個(gè)條件樟澜,第某個(gè) task 執(zhí)行多少次
---
- hosts: all
gather_facts: no
tasks:
- name: debug loops
shell: cat /root/Ansbile
register: host
untill: host.stdout.startswith("Master")
retries: 5 # 總共執(zhí)行 5 次
delay: 5 # 每次執(zhí)行的間隔是 5 秒
使用 with_fist_found
進(jìn)行文件優(yōu)先匹配 loops
不經(jīng)常用,這個(gè)用法以及更多的 loops 請(qǐng)參考官方文檔: https://ansible-tran.readthedocs.io/en/latest/docs/playbooks_loops.html
Playbook lookups
playbook 的 lookups 是讓 Ansible 可以從外部拉取數(shù)據(jù)信息賦值給 Anssible 變量的一種方式叮盘。
這個(gè)實(shí)現(xiàn)的辦法就是 Ansible 的 lookups 插件秩贰。
目前 Ansible 已經(jīng)自帶的很多的 lookups 插件,接下來(lái)只介紹一些常用的柔吼。
* file --> 可以從一個(gè)文件中獲取數(shù)據(jù)
* password --> 可以把傳入的內(nèi)容進(jìn)行加密處理
* pipe --> 就是利用了 Python 的 subprocess.Popen 執(zhí)行命令毒费,之后把執(zhí)行命令的結(jié)果賦值給變量
* redis_kv --> 從 Redis 數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)
* template --> 和 file 類似,都是讀取文件愈魏,但是 template 支持讀取 jinja 模板文件觅玻,并且 loops.j2 文件是每臺(tái)主機(jī)自己的信息,不是控制主機(jī)的信息培漏。
示例:
- file
---
- hosts: ansible
gather_facts: no
vars:
contents: "{{ lookup('file', '/etc/sysconfig/ne---
- hosts: ansible
gather_facts: no
vars:
contents: "{{ lookup('file', '/etc/sysconfig/entwork') }}"
tasks:
- name: debug loops
debug: msg="The contents is {% for i in contents.split('\n') %} {{ i }} {% endfor %}" twork') }}"
tasks:
- name: debug loops
debug: msg="The contents is {% for i in contents.split('\n') %} {{ i }} {% endfor %}"
- password
---
- hosts: ansible
gather_facts: no
vars:
contents: "{{ lookup('password', 'aa') }}"
tasks:
- name: debug loops
debug: msg="The contents is {{ contents }}"
- pipe
---
- hosts: ansible
gather_facts: no
vars:
contents: "{{ lookup('pipe', 'df -P ') }}"
tasks:
- name: debug loops
debug: msg="The contents is {% for i in contents.split() %} {{ i }} {% endfor %}"
- redis_kv
vars:
contents: "{{ lookup('redis_kv', 'redis: //localhost:6379, somekey') }}"
tasks:
- name: debug loops
debug: msg="The contents is {% for i in contents.split('\n') %} {{ i }} {% endfor %}"
- template
模板文件內(nèi)容
? ~ cat lookups.j2
worker_processes {{ ansible_processor_cores }}
IPaddress {{ ansible_ent0.ip4.address }}
使用
---
- hosts: ansible
gather_facts: yes
vars:
contents: "{{ lookup('template', './lookups.j2') }}"
tasks:
- name: debug loops
debug: msg="The contents is {% for i in contents.split() %} {{ i }} {% endfor %}"
Jinja2 filter
Ansible 默認(rèn)支持 Jinja2 語(yǔ)言的內(nèi)置 filter溪厘,下面介紹一些常用的。
---
- hosts: all
gather_facts: no
vars:
list: [1,2,3,4,5]
one: "1"
str: "string"
tasks:
- name: run commands
shell: df -h
register: info
- name: debug pprint filter
debug: msg="{{ info.stdout | pprint }}"
- name: debug conditionals filter
debug: msg="The run commands status is changed"
when: info | changed
- name: debug int capitalize filter
debug: msg="The int value {{ one | int }} The lower value is {{ str | capitalize }}"
- name: debug default filter
debug: msg="The Variable value is {{ ansible | default('ansible is not define') }}"
# default 是假如 ansible 變量沒(méi)有定義牌柄,則采用 default 內(nèi)的的值作為 ansible 變量的值
- name: debug list max and min filter
debug: msg="The list max value is {{ list | max }} The list min value is {{ list | min }}"
- name: debug join filter
debug: msg="The join filter value is {{ list | join("+") }}"
- name: debug replace and regex_replace filter
debug: msg="The replace value is {{ str | replace('t','T') }} The regex_replace value is {{ str | regex_replace('.*str(.*)$','\\1') }}"