Ansible 自動(dòng)化運(yùn)維

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)

  1. 安裝部署簡(jiǎn)單
  2. 學(xué)習(xí)曲線很平坦
  3. 支持多臺(tái)主機(jī)并行管理
  4. 無(wú)代理靴姿,無(wú)需在客戶機(jī)上安裝額外軟件力麸,使用的是 SSH 協(xié)議通信
  5. 非 root 賬戶也可運(yùn)行
  6. 不僅僅支持 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)

管理方式

image

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ù)定配置的順序查找以下配置文件

  1. ANSIBLE_CONFIG 先檢查環(huán)境變量召川,以及這個(gè)環(huán)境變量指向的配置文件
  2. ./ansible.cfg 接著會(huì)檢查執(zhí)行命令的當(dāng)前目錄下的 ansible.cfg 配置文件
  3. ~/.ansible.cfg 之后會(huì)檢查當(dāng)前用戶家目錄下的 .ansible.cfg 這個(gè)隱藏文件
  4. /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),兩種方式任選一種:

  1. 在 ansible.cfg 配置文件中配置
# 在 defaults 域下配置
[defaults]
host_key_checking = False

  1. 直接在控制主機(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 可用性

  1. 先在 /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 文件

  1. 定義一個(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 文件的格式一樣
  1. 再在 /etc/ansible/ansible.cfg 文件中的 [defaults] 配置塊中 配置 inventory 的值指向 這個(gè) 文件夾
image
  1. 驗(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 配置

  1. 在 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 格式悄泥。
  1. 編輯這個(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

  1. 配置 /etc/ansible/ansible.cfg
[ansible@ansible ~]$ grep ^inventory /etc/ansible/ansible.cfg
inventory      = /etc/ansible/Inventory/

  1. 靜態(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 是成功的逻淌。

  1. 動(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è)些子組是有一些限制的:
  1. 假如聲明的子組是靜態(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)功能的基本組成部分

  1. 針對(duì)的目標(biāo)是誰(shuí)?
  2. 讓目標(biāo)做什么票堵,其中包含了具體怎么做扼睬?
  3. 假如在做的過(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龄句,并且想要重用他回论,可以這么做

  1. 先創(chuàng)建這個(gè) handlers 文件,名字叫 handers.yml
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
  service: name=apache state=restarted

  1. 引用它
    然后在你的主 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') }}"
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畸悬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子友鼻,更是在濱河造成了極大的恐慌傻昙,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彩扔,死亡現(xiàn)場(chǎng)離奇詭異妆档,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)虫碉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門贾惦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人敦捧,你說(shuō)我怎么就攤上這事须板。” “怎么了兢卵?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵习瑰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我秽荤,道長(zhǎng)甜奄,這世上最難降的妖魔是什么柠横? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮课兄,結(jié)果婚禮上牍氛,老公的妹妹穿的比我還像新娘。我一直安慰自己烟阐,他們只是感情好搬俊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蜒茄,像睡著了一般唉擂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上扩淀,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天楔敌,我揣著相機(jī)與錄音,去河邊找鬼驻谆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛庆聘,可吹牛的內(nèi)容都是我干的胜臊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼伙判,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼象对!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起宴抚,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤勒魔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后菇曲,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體冠绢,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年常潮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弟胀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡喊式,死狀恐怖孵户,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情岔留,我是刑警寧澤夏哭,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站献联,受9級(jí)特大地震影響竖配,放射性物質(zhì)發(fā)生泄漏厕吉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一械念、第九天 我趴在偏房一處隱蔽的房頂上張望头朱。 院中可真熱鬧,春花似錦龄减、人聲如沸项钮。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)烁巫。三九已至,卻和暖如春宠能,著一層夾襖步出監(jiān)牢的瞬間亚隙,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工违崇, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阿弃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓羞延,卻偏偏與公主長(zhǎng)得像渣淳,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伴箩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容