簡介
Ansible 是一個系統自動化工具,可以用來做系統配管理,批量對遠程主機執行操作指令。我自己使用 Ansible 也有一段時間了,這里總結了一些使用 Ansible 過程中使用的心得與大家分享。
Ansible 性能優化
在使用 Ansible 的過程中,當管理的服務器數量增加時,不得不面對一個無法避免的問題執行效率慢,這里列出一些解決辦法。
優化前的准備—收集數據
在做性能優化之前首先需要做的是收集一些統計數據,這樣才能為后面做的性能優化提供數據支持,對比優化前后的結果。非常不錯的是,在 github 發現一個 Ansible 任務計時插件“ansible-profile”,安裝這個插件后會顯示 ansible-playbook 執行每一個任務所花費的時間。Github 地址: https://github.com/jlafon/ansible-profile 。 這個插件安裝很簡單,只需要簡單的三個命令即可完成安裝。在你的 playbook 文件的目錄下創建一個目錄,目錄名 callback_plugins 然后將下載的 profile_tasks.py 文件放到該目錄下。
cd /etc/ansible
mkdir callback_plugins cd callback_plugins wget https://raw.githubusercontent.com/jlafon/ansible-profile/master/callback_plugins/profile_tasks.py
現在,執行 ansible-playbook 命令就會看到 playbook 中每個 tasks 的用時情況。
圖 1.ansible-playbook tasks 用時情況

在這里,我設置了 2 個 task,1 個 task sleep 10 秒,另 1 個 task sleep 15 秒,在 PLAY RECAP 處會匯總所有 task 執行消耗的時間。
關閉 gathering facts
如果您觀察過 ansible-playbook 的執行過程中,您會發現 ansible-playbook 的第 1 個步驟總是執行 gather facts,不論你有沒有在 playbook 設定這個 tasks。如果你不需要獲取被控機器的 fact 數據的話,你可以關閉獲取 fact 數據功能。關閉之后,可以加快 ansible-playbook 的執行效率,尤其是你管理很大量的機器時,這非常明顯。關閉獲取 facts 很簡單,只需要在 playbook 文件中加上“gather_facts: no”即可。如下
---
- hosts: 172.16.64.240 gather_facts: no remote_user: liheng sudo: yes roles: - {role: profile_test}
好的,來看關閉前后的執行時間變化。
圖 2. 關閉 gather_facts 前后的執行變化

關閉前后,執行時間相關 1 秒,因為我這里只有一台機器,所以時間差距並不是很明顯。不過,從這個例子也可以看出,關閉 facts 獲取后,執行速度是快了的。
SSH PIPElinING
SSH pipelining 是一個加速 Ansible 執行速度的簡單方法。ssh pipelining 默認是關閉,之所以默認關閉是為了兼容不同的 sudo 配置,主要是 requiretty 選項。如果不使用 sudo,建議開啟。打開此選項可以減少 ansible 執行沒有傳輸時 ssh 在被控機器上執行任務的連接數。不過,如果使用 sudo,必須關閉 requiretty 選項。修改 /etc/ansible/ansible.cfg 文件可以開啟 pipelining
將
pipelining=False
修改為
pipelining=True
修改完后,可以批量對機器執行命令試下,可以明顯感受到速度的提升。
ControlPersist
ControlPersist 特性需要高版本的 SSH 才支持,CentOS 6 默認是不支持的,如果需要使用,需要自行升級 openssh。ControlPersist 即持久化 socket,一次驗證,多次通信。並且只需要修改 ssh 客戶端就行,也就是 Ansible 機器即可。
升級 openssh 的過程這里不做介紹。這里只介紹下 ControlPersist 設置的辦法。
cat ~/.ssh/config
Host *
Compression yes
ServerAliveInterval 60
ServerAliveCountMax 5 ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 4h
在開啟了 ControlPersist 特性后,SSH 在建立了 sockets 之后,節省了每次驗證和創建的時間。在網絡狀況不是特別理想,尤其是跨互聯網的情況下,所帶來的性能提升是非常可觀的。有這邊需求的,試試就知道了。
Ansible-playbook 技巧
獲取執行命令的輸出 --Register
在剛開始使用 ansible-playbook 做應用程序部署的時候,因為在部署的過程中有使用到 command 或 shell 模塊執行一些自定義的腳本,而且這些腳本都會有輸出,用來表示是否執行正常或失敗。如果像之前自己寫腳本做應用程序部署的,這很好實現。但現在是用 Ansible 做,那么要怎么樣做可以獲取到 ansible playbook 中 command 模塊的輸出呢? Ansible 也提供的解決辦法,這時我們就可以通過使用 register 關鍵字來實現,register 關鍵字可以存儲指定命令的輸出結果到一個自定義的變量中,我們通過訪問這個自定義變量就可以獲取到命令的輸出結果。Register 的使用很方便,只需要在 task 聲明 register 關鍵字,並自定義一個變量名就可以。如下:
- name: echo date
command: date register: date_output - name: echo date_output command: echo "30" when: date_output.stdout.split(' ')[2] == "30"
這里第 1 個 task 是執行了一個 date 命令,register 關鍵字將 date 命令的輸出存儲到 date_output 變量名。第 2 個 task 對輸出進行分析,並使用 when 對關鍵字對分析后的進行判斷,如果匹配,則執行這個 task,不匹配就不執行。這里要重點說下的,因為 register 獲取到的輸出內容都是字符串,而 ansible 又是 python 寫的,你可以使用 python 字符串的方法對其做處理,比如本文中使用的 split,還可以使用 find 方法。個人覺得,真是非常靈活方便。
圖 3.register 執行結果 1

這里由於條件匹配,兩個 task 都執行了。然后把第 2 個 task 中的條件改動了下,使其不匹配,執行結果如下:
圖 4.register 執行結果 2

這里第 2 個 task 條件不匹配,skipping 了。
Delegate_to( 任務委派功能 )
場景介紹:在對一組服務器 server_group1 執行操作過程中,需要在另外一台機器 A 上執行一個操作,比如在 A 服務器上添加一條 hosts 記錄,這些操作必須要在一個 playbook 聯動完成。也就是是說 A 服務器這個操作與 server_group1 組上的服務器有依賴關系。Ansible 默認只會在定義好的一組服務器上執行相同的操作,這個特性對於執行批處理是非常有用的。但如果在這過程中需要同時對另外 1 台機器執行操作時,就需要用到 Ansible 的任務委派功能(delegate_to)。使用 delegate_to 關鍵字可以委派任務到指定的機器上運行。在 playbook 的操作如下:
- name: add host record
shell: 'echo "192.168.1.100 test.xyz.com" >> /etc/hosts' - name: add host record to center server shell: 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts' delegate_to: 192.168.1.1
任務委派功能還可以用於以下場景:
- 在部署之前將一個主機從一個負載均衡集群中刪除。
- 當你要對一個主機做改變之前去掉相應 dns 的記錄
- 當在一個存儲設備上創建 iscsi 卷的時候
- 當使用外的主機來檢測網絡出口是否正常的時候
本地操作功能 --local_action
Ansible 默認只會對控制機器執行操作,但如果在這個過程中需要在 Ansible 本機執行操作呢?細心的讀者可能已經想到了,可以使用 delegate_to( 任務委派 ) 功能呀。沒錯,是可以使用任務委派功能實現。不過除了任務委派之外,還可以使用另外一外功能實現,這就是 local_action 關鍵字。
- name: add host record to center server local_action: shell 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts'
當然您也可以使用 connection:local 方法,如下:
- name: add host record to center server shell: 'echo "192.168.1.100 test.xyz.com " >> /etc/hosts' connection: local
這兩個操作結果是一樣的。
Check 模式
當以— check 參數來運行 ansible-playbook 時,將不會對遠程的系統作出任何修改。相對的,任何帶有檢測功能的模塊只要支持‘檢測模式’將會報告它們會做出什么改變而不是直接進行改變。其他不支持檢測模式的模塊將即不響應也不提出相應的報告(事實上幾乎所有主要核心模塊都是支持‘檢測模式’)。檢測模式只是一種模擬。如果你的 playbook 是以先前命令的執行結果作為條件的話,那它可能作用就不明顯了。但是在正式運行前,使用 check 模式做個語法檢查也是不錯的。
選擇性執行 task-- Tag(標簽)
您可能因為某些原因,會創建一個很大型的 playbook,但是你可能只想想運行其中特定部分的配置而無需要運行整個 playbook 。那么這時你可能需要用到 tag 功能。示例如下:
- name: yun install package
yum: name={{ item }} state=installed with_items: - httpd - memcached tags: - packages - name: configuration modity template: src=templates/src.j2 dest=/etc/foo.conf tags: - configuration
如果你只想運行 playbook 中的”configuration”和”packages”,你可以這樣做
ansible-playbook example.yml – tags “configuration,packages”
如果你只想執行 playbook 中某個特定任務之外的所有任務,你可以這樣做:
ansible-playbook example.yml – skip-tags “configuration”
tag 特性是一個不錯的功能,但如果真的是要維護一個大型的 playbook,還是建議將 playbook 按功能或應用拆分成多個 playbook,然后再在主 playbook include 其他子 playbook,這樣即既利於維護也方便管理
錯誤處理
Ansible 默認會檢查命令和模塊的返回狀態,並進行相應的錯誤處理,默認是遇到錯誤就中斷 playbook 的執行,這些默認行為都是可以改變的。
忽略錯誤
command 和 shell 模塊執行的命令如果返回非零狀態碼則 ansible 判定這 2 個模塊執行失敗,可以通過 ignore_errors 忽略返回狀態碼(前提是要確定這 command 與 shell 執行錯誤不會影響后面 task 的執行)。如下:
- name: this will not be counted as a failure
command: /bin/false ignore_errors: yes
自定義錯誤判定條件
命令不依賴返回狀態碼來判定是否執行失敗,而是要查看命令返回內容來決定,比如返回內容中包括 failed 字符串,則判定為失敗。示例如下:
- name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr"
ansible 會自動判斷模塊執行狀態,command、shell 及其它模塊如果修改了遠程主機狀態則被判定為 change 狀態,不過也可以自己決定達到 changed 狀態的條件,示例如下:
- name: copy in nginx conf template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf - name: validate nginx conf shell: "/data/app/nginx/sbin/nginx -t" register: command_result changed_when: command_result.stdout.find('successful')
命令返回中有“successful”字符串,則為 changed 狀態,下面這個設定將永遠也不會達到 changed 狀態。
- name: validate nginx conf
shell: "/data/app/nginx/sbin/nginx -t" changed_when: false
結束語 .
本文介紹了一些關於 Ansible 的執行性能優化與 playbook 使用的技巧,這些都是在我們使用 Ansible 過程中需要面對的問題,希望今天列出的這些內容對大家學習和使用 Ansible 能有所幫助。