07 Ansible 最佳實戰(zhàn)

本文鏈接: http://www.reibang.com/p/6550e3d72914
作者:閆立行

一、調(diào)試

在執(zhí)行 ad-hoc 或者 playbook 的時候废睦,在后面加上 -vvv 參數(shù)伺绽,就可以看到 Ansible 的詳細執(zhí)行過程,便于排錯嗜湃。

[root@qfedu.com ~]# ansible dbservers -i hosts -m ping -vvv

[root@qfedu.com ~]# ansible-playbook -i hosts checkhost.yml -vvv

二奈应、優(yōu)化 Ansible 速度

1. 設置 SSH 為長連接

openssh5.6 版本后支持 Multiplexing

1.1 檢查控制機器的 ssh 版本

[root@qfedu.com ~]# ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

1.2 升級 ssh 客戶端程序

假如不是 5.6 版本以上的,可以用下面的辦法升級 ssh 客戶端程序

  • 配置 Centos6 系統(tǒng)的 YUM 源(使用 Centos6)
?  ansible cat /etc/yum.repos.d/openssh.repo
[CentALT]
name=CentALT Packages for Enterprise Linux 6 - $basearch
baseurl=http://mirror.neu.edu.cn/CentALT/6/$basearch/
enable=1
gpgcheck=0
  • 執(zhí)行升級命令
[root@qfedu.com ~]# yum   update  openssh-clients

升級完成后购披,不必重啟任何服務杖挣,因為我們的控制機是使用 ssh 的客戶端

1.3 設置 ansible 配置文件

[root@qfedu.com ~]#  grep sh_args /etc/ansible/ansible.cfg
ssh_args = -C -o ControlMaster=auto -o ControlPersist=10d
# ControlPersist=10d 表示保持長連接 10 天。
# 60s 是 60 秒

1.4 建立長連接并測試

設置好后刚陡,重新連接一次被控主機惩妇,即可讓控制主機和被控主機之間建立長連接

[root@qfedu.com ~]# ansible webservers -i hosts -m ping
172.18.0.4 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

驗證長連接

[root@qfedu.com ~]# ss -an |grep ESTAB
tcp    ESTAB      0      0      172.18.0.2:51864              172.18.0.4:2222

輸出中 有 ESTAB 狀態(tài)的就代表是長連接

同時會在主控機當前用戶的家目錄下的 .ansibl/cp/ 目錄下生成對應的 socket 文件

[root@qfedu.com ~]# ls -l .ansible/cp/13fe34a1c4
srw------- 1 root root 0 Apr 17 03:36 .ansible/cp/13fe34a1c4

2. 開啟 pipelining

我們知道默認情況下 Ansible 執(zhí)行過程中會把生成好的本地 python 腳本文件 PUT 到 遠端機器。如果我們開啟了 ssh 的 pipelining 特性筐乳,這個過程就會在 SSH 的會話中進行歌殃。

在不通過實際文件傳輸?shù)那闆r下執(zhí)行ansible模塊來使用管道特性, 可以減少執(zhí)行遠程服務器上的模塊所需的網(wǎng)絡操作數(shù)量。比如 PUT sftp 等操作都需要建立網(wǎng)絡連接蝙云。

下面是關閉 Pipeline 的情況下的三步操作挺份。

<172.18.0.3> PUT /root/.ansible/tmp/ansible-local-10883q1xq1u/tmpNbePyo TO /root/.ansible/tmp/ansible-tmp-1587214813.33-212837305246708/AnsiballZ_ping.py
<172.18.0.3> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=600s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/553ad38749 '[172.18.0.3]'
<172.18.0.3> (0, 'sftp> put /root/.ansible/tmp/ansible-local-10883q1xq1u/tmpNbePyo /root/.ansible/tmp/ansible-tmp-1587214813.33-212837305246708/AnsiballZ_ping.py\n', '')

如果開啟這個設置,將顯著提高性能.。

然而當使用”sudo:”操作的時候, 你必須在所有管理的主機的 /etc/sudoers 中禁用 requiretty.

下面的步驟是實現(xiàn)這個特性的步驟

  1. 在 ansible.cfg 配置文件中設置 pipelining 為 True
[root@qfedu.com ~]# grep pipelining /etc/ansible/ansible.cfg
# Enabling pipelining reduces the number of SSH operations required to
pipelining = True
  1. 配置被控主機的 /etc/sudoers 文件贮懈,添加下面的內(nèi)容(默認沒有)

關于 Sudo 參考:Sudo(簡體中文)

# Disable "ssh hostname sudo <cmd>", because it will show the password in clear text. 
# You have to run "ssh -t hostname sudo <cmd>".
#
# Defaults    requiretty

三匀泊、設置 facts 緩存

默認情況下,Ansible 每次執(zhí)行 playbook 時的第一個 Task 就是 獲取每臺主機的 facts 信息朵你。假如不需要可以設置 gather_facts = no 進行關閉各聘,以提高執(zhí)行 playbook 的效率。

假如想獲取 facts 信息抡医,同時又想加速這個 task 的效率躲因,就需要設置 facts 緩存。

緩存 facts 信息可以存檔 JSON 文件中忌傻,也可以方式 redis 和 memcached 中大脉。

1. 首先是可以在 ansible.cfg 文件中設置

grep gathering /etc/ansible/ansible.cfg
gathering = smart

ansible的配置文件中可以修改'gathering'的值為 smartimplicit 或者 explicit水孩。

  • smart ??????--> 表示默認收集facts镰矿,但facts已有的情況下不會收集,即使用緩存facts俘种;
  • implicit ??--> 表示默認收集facts秤标,要禁止收集,必須使用gather_facts: False宙刘;
  • explicit ??--> 則表示默認不收集苍姜,要顯式收集,必須使用gather_facts: Ture
  1. 在playbook 中設置
---
- hosts: all
  gather_facts: yes    # 顯式定義收集
  gather_facts: no     # 顯式定義不收集
  gather_facts: smart  # 顯式定義收集

配置緩存的目標

  1. 緩存到文件(JSON格式的數(shù)據(jù))
    在 ansible.cfg 文件中配置緩存到 file
gathering =  smart
fact_caching = jsonfile       # 緩存到 json 文件
fact_caching_connection = /dev/shm/ansible_fact_cache
fact_caching_timeout = 86400  # 緩存數(shù)據(jù)時間是一天 

fact_caching_connection 是一個放置在可讀目錄(如果目錄不存在,ansible會試圖創(chuàng)建它)中的本地文件路徑,文件名是在 inventory 保存的 IP 或者 hostname .

驗證

[root@qfedu.com ~]# ls /dev/shm/ansible_fact_cache/
172.18.0.3  172.18.0.5
[root@qfedu.com ~]# head -n 3 /dev/shm/ansible_fact_cache/*
==> /dev/shm/ansible_fact_cache/172.18.0.3 <==
{
    "_ansible_facts_gathered": true,
    "ansible_all_ipv4_addresses": [

==> /dev/shm/ansible_fact_cache/172.18.0.5 <==
{
    "_ansible_facts_gathered": true,
    "ansible_all_ipv4_addresses": [
[root@qfedu.com ~]#
  1. 緩存到 redis
  • 在任一機器或者ansible 控制主機上部署 Redis 服務
[root@qfedu.com ~]# yum install redis
  • 假如 Redis 服務不在 ansible 控制主機上悬包,還應該設置 redis 監(jiān)聽地址
~ # grep '^bind' /etc/redis.conf
bind 0.0.0.0
  • 在控制主機 python 的 redis 庫
[root@qfedu.com ~]# pip install redis
  • 在 ansible.cfg 文件中配置緩存到 redis
gathering = smart
fact_caching = redis       # 緩存到 redis
fact_caching_connection = 192.168.1.37:6379:0

fact_caching_timeout = 86400  # 緩存數(shù)據(jù)時間是一天 

  • 檢查
127.0.0.1:6379> zcard ansible_cache_keys
(integer) 2
127.0.0.1:6379> ZRANGE ansible_cache_keys 0 2
1) "172.18.0.3"
2) "172.18.0.5"

四衙猪、設置 Ansible 的執(zhí)行策略

1. 策略介紹

默認的執(zhí)行策略是按批并行處理的,假如總共 15 臺主機布近,每次并發(fā) 5 個線程執(zhí)行的策略如下:

h1/h2/h3/h4h5 -------> h6/h7/h8/h9/h10  -----> h11/h12/h13/h14/h15
               全部執(zhí)行完后垫释,進入下一批                    依次類推

從 asible2.0 開始,可以通過在 playbook 中設置 strategy 的值改變這策略吊输,也可以在 ansible.cfg 配置文件中設置一個默認的策略:

[defaults]
strategy = free

改變后的策略饶号,可以前赴后繼的對主機進行執(zhí)行 task,執(zhí)行模式如下:

假如 h4 主機先執(zhí)行完季蚂,會及時的讓 下一個排隊的主機進入到 執(zhí)行的隊列中茫船。

h1/h2/h3/h4/h5  ------> h1/h2/h3/h6/h5 -------> h1/h2/h3/h6/h7  -----> ...

2 環(huán)境準備

準備多臺機器

可以使用如下方式給一臺主機添加多個 IP 達到擁有多個主機的效果。

[root@web-server ~]# ip addr add 172.18.0.5/16 dev eth0
[root@web-server ~]# ip addr add 172.18.0.6/16 dev eth0
[root@web-server ~]# ip addr add 172.18.0.7/16 dev eth0
[root@web-server ~]# ip addr add 172.18.0.8/16 dev eth0
[root@web-server ~]# ip addr add 172.18.0.9/16 dev eth0
[root@web-server ~]# ip addr add 172.18.0.10/16 dev eth0

添加到資產(chǎn)中

[dbservers]
172.18.0.3

[webservers]
172.18.0.4  ansible_ssh_port=2222
172.18.0.5 ansible_ssh_port=2222
172.18.0.6  ansible_ssh_port=2222
172.18.0.7  ansible_ssh_port=2222
172.18.0.8  ansible_ssh_port=2222
172.18.0.9  ansible_ssh_port=2222
172.18.0.10  ansible_ssh_port=2222

[allservers:children]
dbservers
webservers

[allservers:vars]
user=tomcat

strategy 默認的值的是 linear 扭屁,就是按批并行處理算谈,下面是配置為 free 的方式實例:

- hosts: webservers
  strategy: free
  tasks:
    - name: ping hosts
      ping:

執(zhí)行

默認 Ansible 的執(zhí)行隊列有一個,就是并行執(zhí)行料滥,假如控制節(jié)點的機器有多個 CPU然眼,并且性能較好,可以打開多個執(zhí)行隊列葵腹,就是并發(fā)。

  • 方式一:
    在 ansible.cfg 中設置

    [defaults]
    forks = 30
    
  • 方式二:
    在命令行里使用

    ansible-playbook -f 3  my_playbook.yml
    
  • 實例演示

[root@qfedu.com ~]# ansible-playbook -i hosts checkhost-2.yml -f 3

PLAY [webservers] **************************************************************

TASK [Gathering Facts] *********************************************************
ok: [172.18.0.5]
ok: [172.18.0.4]
ok: [172.18.0.6]
ok: [172.18.0.7]
ok: [172.18.0.8]
ok: [172.18.0.9]

TASK [ping hosts] **************************************************************
ok: [172.18.0.4]
ok: [172.18.0.5]
ok: [172.18.0.6]
ok: [172.18.0.7]
ok: [172.18.0.8]
ok: [172.18.0.9]

TASK [Gathering Facts] *********************************************************
ok: [172.18.0.10]

TASK [ping hosts] **************************************************************
ok: [172.18.0.10]

PLAY RECAP *********************************************************************
172.18.0.10                : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.4                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.5                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.6                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.7                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.8                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
172.18.0.9                 : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

五坚嗜、 異步和輪詢

默認情況下作郭,劇本塊中的任務是指連接保持打開狀態(tài),直到在每個節(jié)點上完成任務為止爷怀。這可能并不總是合乎需要的,或者您運行的操作所花費的時間超過了SSH超時带欢。

可以在后臺運行長時間運行的操作运授,以后再查看它們的狀態(tài)。

1 執(zhí)行臨時命令是使用異步

比如如下示例是 執(zhí)行一個任務持續(xù)運行 5 秒鐘乔煞,超時 10 秒(-B 10)吁朦,并且不等待任務返回結果(-P 0)

[root@qfedu.com ~]# ansible dbservers -B 10 -P 0 -i hosts -a "sleep 5"
172.18.0.3 | CHANGED => {
    "ansible_job_id": "191465439990.2210",
    "changed": true,
    "finished": 0,
    "results_file": "/root/.ansible_async/191465439990.2210",
    "started": 1
}
  • 查看保存結果集的文件

執(zhí)行結果會存放的被控節(jié)點主機的 /root/.ansible_async/191465439990.2210 文件中

[root@db-server /]# cat /root/.ansible_async/191465439990.2210
{"changed": true, "end": "2020-04-19 02:06:23.716226", "stdout": "", "cmd": ["sleep", "5"], "start": "2020-04-19 02:06:18.310407", "delta": "0:00:05.405819", "stderr": "", "rc": 0, "invocation": {"module_args": {"warn": true, "executable": null, "_uses_shell": false, "strip_empty_ends": true, "_raw_params": "sleep 5", "removes": null, "argv": null, "creates": null, "chdir": null, "stdin_add_newline": true, "stdin": null}}}[root@db-server /]#
  • 獲取結果

應該使用 async_status 模塊來獲取結果,需要傳遞 job id渡贾,就是返回信息中字段 ansible_job_id 的值逗宜,這里是 191465439990.2210

[root@qfedu.com ~]# ansible dbservers -i hosts -m async_status -a "jid=191465439990.2210"
172.18.0.3 | CHANGED => {
    "ansible_job_id": "191465439990.2210",
    "changed": true,
    "cmd": [
        "sleep",
        "5"
    ],
    "delta": "0:00:05.405819",
    "end": "2020-04-19 02:06:23.716226",
    "finished": 1,
    "rc": 0,
    "start": "2020-04-19 02:06:18.310407",
    "stderr": "",
    "stderr_lines": [],
    "stdout": "",
    "stdout_lines": []
}

假如 -P 的值大于 0 就會起到同步執(zhí)行的效果剥啤,整個Ansible 命令還是阻塞狀態(tài)的锦溪。并且此時 -B 等待結果集的超時時間必須大于,命令實際執(zhí)行消耗的時間府怯。否則報錯刻诊。
如下所示:

[root@qfedu.com ~]# ansible dbservers -B 3 -P 1 -i hosts -a "sleep 5"
172.18.0.3 | FAILED | rc=-1 >>
async task did not complete within the requested time - 3s
[WARNING]: Failure using method (v2_runner_on_failed) in callback plugin
(<ansible.plugins.callback.mail.CallbackModule object at 0x7f9796792c90>):
'CallbackModule' object has no attribute 'itembody'

2 Playbook 中使用異步

這里講介紹如何異步執(zhí)行 playbook。

下面演示一個異步任務牺丙,這個異步任務執(zhí)行時長 5 秒左右则涯,等待超時時間是 10 秒鐘, 之后需把返回結果注冊到變量 job 中冲簿,這樣才能獲取到每個備課主機的 job id粟判。最后使用 debug 模塊打印出來。

async.yml

---
- hosts: dbservers
  remote_user: root

  tasks:
    - name: simulate long running op (5 sec), wait for up to 6 sec, poll every 0 sec
      shell: /bin/sleep 5;hostname -i
      async: 10
      poll: 0
      register: job
    - name: show  job id
      debug:
        msg: "Job id is {{ job }}"

執(zhí)行playbook

[root@qfedu.com ~]# ansible-playbook -i hosts async.yaml

PLAY [dbservers] ***************************************************************

TASK [simulate long running op (5 sec), wait for up to 6 sec, poll every 0 sec] ***
changed: [172.18.0.3]

TASK [show  job id] ************************************************************
ok: [172.18.0.3] => {
    "msg": "Job id is {u'ansible_job_id': u'801565582767.3551', u'started': 1, 'changed': True, 'failed': False, u'finished': 0, u'results_file': u'/root/.ansible_async/801565582767.3551'}"
}

PLAY RECAP *********************************************************************
172.18.0.3                 : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  • 獲取結果

可以那其中的一個峦剔,查看任務結果

getJobResult.yml

- hosts: dbservers
  tasks:
  - name: Get job result
    async_status:
      jid: "801565582767.3551"
    register: job_result

  - name: debug job result
    debug:
      var: job_result

執(zhí)行 playbook

[root@qfedu.com ~]# ansible-playbook -i hosts getJobResult.yml

PLAY [dbservers] ***************************************************************

TASK [Get job result] **********************************************************
changed: [172.18.0.3]

TASK [debug job result] ********************************************************
ok: [172.18.0.3] => {
    "job_result": {
        "ansible_job_id": "801565582767.3551",
        "changed": true,
        "cmd": "/bin/sleep 5;hostname -i",
        "delta": "0:00:05.421222",
        "end": "2020-04-19 03:21:47.090911",
        "failed": false,
        "finished": 1,
        "rc": 0,
        "start": "2020-04-19 03:21:41.669689",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "172.18.0.3",
        "stdout_lines": [
            "172.18.0.3"
        ]
    }
}

PLAY RECAP *********************************************************************
172.18.0.3                 : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

3 注意事項

不應通過將輪詢值指定為0來進行需要排他鎖的操作(例如yum事務)來嘗試異步運行任務档礁。

安裝多個包 YUM 模塊本身就支持

yum_tasks.yaml

- name: install tree vim
  yum:
    name: [tree, vim]
    state: present

命令行中使用英文逗號隔開:
-m yum -a "name=tree,vim state=present"

六、使用多個 Inventory 文件

通過從命令行提供多個清單參數(shù)或通過配置多個清單參數(shù)吝沫,可以同時定位多個清單源(目錄呻澜,動態(tài)清單腳本或清單插件支持的文件)

這對于具有多環(huán)境的狀態(tài)下非常有幫助,比如生產(chǎn)環(huán)境和開發(fā)環(huán)境惨险。

1 從命令行定位兩個源羹幸,如下所示:

ansible-playbook get_logs.yml -i development -i production

2 使用目錄匯總清單源

可以通過組合目錄下的多個清單來源和來源類型來創(chuàng)建清單。
這對于組合靜態(tài)和動態(tài)主機并將它們作為一個清單進行管理很有用辫愉。

目錄中僅支持如下擴展名

.yaml   .yml   .json

以下清單結合了清單插件源栅受,動態(tài)清單腳本和具有靜態(tài)主機的文件

inventory/
  aliyun.yml          # 清單插件,獲取阿里云的主機
  dynamic-inventory.py   # 使用動態(tài)腳本添加額外的主機
  static-inventory       # 添加靜態(tài)主機和組
  group_vars/
    all.yml              # 給所有的主機指定變量

以上的組合可以去掉自己環(huán)境中不需要的

  • 命令行里使用這個清單目錄
ansible-playbook example.yml -i inventory

  • 可以在配置文件中配置

假設這個清單目錄的絕對路徑是: /etc/ansible/inventory

應該這樣配置:

[defaults]
inventory      = /etc/ansible/inventory
  • 要注意變量覆蓋

如果存在與其他庫存來源之間的變量沖突或組依賴關系,則控制庫存來源的合并順序可能很有用屏镊。

根據(jù)文件名按字母順序合并清單依疼,因此可以通過在文件前添加前綴來控制結果:

inventory/
  01-aliyun.yml          # 清單插件,獲取阿里云的主機
  02-dynamic-inventory.py   # 使用動態(tài)腳本添加額外的主機
  03-static-inventory       # 添加靜態(tài)主機和組
  group_vars/
    all.yml              # 給所有的主機指定變量

重復定義變量導致變量被覆蓋闸衫,是應該避免的涛贯,也可以避免的。

  • 測試:

目錄結構

[root@qfedu.com ~]# tree inventory
inventory
|-- 01-static.yml
`-- 02-static.yml

0 directories, 2 files

文件內(nèi)容l*

# inventory/01-static.yml
[webservers]
172.18.0.[4:10]

[allservers:children]
webservers

[allservers:vars]
name = xiguatian
# inventory/02-static.yml
[dbservers]
172.18.0.3

[allservers:children]
dbservers

[allservers:vars]
name = shark

驗證變量的值

[root@qfedu.com ~]# ansible all -i inventory -m debug -a "var=name"
172.18.0.4 | SUCCESS => {
    "name": "shark"
}
172.18.0.5 | SUCCESS => {
    "name": "shark"
}
172.18.0.6 | SUCCESS => {
    "name": "shark"
}
172.18.0.7 | SUCCESS => {
    "name": "shark"
}
172.18.0.8 | SUCCESS => {
    "name": "shark"
}
172.18.0.9 | SUCCESS => {
    "name": "shark"
}
172.18.0.10 | SUCCESS => {
    "name": "shark"
}
172.18.0.3 | SUCCESS => {
    "name": "shark"
}

七蔚出、使用 Inventory scripts

清單腳本不限制語言

腳本限制條件:

  • 腳本必須接受--list--host <hostname> 參數(shù)
  • 當使用單個 --list 參數(shù)調(diào)用腳本時,腳本必須輸出到標準輸出虫腋,就是輸出到終端骄酗,其中包含要管理的所有組的JSON編碼的哈希或字典悦冀。

每個組的值應該是包含每個主機列表趋翻,任何子組和潛在組變量的哈希或字典盒蟆,或者僅是主機列表:

{
    "group001": {
        "hosts": ["host001", "host002"],
        "vars": {
            "var1": true
        },
        "children": ["group002"]
    },
    "group002": {
        "hosts": ["host003","host004"],
        "vars": {
            "var2": 500
        },
        "children":[]
    }

}

如果組中的任何元素為空踏烙,則可以從輸出中將其省略。

  • 當使用 host <hostname> 參數(shù)(其中<hostname>是上面的主機)進行調(diào)用時历等,腳本必須打印一個空的JSON哈希/字典或含有這個主機變量的哈希/字典讨惩,以使其可用于模板和劇本。例如:
{
    "VAR001": "VALUE",
    "VAR002": "VALUE",
}

打印變量是可選的寒屯。如果腳本不執(zhí)行此操作荐捻,則應打印一個空的哈希或字典寡夹。

  • 一個簡單的示例
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import json
import argparse

def lists():
    """
    indent 定義輸出時的格式縮進的空格數(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)文件中的組处面,在這里定義了主機信息
    

    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()
  • 改變文件權限為可執(zhí)行
[ansible@ansible ~]$ sudo chmod 655 /etc/ansible/hosts.py

八、項目錄結構

使用官方建議的目錄結構來組織很多 role 和 playbook 文件是個很棒的建議菩掏。

假如你用 role 封裝了 playbook魂角,并且任務依賴文件或者依賴其他的任務時,建議使用目錄結構管理智绸。

假如是一個簡單的獨立任務野揪, 只使用 playbook 文件即可,這樣會方便我們在其他地方進行引用传于。

下面是官網(wǎng)最佳實戰(zhàn)中推薦的目錄結構

production                # 關于生產(chǎn)環(huán)境服務器的資產(chǎn)清單文件
develop                     # 關于開發(fā)環(huán)境的清單文件

group_vars/
   group1                 # 組 group1 的變量文件
   group2                 # 組 group2 的變量文件
host_vars/
   hostname1              # hostname1 定義的變量文件
   hostname2              # hostname2 定義的變量文件

library/                  # 如果有自定義的模塊,放在這里(可選)
filter_plugins/           # 如果有自定義的過濾插件,放在這里(可選)

site.yml                  # 執(zhí)行 playbook 的統(tǒng)一入口文件
webservers.yml            # 特殊任務的 playbook
dbservers.yml             # 還是特殊任務的 playbook

roles/                    # role 存放目錄
    common/               # common 角色的目錄
        tasks/
            main.yml
        handlers/
            main.yml
        templates/
            ntp.conf.j2
        files/
            bar.txt
            foo.sh
        vars/    
            main.yml      # common 角色定義的變量文件
        defaults/
            main.yml      # common 角色定義的默認變量文件(優(yōu)先級低)
        meta/ 
            main.yml      #  common 角色的依賴關系文件

    webtier/              # 下面這些都是和 common 同級的目錄囱挑,是另外的一些角色
    monitoring/       
    fooapp/           

九、定義多環(huán)境

在實際的工作中可能會遇到不同環(huán)境的機器沼溜。比如 生產(chǎn)平挑、存儲、開發(fā)等

在對這些環(huán)境部署的工程中,可能會出現(xiàn)很多重復的 play通熄,如何將重復的提取處理唆涝,變成可重復調(diào)用的呢?

并且根據(jù)不同的環(huán)境唇辨,同過設置相應的特殊變量廊酣、參數(shù),來調(diào)用這些對應的 play赏枚。下面就介紹一些思路:

可以寫個腳本亡驰,從公司的 CMDB 里拉取這些環(huán)境的主機信息。根據(jù)這些信息饿幅,生成這三個環(huán)境對應的 Inventory 文件(production凡辱、stage和 develop),最后采用多 Invertory 方式進行引用栗恩。

在這些文件里面再進行分小組透乾,例如 production 環(huán)境下有 mongeodb,就定義個 P@mongodb 組磕秤。

之后根據(jù)不同的環(huán)境配置管理中的配置方法存在哪些異同進行整合乳乌。

根據(jù)不同的環(huán)境引入不同的 task,可以通過 when 方式去判斷當前的主機信息存在哪個環(huán)境中市咆,然后進行引用汉操。

目錄結構有點像這樣:

inventories/
   production/
      hosts               # inventory file for production servers
      group_vars/
         group1.yml       # here we assign variables to particular groups
         group2.yml
      host_vars/
         hostname1.yml    # here we assign variables to particular systems
         hostname2.yml

   develop/
      hosts               # inventory file for develop environment
      group_vars/
         group1.yml       # here we assign variables to particular groups
         group2.yml
      host_vars/
         stagehost1.yml   # here we assign variables to particular systems
         stagehost2.yml

library/
module_utils/
filter_plugins/

site.yml
webservers.yml
dbservers.yml

roles/
    common/
    webtier/
    monitoring/
    fooapp/

這種布局為更大的環(huán)境提供了更大的靈活性床绪,并且使不同環(huán)境之間的庫存變量完全分開。缺點是它很難維護癞己,因為文件更多膀斋。

根據(jù)環(huán)境定義不同的組

讓我們展示一個靜態(tài)清單示例痹雅。下面,生產(chǎn)文件包含所有生產(chǎn)主機的庫存绩社。

建議您根據(jù)主機(角色)的目的,以及地理位置或數(shù)據(jù)中心位置定義組(如果適用)愉耙。

# file: production

[beijingwebservers]
www-bj-1.example.com
www-bj-2.example.com

[shanghaiwebservers]
www-sh-1.example.com
www-sh-2.example.com

[beijingdbservers]
db-bj-1.example.com
db-bj-2.example.com

[shanghaidbservers]
db-sh-1.example.com

# webservers in all geos
[webservers:children]
beijing-webservers
shanghai-webservers

# dbservers in all geos
[dbservers:children]
beijingdbservers
shanghaidbservers

# everything in the beijing go
[beijing:children]
beijingwebservers
beijingdbservers

# everything in the shanghai geo
[shangai:children]
shanghaiwebservers
shanghaidbservers

Group And Host Variables

針對組和主機的變量請始終用 group_vars 和 host_vars 目錄下 定義他們贮尉。

這是非常好的方式。

---
# file: group_vars/shanghai
ntp: ntp-beijing.example.com
backup: backup-beijing.example.com
---
# file: group_vars/webservers
apacheMaxRequestsPerChild: 3000
apacheMaxClients: 900
---
# file: host_vars/db-shanghai-1.example.com
foo_agent_port: 86
bar_agent_port: 99

十朴沿、 在頂級playboo 中使用角色進行管理

在site.yml中猜谚,我們導入一個定義整個基礎架構的劇本败砂。這是一個非常簡短的示例,因為它只是導入其他一些劇本:

---
# file: site.yml
- import_playbook: webservers.yml
- import_playbook: dbservers.yml

-在類似webservers.yml的文件中(也是在頂層)魏铅,我們將webservers組的配置映射到webservers組執(zhí)行的角色:

---
# file: webservers.yml
- hosts: webservers
  roles:
    - common
    - webtier

這里的想法是我們可以選擇通過“運行” site.yml來配置整個基礎架構昌犹,也可以選擇通過運行webservers.yml來運行一個子集。

這類似于ansible的“ –limit”參數(shù)览芳,但更為明確:

ansible-playbook site.yml --limit webservers
ansible-playbook webservers.yml

組織角色的 tasks 和 handlers

  • 下面是一個示例任務文件斜姥,解釋了角色的工作方式。

我們在這里的共同角色只是設置NTP沧竟,但如果需要铸敏,它可以做更多的事情:

# file: roles/common/tasks/main.yml

- name: be sure ntp is installed
  yum:
    name: ntp
    state: present
  tags: ntp

- name: be sure ntp is configured
  template:
    src: ntp.conf.j2
    dest: /etc/ntp.conf
  notify:
    - restart ntpd
  tags: ntp

- name: be sure ntpd is running and enabled
  service:
    name: ntpd
    state: started
    enabled: yes
  tags: ntp

可以使用 tags 來代表一組有依賴性質(zhì)的 task

  • 當然還有 handlers

這是一個示例處理程序文件。作為回顧屯仗,處理程序僅在某些任務報告更改時才被觸發(fā)搞坝,并在每次播放結束時運行:

---
# file: roles/common/handlers/main.yml
- name: restart ntpd
  service:
    name: ntpd
    state: restarted

如何使用上面這個基礎架構:

  1. 若我想重新配置整個基礎架構,如此即可:
ansible-playbook -i production site.yml
  1. 那只重新配置所有的 NTP 呢?太容易了.:
ansible-playbook -i production site.yml --tags ntp
  1. 只重新配置我的 Web 服務器呢魁袜?:
ansible-playbook -i production webservers.yml
  1. 只重新配置我在上海的 Web服務器呢?:
ansible-playbook -i production webservers.yml --limit shanghai
  1. 前10臺 和 接下來的10臺呢?
ansible-playbook -i production webservers.yml --limit boston[0-9] 
ansible-playbook -i production webservers.yml --limit boston[10-20]
  1. 這里的 Invertory 通用適用于 Ad-Hoc
ansible boston -i production -m ping
ansible boston -i production -m command -a '/sbin/reboot'
  1. 其他一些參數(shù)
# 可以列出指定標志名的 task
ansible-playbook -i production webservers.yml --tags ntp --list-tasks

# 列出上海的主機列表
ansible-playbook -i production webservers.yml --limit shanghai --list-hosts

十一敦第、使用插件

十二峰弹、開發(fā)自定義插件

# Make coding more python3-ish, this is required for contributions to Ansible
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

# not only visible to ansible-doc, it also 'declares' the options the plugin requires and how to configure them.
DOCUMENTATION = '''
  callback: timer
  callback_type: aggregate
  requirements:
    - whitelist in configuration
  short_description: Adds time to play stats
  version_added: "2.0"
  description:
      - This callback just adds total play duration to the play stats.
  options:
    format_string:
      description: format of the string shown to user at play end
      ini:
        - section: callback_timer
          key: format_string
      env:
        - name: ANSIBLE_CALLBACK_TIMER_FORMAT
      default: "Playbook run took %s days, %s hours, %s minutes, %s seconds"
'''
from datetime import datetime

from ansible.plugins.callback import CallbackBase


class CallbackModule(CallbackBase):
    """
    This callback module tells you how long your plays ran for.
    """
    CALLBACK_VERSION = 2.0
    CALLBACK_TYPE = 'aggregate'
    CALLBACK_NAME = 'namespace.collection_name.timer'

    # 默認不啟用,必須在 ansible.cfg 中配置才可以啟用
    CALLBACK_NEEDS_WHITELIST = True

    def __init__(self):

        # 確保執(zhí)行父類的初始化函數(shù)芜果,以便初始化相關變量
        super(CallbackModule, self).__init__()

        # 插件被加載的時候鞠呈,會執(zhí)行這個代碼
        # 第一個  play 將在幾毫秒之后開始
        self.start_time = datetime.now()

    def _days_hours_minutes_seconds(self, runtime):
        ''' 這個回調(diào)內(nèi)部使用的方法,返回了天右钾,時蚁吝,分,秒 '''
        minutes, r_secondes = divmod(3980, 60)
        hour, minutes = divmod(minutes, 60)
        return runtime.days, hour, minutes, r_seconds

    # this is only event we care about for display, when the play shows its summary stats; the rest are ignored by the base class
    def v2_playbook_on_stats(self, stats):
        end_time = datetime.now()
        runtime = end_time - self.start_time

        # 這里是把結果打印處理舀射,
        self._display.display(self._plugin_options['format_string'] % (self._days_hours_minutes_seconds(runtime)))


最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
禁止轉載窘茁,如需轉載請通過簡信或評論聯(lián)系作者。
  • 序言:七十年代末脆烟,一起剝皮案震驚了整個濱河市山林,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邢羔,老刑警劉巖驼抹,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拜鹤,居然都是意外死亡框冀,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進店門敏簿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來明也,“玉大人,你說我怎么就攤上這事诡右。” “怎么了帆吻?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長次员。 經(jīng)常有香客問我王带,道長,這世上最難降的妖魔是什么刹衫? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任搞挣,我火速辦了婚禮,結果婚禮上仓犬,老公的妹妹穿的比我還像新娘舍肠。我一直安慰自己,他們只是感情好叽躯,可當我...
    茶點故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布险毁。 她就那樣靜靜地躺著们童,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跷跪。 梳的紋絲不亂的頭發(fā)上齐板,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天葛菇,我揣著相機與錄音橡羞,去河邊找鬼。 笑死莺债,一個胖子當著我的面吹牛签夭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播措拇,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼慎宾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了趟据?” 一聲冷哼從身側響起之宿,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤比被,失蹤者是張志新(化名)和其女友劉穎泼舱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娇昙,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡冒掌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年股毫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铃诬。...
    茶點故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖兵志,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悠栓,我是刑警寧澤弧呐,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站腥沽,受9級特大地震影響鸠蚪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盾舌,卻給世界環(huán)境...
    茶點故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一蘸鲸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧膝舅,春花似錦窑多、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至琉闪,卻和暖如春砸彬,著一層夾襖步出監(jiān)牢的瞬間斯入,已是汗流浹背蛀蜜。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留磅摹,地道東北人户誓。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像帝美,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悼潭,可洞房花燭夜當晚...
    茶點故事閱讀 43,606評論 2 350

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