使用ansible批量管理遠端伺服器
背景
本地需要管理遠端的一批伺服器,主要執行以下任務:
1) 將本地的檔案複製到遠端所有伺服器;
2) 需要在遠端伺服器中執行一個個命令;
遠端伺服器路徑並非完全一致,一般訪問通過環境變數中定義的變數路徑訪問;
比如在.bashrc中定義$app_path=/opt/app/bin
最終選擇ansible,使用這個自動化運維工具可以滿足我的需求;
下面介紹下對於我這種場景需要使用的ansible的主要模組;
關於ansible是什麼以及安裝配置請自行百度;
複製
copy模組
使用copy模組,可以將本地檔案一鍵複製到遠端伺服器;
-a後跟上引數,引數中指定本地檔案和遠端路徑;
1 |
ansible myservers -m copy -a "src=/opt/app/bin/transfer.tar dest=~/" |
ansible通過ssh登入到遠端伺服器後,並不執行.bash_profile來設定使用者自定義的環境變數;如果我們需要管理的目標伺服器的路徑不同,就不能直接寫絕對路徑,也不能寫變數替換的路徑;
比如:針對伺服器A的目標複製路徑為 /opt/app/user1/bin ,伺服器B的目標複製路徑為/opt/app/user2/bin; 這兩個路徑在各自的伺服器中的路徑變數都設定為$bin; 但在copy模組中,我們不能直接使用dest = $bin/;
路徑設定一般放在.bashrc /.bash_profile檔案,但ansible模組登入後並不載入這兩個檔案;
解決方法:
針對這種情況,可以將dest路徑設定為~/,都複製到使用者目錄,後續再通過遠端指令碼處理;
遠端批量命令
需要在遠端執行一個個命令來管理遠端伺服器;
遠端執行命令的模組有command、shell、scripts、以及raw模組;
command模組
command模組為ansible預設模組,不指定-m引數時,使用的就是command模組;
comand模組比較簡單,常見的命令都可以使用,但其命令的執行不是通過shell執行的,所以,像這些 “”, “|”, and “&”操作都不可以,當然,也就不支援管道;
示例:顯示遠端路徑:
1 2 3 4 5 6 7 |
ansible myservers -a 'pwd' 10.6.143.38 | success | rc=0 >> /home/rduser 10.6.143.53 | success | rc=0 >> /home/rduser 10.6.143.37 | success | rc=0 >> /home/rduser |
缺點:不支援管道,就沒法批量執行命令;
shell模組
使用shell模組,在遠端命令通過/bin/sh來執行;所以,我們在終端輸入的各種命令方式,都可以使用;
但是我們自己定義在.bashrc/.bash_profile中的環境變數shell模組由於沒有載入,所以無法識別;如果需要使用自定義的環境變數,就需要在最開始,執行載入自定義指令碼的語句;
對shell模組的使用可以分成兩塊:
1) 如果待執行的語句少,可以直接寫在一句話中:
1 |
ansible myservers -a ". .bash_profile;ps -fe |grep sa_q" -m shell |
2) 如果在遠端待執行的語句比較多,可寫成一個指令碼,通過copy模組傳到遠端,然後再執行;但這樣就又涉及到兩次ansible呼叫;對於這種需求,ansible已經為我們考慮到了,script模組就是幹這事的;
scripts模組
使用scripts模組可以在本地寫一個指令碼,在遠端伺服器上執行:
1 |
ansible myservers -m script -a "/opt/app/target.sh" |
這裡是命令模組的官方文件:
http://docs.ansible.com/list_of_commands_modules.html
批量執行playbooks
遠端批量命令執行的另外一種方式是用playbooks;
這裡是playbooks的官方文件:http://docs.ansible.com/playbooks.html
這裡有ansible的playbooks示例:https://github.com/ansible/ansible-examples
在python中使用ansbile API
以上執行ansible模組的方式都是在命令列中直接呼叫,如果對返回結果需要進一步處理,可以在程式中通過API呼叫的方式來使用ansible模組:
比如,以上在命令列中呼叫scripts的模組的方式在API中呼叫:
1 2 3 4 5 |
import ansible.runner results = ansible.runner.Runner( pattern='myservers', forks=5, module_name='script', module_args='/opt/app/target.sh', ).run() |
這裡是官方給出的一個詳細示例,直接執行一次,將result全部列印出來,會有直觀的瞭解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#!/usr/bin/python import ansible.runner import sys # construct the ansible runner and execute on all hosts results = ansible.runner.Runner( pattern='*', forks=10, module_name='command', module_args='/usr/bin/uptime', ).run() if results is None: print "No hosts found" sys.exit(1) print "UP ***********" for (hostname, result) in results['contacted'].items(): if not 'failed' in result: print "%s >>> %s" % (hostname, result['stdout']) print "FAILED *******" for (hostname, result) in results['contacted'].items(): if 'failed' in result: print "%s >>> %s" % (hostname, result['msg']) print "DOWN *********" for (hostname, result) in results['dark'].items(): print "%s >>> %s" % (hostname, result) |