Ansible性能優化——提升ansible執行效率


最初,ansible的執行效率和saltstack(基於zeromq消息隊列的方式)相比要慢的多的多,特別是被控節點量很大的時候。但是ansible發展到現在,它的效率得到了極大的改善。在被控節點不太多的時候,默認的設置已經夠快。即使被控節點數量巨大的時候,也可以通過一些優化去極大的提高ansible的執行效率。所以在使用 Ansible 的過程中,當管理的服務器數量增加時,不得不面對一個無法避免的問題執行效率慢,這里列出一些解決辦法。

一、關閉gathering facts功能

如果觀察過ansible-playbook的執行過程,就會發現ansible-playbook的第1個步驟總是執行gather facts,不論你有沒有在playbook設定這個tasks。
如果你不需要獲取被控機器的fact數據的話,就可以關閉獲取fact數據功能。關閉之后,可以加快ansible-playbook的執行效率,尤其是你管理很大量的機器時,這非常明顯。
關閉獲取facts很簡單,只需要在playbook文件中加上"gather_facts: False" 或者 "gather_facts: No"即可(False和No都為小寫也可以)。

$ cat test.yml
- hosts: test_server
  remote_user: root

  tasks:
    - name: this is a test
      shell: echo "haha"


# 執行這個paly,會發現第一個執行的是gather facts,因為默認是打開gather facts功能的!!!!
$ ansible-playbook test.yml

PLAY [test_server] ******************************************************************************************************

TASK [Gathering Facts] **************************************************************************************************
ok: [10.4.7.102]
ok: [10.4.7.101]

TASK [this is a test] ***************************************************************************************************
changed: [10.4.7.102]
changed: [10.4.7.101]

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

現在關閉gathering facts功能

$ cat test.yml
- hosts: test_server
  remote_user: root
  gather_facts: False

  tasks:
    - name: this is a test
      shell: echo "haha"

# 再執行這個play,就會發現沒有了gathering facts執行過程,整個執行速度也快了!
$ ansible-playbook test.yml

PLAY [test_server] ******************************************************************************************************

TASK [this is a test] ***************************************************************************************************
changed: [10.4.7.102]
changed: [10.4.7.101]

PLAY RECAP **************************************************************************************************************
10.4.7.101                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
10.4.7.102                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

二、開啟SSH pipelining

pipeline是openssh的一個特性,ssh pipelining 是一個加速Ansible執行速度的簡單方法。

在ansible執行每個任務的整個流程中,有一個過程是將臨時任務文件put到遠程的ansible客戶機上,然后通過ssh連接過去遠程執行這個任務。
如果開啟了pipelining,一個任務的所有動作都在一個ssh會話中完成,也會省去sftp到遠端的過程,它會直接將要執行的任務在ssh會話中進行。

ssh pipelining 默認是關閉!!!!之所以默認關閉是為了兼容不同的sudo配置,主要是 requiretty 選項。如果不使用sudo,建議開啟!!!
打開此選項可以減少ansible執行沒有傳輸時ssh在被控機器上執行任務的連接數。
不過,如果使用sudo,必須關閉requiretty選項。修改/etc/ansible/ansible.cfg 文件可以開啟pipelining

$ vim /etc/ansible/ansible.cfg
........
pipelining = True

這樣開啟了pipelining之后, ansible執行的整個流程就少了一個PUT腳本去遠程服務端的流程,然后就可以批量對機器執行命令試下,可以明顯感受到速度的提升。


但是要注意的是:
如果在ansible中使用sudo命令的話(ssh user@host sudo cmd),需要在被控節點的/etc/sudoers中禁用"requiretty"!!!!

之所以要設置/etc/sudoers中的requiretty,是因為ssh遠程執行命令時,它的環境是非登錄式非交互式shell,默認不會分配tty,沒有ttysshsudo就無法關閉密碼回顯(使用
"-tt"選項強制SSH分配tty)。所以出於安全考慮,/etc/sudoers中默認是開啟requiretty的,它要求只有擁有tty的用戶才能使用sudo,也就是說ssh連接過去不允許執行sudo
可以通過visudo編輯配置文件,注釋該選項來禁用它。

$ grep requiretty /etc/sudoers  
# Defaults  requiretty

三、開啟SSH長連接

ansible天然支持openssh,默認連接方式下,它對ssh的依賴性非常強。所以優化ssh連接,在一定程度上也在優化ansible。其中一點是開啟ssh的長連接,即長時間保持連接狀態。

Ansible模式是使用SSH和遠程主機進行通信, 所以Ansible對SSH的依賴性非常強, 在OpenSSH 5.6版本以后SSH就支持了Multiplexing(多路復用)。
所以如果Ansible中控機的SSH -V版本高於5.6時, 就可以使用ControlPersist來提高ssh連接速度,從而提高ansible執行效率。

$ cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 

$ ssh -V
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

$ vim /etc/ansible/ansible.cfg
..........
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
# 注意:ConrolPersist=5d, 這個參數是設置整個長連接保持時間為5天。

開啟此參數的ssh長連接功能后,在會話過期前會一直建立連接,在netstat的結果中會看到ssh連接是一直established狀態,且通過SSH連接過的設備都會在當前用戶家目錄的
".ansible/cp"目錄下生成一個socket文件,每個會話對應生成一個socket文件。也可以通過netstat命令查看, 會發現有一個ESTABLISHED狀態的連接一直與遠程設備進行着TCP連接。

$ ps -ef|grep ssh|grep ansible
root      26064      1  0 17:32 ?        00:00:00 ssh: /root/.ansible/cp/cb9972d2a5 [mux]
root      26067      1  0 17:32 ?        00:00:00 ssh: /root/.ansible/cp/baefa88ac8 [mux]

$ ps -ef|grep ssh|grep /root
root      26064      1  0 17:32 ?        00:00:00 ssh: /root/.ansible/cp/cb9972d2a5 [mux]
root      26067      1  0 17:32 ?        00:00:00 ssh: /root/.ansible/cp/baefa88ac8 [mux]

$ ls /root/.ansible/cp/
baefa88ac8  cb9972d2a5

需要注意:
ControlPersist 特性需要高版本的SSH才支持,CentOS 6默認是不支持的,如果需要使用,需要自行升級openssh(確保SSH -V版本高於5.6)。
ControlPersist即持久化socket,一次驗證,多次通信。並且只需要修改 ssh 客戶端就行,也就是 Ansible 機器即可。

三、設置facts緩存

如果細心的話, 就會發現執行playbook的時候, 默認第一個task都是GATHERING FACTS, 這個過程就是Ansible在收集每台主機的facts信息。
方便我們在playbook中直接飲用facts里的信息,當然如果你的playbook中不需要facts信息, 可以在playbook中設置"gather_facts: False"來提高playbook效率.

但是如果我們既想在每次執行playbook的時候都能收集facts, 又想加速這個收集過程, 那么就需要配置facts緩存了。

3.1 使用json文件緩存

$ vim /etc/ansible/ansible.cfg
.........
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_caching_connection = /dev/shm/ansible_fact_cache

# 正常配置palybook,不需要關閉gathering facts功能
$ cat test.yml 
---
- hosts: 10.4.7.101
  remote_user: root
  vars:
    - list: [1,2,3]
  tasks:
    - name: this is loop
      debug: msg="{{ item }}"
      with_items: '{{list}}'

查看這個playbook過程,用時6.699s(第一次可能稍微慢點,緩存之后,后面執行就很快了)
$ time ansible-playbook test.yml 

PLAY [10.4.7.101] *******************************************************************************************************************************

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

TASK [this is loop] *****************************************************************************************************************************
ok: [10.4.7.101] => (item=1) => {
    "msg": 1
}
ok: [10.4.7.101] => (item=2) => {
    "msg": 2
}
ok: [10.4.7.101] => (item=3) => {
    "msg": 3
}

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


real	0m6.699s
user	0m1.301s
sys     0m0.250s

# 如果去掉上面的facts緩存的四行配置,再次執行上面的playbok,發現用時10s左右!!!

# 查看緩存文件
$ ls /dev/shm/ansible_fact_cache/
10.4.7.101

3.2 使用redis存儲facts文件需安裝redis,還需要安裝python庫

$ yum install redis
$ yum -y install epel-release
$ yum install python-pip
$ pip install redis
$ vim /etc/ansible/ansible.cfg
........
gathering = smart
facts_caching_timeout = 86400      #設置緩存過期時間86400秒
facts_caching = redis              # 使用redis或者 (或者使用memcached,即"facts_caching = memcached")
fact_caching_connection = 127.0.0.1:6379
#若redis設置了密碼,比如密碼為"admin",則配置修改如下:
# fact_caching_connection = localhost:6379:0:admin

$ systemctl start redis
$ lsof -i:6379
COMMAND     PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 26593 redis    4u  IPv4 125427      0t0  TCP localhost:6379 (LISTEN)

$ time ansible-playbook test.yml 

PLAY [10.4.7.101] *******************************************************************************************************************************

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

TASK [this is loop] *****************************************************************************************************************************
ok: [10.4.7.101] => (item=1) => {
    "msg": 1
}
ok: [10.4.7.101] => (item=2) => {
    "msg": 2
}
ok: [10.4.7.101] => (item=3) => {
    "msg": 3
}

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


real	0m6.720s
user	0m1.219s
sys	    0m0.338s

需要注意:
在使用redis緩存后,如果出現異常(若未出現,請忽略):TypeError: the JSON object must be str, not 'bytes'。
解決辦法:
$ find / -name ansible
$ vim /usr/lib/python2.7/site-packages/ansible/plugins/cache/redis.py
..........
self._cache[key] = json.loads(value.decode('utf-8'))     # 修改為這個
    
查看redis存儲情況
$ redis-cli
127.0.0.1:6379> keys *
1) "ansible_facts10.4.7.101"
2) "ansible_cache_keys"

總之:不同網絡環境下的耗時肯定是不同的,但是設置緩存是肯定可以加快 Ansible 運行速度的,特別是 playbook 的運行。

四、Ansible取消交互

$ vim /etc/ansible/ansible.cfg
........
host_key_checking = False          # 打開注釋即可
    
# 取消ssh的yes和no的交互:
$ vim /root/.ssh/config
UserKnownHostsFile /dev/null
ConnectTimeout 15
StrictHostKeyChecking no
    
或者直接ssh時增加一個參數
$ ssh -o StrictHostKeyChecking=no -p22 root@10.4.7.101

五、Ansible的-t選項,提高ansible執行效率

ansible的"-t""--tree"選項是將ansible的執行結果按主機名保存在指定目錄下的文件中。

有些時候,ansible執行起來的速度會非常慢,這種慢體現在即使執行的是一個立即返回的簡單命令(如ping模塊),也會耗時很久,且不是因為ssh連接慢導致的。
如果使用-t選項,將第一次執行得到的結果按inventory中定義的主機名保存在文件中,下次執行到同一台主機時速度將會變快很多,即使之后不再加上-t選項,
也可以在一定時間內保持迅速執行。即使執行速度正常(如執行一個Ping命令0.7秒左右),使用-t選項也可以在此基礎上變得更快。

除了使用-t選項,使用重定向將結果重定向到某個文件中也是一樣的效果。
這也算是一種ansible提速方式,但在centos6上使用低版本ansible時,有時會出現執行很慢的現象,但不是每次都這樣,且centos7執行速度正常
所以這也是一種"bug"式問題,故這種方式沒有通用性。

$ time ansible test_server -m command -a "hostname"
$ time ansible test_server -m command -a "hostname" -t /tmp/test
 
$ ll /tmp/test/
總用量 8
-rw-r--r--. 1 root root 236 2月   7 17:59 10.4.7.101
-rw-r--r--. 1 root root 307 2月   7 17:59 10.4.7.102

上面做了對比,發現使用-t或重定向方式,將ansible的執行結果按主機名保存在指定目錄下的文件中,ansible執行效率會有所提升。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM