Ansible系列(七):執行過程分析、異步模式和速度優化


我寫了更完善的Ansible專欄文章:一步到位玩兒透Ansible

Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html


1.1 ansible執行過程分析

使用ansible的-vvv-vvvv分析執行過程。以下是一個啟動遠程192.168.100.61上httpd任務的執行過程分析。其中將不必要的信息都是用"....."替換了。

# 讀取配置文件,然后開始執行對應的處理程序。
Using /etc/ansible/ansible.cfg as config file
META: ran handlers

# 第一個任務默認都是收集遠程主機信息的任務。
# 第一個收集任務,加載setup模塊
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/setup.py

# 建立連接,獲取被控節點當前用戶的家目錄,用於存放稍后的臨時任務文件,此處返回值為/root。
# 在-vvv的結果中,第一行屬於描述性信息,第二行為代碼執行段,第三行類似此處的<host_node>(,,,,,)為上一段代碼的返回結果。后同
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C ..........................
<192.168.100.61> (0, '/root\n', '')

# 再次建立連接,在遠端創建臨時任務文件的目錄,臨時目錄由配置文件中的remote_tmp指令控制
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C .......................... '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202 `" && echo ansible-tmp-1495977564.58-40718671162202="` echo /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202 `" ) && sleep 0'"'"''
<192.168.100.61> (0, 'ansible-tmp-1495977564.58-40718671162202=/root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202\n', '')

# 將要執行的任務放到臨時文件中,並使用sftp將任務文件傳輸到被控節點上
<192.168.100.61> PUT /tmp/tmpY5vJGX TO /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/setup.py
<192.168.100.61> SSH: EXEC sftp -b - -C ............. '[192.168.100.61]'
<192.168.100.61> (0, 'sftp> put /tmp/tmpY5vJGX /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/setup.py\n', '')

# 建立連接,設置遠程任務文件其所有者有可執行權限
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C ......................... '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/ /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/setup.py && sleep 0'"'"''
<192.168.100.61> (0, '', '')

# 建立連接,執行任務,執行完成后立即刪除任務文件,並返回收集到的信息給ansible。到此為止,setup收集任務結束,關閉共享連接
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C ............ '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/setup.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1495977564.58-40718671162202/" > /dev/null 2>&1 && sleep 0'"'"''
<192.168.100.61> (0, '\r\n{"invocation": {"...........', 'Shared connection to 192.168.100.61 closed.\r\n')


# 進入下一個任務,此處為服務管理任務,所以加載service模塊
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/service.py

# 建立連接,獲取被控節點當前用戶的家目錄,用於存放稍后的臨時任務文件,此處返回值為/root
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C .........................
<192.168.100.61> (0, '/root\n', '')

# 建立連接,將要執行的任務放入到臨時文件中,並傳輸到遠程目錄
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C .............. '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241 `" && echo ansible-tmp-1495977564.97-137863382080241="` echo /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241 `" ) && sleep 0'"'"''
<192.168.100.61> (0, 'ansible-tmp-1495977564.97-137863382080241=/root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241\n', '')

<192.168.100.61> PUT /tmp/tmpn5uZhP TO /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/service.py
<192.168.100.61> SSH: EXEC sftp -b - -C .............. '[192.168.100.61]'
<192.168.100.61> (0, 'sftp> put /tmp/tmpn5uZhP /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/service.py\n', '')

# 建立連接,設置遠程任務文件其所有者有可執行權限
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C ........................ '/bin/sh -c '"'"'chmod u+x /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/ /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/service.py && sleep 0'"'"''
<192.168.100.61> (0, '', '')

# 建立連接,執行任務,執行完成后立即刪除任務文件,並將執行的結果返回到ansible端。到此為止,service模塊任務執行結束,關閉共享連接
<192.168.100.61> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.61> SSH: EXEC ssh -C .............. '/bin/sh -c '"'"'/usr/bin/python /root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/service.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1495977564.97-137863382080241/" > /dev/null 2>&1 && sleep 0'"'"''
<192.168.100.61> (0, '\r\n{"msg": "............', 'Shared connection to 192.168.100.61 closed.\r\n')

將上面的進行總結,執行過程將是這樣的:

  • 讀取配置文件
  • 加載inventory文件。包括主機變量和主機組變量
  • 執行第一個任務:收集遠程被控節點的信息
    • 建立連接,獲取家目錄信息
    • 將要執行的收集任務放到臨時文件中
    • 將臨時任務文件傳輸到被控節點的臨時目錄中
    • ssh連接到遠端執行收集任務
    • 刪除任務文件
    • 將收集信息返回給ansible端
    • 關閉連接
  • 執行第二個任務,此為真正的主任務
    • 建立連接,獲取家目錄信息
    • 將要執行的任務放到臨時文件中
    • 將臨時任務文件傳輸到被控節點的臨時目錄中
    • ssh連接到遠端執行任務
    • 刪除任務文件
    • 將執行結果返回給ansible端,ansible輸出到屏幕或指定文件中
    • 關閉連接
  • 執行第三個任務
  • 執行第四個任務

如果是多個被控節點,那么將同時在多個節點上並行執行每一個任務,例如同時執行信息收集任務。不同節點之間的任務沒有先后關系,主要依賴於性能。每一個任務執行完畢都會立即將結果返回給ansible端,所以可以通過ansible端結果的輸出順序和速度判斷執行完畢的先后順序。

如果節點數太多,ansible無法一次在所有遠程節點上執行任務,那么將先在一部分節點上執行一個任務(每一批節點的數量取決於fork進程數量),直到這一批所有節點上該任務完全執行完畢才會接入下一個批節點(數量取決於fork進程數量),直到所有節點將該任務都執行完畢,然后重新回到第一批節點開始執行第二個任務。依次類推,直到所有節點執行完所有任務,ansible端才會釋放shell。這是默認的同步模式,也就是說在未執行完畢的時候,ansible是占用當前shell的,任務執行完畢后,釋放shell了才可以輸入其他命令做其他動作。

如果是異步模式,假如fork控制的並發進程數為5,遠程控制節點為24個,則ansible一開始會將5個節點的任務扔在后台,並每隔一段時間去檢查這些節點的任務完成情況,當某節點完成不會立即返回,而是繼續等待直到5個進程都空閑了,才會將這5個節點的結果返回給ansible端,ansible會繼續將下一批5個節點的任務扔在后台並每隔一段時間進行檢查,依次類推,直到完成所有任務。

在異步模式下,如果設置的檢查時間間隔為0,在將每一批節點的任務丟到后台后都會立即返回ansible,並立即將下一批節點的任務丟到后台,直到所有任務都丟到后台完成后,會返回ansible端,ansible會立即釋放占用的shell。也就是說,此時ansible是不會管各個節點的任務執行情況的,不管執行成功還是失敗。

因此,在輪訓檢查時間內,ansible仍然正在運行(盡管某批任務已經被放到后台執行了),當前shell進程仍被占用處於睡眠狀態,只有指定的檢查時間間隔為0,才會盡快將所有任務放到后台並釋放shell。

需要注意3點:

1 .按批(例如每次5台全部完成一個任務才進入下一批的5台)完成任務的模式在ansible 2.0版本之后可以通過修改ansible的執行策略來改變(見后文),改變后會變成"前赴后繼"的執行模式:當一個節點執行完一個任務會立即接入另一個節點,不再像默認情況一樣等待這一批中的其他節點完成該任務。
2 .上面執行過程是默認的執行過程,如果開啟了pipelining加速ansible執行效率,會省去sftp到遠端的過程。
3 .信息收集任務是默認會執行的,但是可以設置禁用它。

1.2 ansible並發和異步

上面已經對ansible的執行過程進行了很詳細的分析,也解釋了同步和異步的模式是如何處理任務的。所以此處簡單舉幾個例子。

ansible默認只會創建5個進程並發執行任務,所以一次任務只能同時控制5台機器執行。如果有大量的機器需要控制,例如20台,ansible執行一個任務時會先在其中5台上執行,執行成功后再執行下一批5台,直到全部機器執行完畢。使用-f選項可以指定進程數,指定的進程數量多一些,不僅會實現全並發,對異步的輪訓poll也會有正面影響。

ansible默認是同步阻塞模式,它會等待所有的機器都執行完畢才會在前台返回。可以采取異步執行模式。

異步模式下,ansible會將節點的任務丟在后台,每台被控制的機器都有一個job_id,ansible會根據這個job_id去輪訓該機器上任務的執行情況,例如某機器上此任務中的某一個階段是否完成,是否進入下一個階段等。即使任務早就結束了,但只有輪訓檢查到任務結束后才認為該job結束。可以指定任務檢查的時間間隔,默認是10秒。除非指定任務檢查的間隔為0,否則會等待所有任務都完成后,ansible端才會釋放占用的shell。

如果指定時間間隔為0,則ansible會立即返回(至少得連接上目標主機,任務發布成功之后立即返回),並不會去檢查它的任務進度。

ansible centos -B200 -P 0 -m yum -a "name=dos2unix" -o -f 6 
192.168.100.61 | SUCCESS => {"ansible_job_id": "986026954359.9166", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/986026954359.9166", "started": 1}
192.168.100.59 | SUCCESS => {"ansible_job_id": "824724696770.9431", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/824724696770.9431", "started": 1}
192.168.100.60 | SUCCESS => {"ansible_job_id": "276581152579.10006", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/276581152579.10006", "started": 1}
192.168.100.64 | SUCCESS => {"ansible_job_id": "237326453903.72268", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/237326453903.72268", "started": 1}
192.168.100.63 | SUCCESS => {"ansible_job_id": "276700021098.73070", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/276700021098.73070", "started": 1}
192.168.100.65 | SUCCESS => {"ansible_job_id": "877427488272.72032", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/877427488272.72032", "started": 1}

關於同步、異步以及異步時的並行數、輪訓間隔對ansible的影響,通過以下示例說明:

當有6個節點時,僅就釋放shell的速度而言,以下幾種寫法:

# 同步模式,大約10秒返回。
ansible centos -m command -a "sleep 5" -o 
# 異步模式,分兩批執行。大約10秒返回。
ansible centos -B200 -P 1 -m command -a "sleep 5" -o -f 5
# 異步模式,和上一條命令時間差不多,但每次檢查時間長一秒,所以可能會稍有延遲。大約11-12秒返回。
ansible centos -B200 -P 2 -m command -a "sleep 5" -o -f 5
# 異步模式,一批就執行完,大約5-6秒返回。
ansible centos -B200 -P 1 -m command -a "sleep 5" -o -f 6
# 異步模式,一批就完成,大約5-6秒完成。
ansible centos -B200 -P 2 -m command -a "sleep 5" -o -f 6 
# 異步模式,分兩批,且檢查時間過長。即使只睡眠5秒,但仍需要10秒才能判斷該批執行結束。所以大約20秒返回。
ansible centos -B200 -P 10 -m command -a "sleep 5" -o -f 5 
# 異步模式,一批執行完成,但檢查時間超過睡眠時間,因此大約10秒返回。
ansible centos -B200 -P 10 -m command -a "sleep 5" -o -f 6

在異步執行任務時,需要注意那些有依賴性的任務。對於那些對資源要求占有排它鎖的任務,如yum,不應該將Poll的間隔設置為0。如果設置為0,很可能會導致資源阻塞。

總結來說,大概有以下一些場景需要使用到ansible的異步特性:

  • 某個task需要運行很長的時間,這個task很可能會達到ssh連接的timeout
  • 沒有任務是需要等待它才能完成的,即沒有任務依賴此任務是否完成的狀態
  • 需要盡快返回當前shell

當然也有一些場景不適合使用異步特性:

  • 這個任務是需要運行完后才能繼續另外的任務的
  • 申請排它鎖的任務

當然,對於有任務依賴性的任務,也還是可以使用異步模式的,只要檢查它所依賴的主任務狀態已完成就可以。例如,要配置nginx,要求先安裝好nginx,在配置nginx之前先檢查yum安裝的狀態。

- name: 'YUM - fire and forget task'
  yum: name=nginx state=installed
  async: 1000
  poll: 0
  register: yum_sleeper

- name: 'YUM - check on fire and forget task'
  async_status: jid={{ yum_sleeper.ansible_job_id }}
  register: job_result
  until: job_result.finished
  retries: 30

1.3 ansible的-t選項妙用

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

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

除了使用-t選項,使用重定向將結果重定向到某個文件中也是一樣的效果。至於為何會如此,我也不知道,是在無意中測試出來的。有必要指出:我在CentOS 6.6上遇到過這樣的問題,但並不是總會如此,且在CentOS 7上正常。因此,如果你也出現了這樣的問題,可以參考這種偏方。

以CentOS 6.6安裝的ansible 2.3為例,正常執行ansible會非常慢,使用-t可以解決這個問題。如下。

沒有使用-t時:移除dos2unix包所需時間為13秒多。

time ansible centos -B200 -P 0 -m yum -a "name=dos2unix state=removed" -o -f 6
192.168.100.60 | SUCCESS => {"ansible_job_id": "987125400759.10653", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/987125400759.10653", "started": 1}
192.168.100.63 | SUCCESS => {"ansible_job_id": "735153954362.74074", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/735153954362.74074", "started": 1}
192.168.100.61 | SUCCESS => {"ansible_job_id": "192721090554.9813", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/192721090554.9813", "started": 1}
192.168.100.64 | SUCCESS => {"ansible_job_id": "494724112239.73269", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/494724112239.73269", "started": 1}
192.168.100.59 | SUCCESS => {"ansible_job_id": "2259915341.10078", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/2259915341.10078", "started": 1}
192.168.100.65 | SUCCESS => {"ansible_job_id": "755223232484.73025", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/755223232484.73025", "started": 1}

real    0m13.746s
user    0m1.288s
sys     0m1.417s

使用-t選項后:安裝dos2unix只需1.9秒左右。

time ansible centos -B200 -P 0 -m yum -a "name=dos2unix state=installed" -o -f 6 -t /tmp/a 


real    0m1.933s
user    0m0.398s
sys     0m0.900s

之后即使不再使用-t選項,對同樣的主機進行操作,速度也會變得非常快。

time ansible centos -B200 -P 0 -m yum -a "name=dos2unix state=removed" -o -f 6

real    0m1.730s
user    0m0.892s
sys     0m0.572s

至於保存的內容為何?實際上僅僅只是保存了普通的輸出內容而已。

ll /tmp/a/
total 24
-rw-r--r-- 1 root root 145 May 28 15:54 192.168.100.59
-rw-r--r-- 1 root root 145 May 28 15:54 192.168.100.60
-rw-r--r-- 1 root root 143 May 28 15:54 192.168.100.61
-rw-r--r-- 1 root root 143 May 28 15:54 192.168.100.63
-rw-r--r-- 1 root root 145 May 28 15:54 192.168.100.64
-rw-r--r-- 1 root root 145 May 28 15:54 192.168.100.65

cat /tmp/a/192.168.100.59
{"ansible_job_id": "659824383578.10145", "changed": true, "finished": 0, "results_file": "/root/.ansible_async/659824383578.10145", "started": 1}

1.4 優化ansible速度

最初,ansible的執行效率和saltstack(基於zeromq消息隊列的方式)相比要慢的多的多,特別是被控節點量很大的時候。但是ansible發展到現在,它的效率得到了極大的改善。在被控節點不太多的時候,默認的設置已經夠快,即使被控節點數量巨大的時候,也可以通過一些優化,極大的提高其執行效率。

前面"-t"選項也算是一種提速方式,但算是"bug"式的問題,所以沒有通用性。

1.4.1 設置ansible開啟ssh長連接

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

要開啟ssh長連接,要求ansible端的openssh版本高於或等於5.6。使用ssh -V可以查看版本號。然后設置ansible使用ssh連接被控端的連接參數,此處修改/etc/ansible/ansible.cfg,在此文件中啟動下面的連接選項,其中ControlPersist=5d是控制ssh連接會話保持時長為5天。

ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d

除此之外直接設置/etc/ssh/ssh_config(不是sshd_config,因為ssh命令是客戶端命令)中對應的長連接項也是可以的。 開啟長連接后,在會話過期前會一直建立連接,在netstat的結果中會看到ssh連接是一直established狀態,且會在當前用戶家目錄的".ansible/cp"目錄下生成一些socket文件,每個會話一個文件。 例如:執行一次ad-hoc操作。

ansible centos -m ping

查看netstat,發現ssh進程的會話一直是established狀態。

shell> netstat -tnalp

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address      State       PID/Program name    
tcp        0      0 0.0.0.0:22              0.0.0.0:*            LISTEN      1143/sshd           
tcp        0      0 127.0.0.1:25            0.0.0.0:*            LISTEN      2265/master         
tcp        0      0 192.168.100.62:58474    192.168.100.59:22    ESTABLISHED 31947/ssh: /root/.a 
tcp        0     96 192.168.100.62:22       192.168.100.1:8189   ESTABLISHED 29869/sshd: root@pt 
tcp        0      0 192.168.100.62:37718    192.168.100.64:22    ESTABLISHED 31961/ssh: /root/.a 
tcp        0      0 192.168.100.62:38894    192.168.100.60:22    ESTABLISHED 31952/ssh: /root/.a 
tcp        0      0 192.168.100.62:48659    192.168.100.61:22    ESTABLISHED 31949/ssh: /root/.a 
tcp        0      0 192.168.100.62:33546    192.168.100.65:22    ESTABLISHED 31992/ssh: /root/.a 
tcp        0      0 192.168.100.62:54824    192.168.100.63:22    ESTABLISHED 31958/ssh: /root/.a 
tcp6       0      0 :::22                   :::*                 LISTEN      1143/sshd           
tcp6       0      0 ::1:25                  :::*                 LISTEN      2265/master

且家目錄下"~/.ansible/cp/"下會生成對應的socket文件。

ls -l ~/.ansible/cp/
total 0
srw------- 1 root root 0 Jun 3 18:26 5c4a6dce87
srw------- 1 root root 0 Jun 3 18:26 bca3850113
srw------- 1 root root 0 Jun 3 18:26 c89359d711
srw------- 1 root root 0 Jun 3 18:26 cd829456ec
srw------- 1 root root 0 Jun 3 18:26 edb7051c84
srw------- 1 root root 0 Jun 3 18:26 fe17ac7eed

1.4.2 開啟pipelining

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

開啟pipelining的方式是配置文件(如ansible.cfg)中設置pipelining=true,默認是false。

shell> grep '^pipelining' /etc/ansible/ansible.cfg
pipelining = True

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

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

grep requiretty /etc/sudoers
# Defaults requiretty

修改設置/etc/sudoers是在被控節點上進行的(或者ansible連接過去修改),其實在ansible端也可以解決sudo的問題,只需在ansible的ssh參數上加上"-tt"選項即可。

ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d -tt

以下是開啟pipelining前ansible執行過程,其中將很多不必要的信息使用......來替代了。

######## 開啟pipelining前,執行ping模塊的過程 ########
Using /etc/ansible/ansible.cfg as config file
Loading callback plugin minimal of type stdout, v2.0 from /usr/lib/python2.7/site-packages/ansible/plugins/callback/__init__.pyc
META: ran handlers
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/ping.py

# 首先建立一次ssh連接,獲取遠端當前用戶家目錄,用於存放稍后的臨時任務文件
<192.168.100.65> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.65> SSH: EXEC ssh -vvv -C ................ 192.168.100.65 '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''
<192.168.100.65> (0, '/root\n', ................)

# 再次建立ssh連接,創建臨時文件目錄
<192.168.100.65> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.65> SSH: EXEC ssh -vvv -C ..................... 192.168.100.65 '/bin/sh -c '"'"'( umask 77 && mkdir -p "......." ) && sleep 0'"'"''
<192.168.100.65> (0, 'ansible-tmp-1496489511.13-10633592020239=/root/.ansible/tmp/ansible-tmp-1496489511.13-10633592020239\n', '.............')

# 將任務放入到本地臨時文件中,然后使用sftp傳輸到遠端
<192.168.100.65> PUT /tmp/tmp2_VKGo TO /root/.ansible/tmp/ansible-tmp-1496489511.13-10633592020239/ping.py
<192.168.100.65> SSH: EXEC sftp -b - -vvv -C ................. '[192.168.100.65]'
<192.168.100.65> (0, 'sftp> put /tmp/tmp2_VKGo /root/.ansible/tmp/ansible-tmp-1496489511.13-10633592020239/ping.py\n', '.....................')

# 又一次建立ssh連接,對任務文件進行授權
<192.168.100.65> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.65> SSH: EXEC ssh -vvv -C ............. 192.168.100.65 '/bin/sh -c '"'"'chmod u+x .......... /ping.py && sleep 0'"'"''
<192.168.100.65> (0, '', '........................')

# 最后執行任務,完成任務后刪除任務文件,並返回ansible端信息,注意ssh -tt選項,它強制為ssh會話分配tty,這樣可以執行sudo命令
<192.168.100.65> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.65> SSH: EXEC ssh -vvv -C .............. -tt 192.168.100.65 '/bin/sh -c '"'"'/usr/bin/python .........../ping.py; rm -rf ".........." > /dev/null 2>&1 && sleep 0'"'"''
<192.168.100.65> (0, '\r\n{"invocation": {"...............')
以下是開啟pipelining后,ansible執行過程。
########### 開啟pipelining后,執行ping模塊的過程 ########
Using /etc/ansible/ansible.cfg as config file
Loading callback plugin minimal of type stdout, v2.0 from /usr/lib/python2.7/site-packages/ansible/plugins/callback/__init__.pyc
META: ran handlers
Using module file /usr/lib/python2.7/site-packages/ansible/modules/system/ping.py

# 只建立一次ssh連接,所有動作都在這一個ssh連接中完成,由於沒有使用-tt選項,所以需要在被控主機上禁用requiretty選項
<192.168.100.65> ESTABLISH SSH CONNECTION FOR USER: None
<192.168.100.65> SSH: EXEC ssh -vvv -C ............ 192.168.100.65 '/bin/sh -c '"'"'/usr/bin/python && sleep 0'"'"''
<192.168.100.65> (0, '\n{".............')

從上面的過程對比中可以看到,開啟pipelining后,每次執行任務時都大量減少了ssh連接次數(只需要一次ssh連接),且省去了sftp傳輸任務文件的過程,因此在管理大量節點時能極大提升執行效率。

1.4.3 修改ansible執行策略

默認ansible在遠程執行任務是按批並行執行的,一批控制多少台主機由命令行的"-f"或"--forks"選項控制。例如,默認的並行進程數是5,如果有20台被控主機,那么只有在每5台全部執行完一個任務才繼續下一批的5台執行該任務,即使中間某台機器性能較好,完成速度較快,它也會空閑地等待在那,直到所有20台主機都執行完該任務才會以同樣的方式繼續下一個任務。如下所示:

h1 h2 h3 h4 h5(T1)-->h6 h7 h8 h9 h10(T1)...-->h16 h17 h18 h19 h20(T1)-->h1 h2 h3 h4 h5(T2)-->.....

在ansible 2.0中,添加了一個策略控制選項strategy,默認值為"linear",即上面按批並行處理的方式。還可以設置strategy的值為"free"。 在free模式下,ansible會盡可能快的切入到下一個主機。同樣是上面的例子,首先每5台並行執行一個任務,當其中某一台機器由於性能較好提前完成了該任務,它不會等待其他4台完成,而是會跳出該任務讓ansible切入到下一台機器來執行該任務。也就是說,這種模式下,一台主機完成一個任務后,另一台主機會立即執行任務,它是"前赴后繼"的方式。如下所示:

h1 h2 h3 h4 h5(T1)-->h1 h2 h3 h4 h6(T1)-->h1 h3 h4 h6 h7(T1)-->......-->h17 h18 h19 h20(T1) h1(T2)-->h18 h19 h20(T1) h1 h2(T2)-->...

設置的方式如下:

- hosts: all
  strategy: free
  tasks:
  ...

1.4.4 設置facts緩存

ansible或ansible-playbook默認總是先收集facts信息。在被控主機較少的情況下,收集信息還可以容忍,如果被控主機數量非常大,收集facts信息會消耗掉非常多時間。

可以設置"gather_facts: no"來禁止ansible收集facts信息,但是有時候又需要使用facts中的內容,這時候可以設置facts的緩存。例如,在空閑的時候收集facts,緩存下來,在需要的時候直接讀取緩存進行引用。

ansible的配置文件中可以修改'gathering'的值為'smart'、'implicit'或者'explicit'。smart表示默認收集facts,但facts已有的情況下不會收集,即使用緩存facts;implicit表示默認收集facts,要禁止收集,必須使用gather_facts: False;explicit則表示默認不收集,要顯式收集,必須使用gather_facts: Ture

在使用facts緩存時(即設置為smart),ansible支持兩種facts緩存:redis和jsonfile。

例如,以下是/etc/ansible/ansible.cfg中jsonfile格式的緩存配置方法。

[defaults]
gathering = smart
fact_caching_timeout = 86400
fact_caching = jsonfile
fact_caching_connection = /path/to/cachedir

這里設置的緩存過期時間為86400秒,即緩存一天。緩存的json文件放在/path/to/cachedir目錄下,各主機的緩存文件以主機名命名。緩存文件是一個json文件,要查看緩存文件,如/path/to/cachedir/192.168.100.59中的內容,使用如下語句即可。

cat /path/to/cachedir/192.168.100.59 | python -m json.tool


免責聲明!

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



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