測試策略

Ansible Playbooks 的整合測試

很多時候, 人們問, “我怎樣才能最好的將 Ansible playbooks 和測試結合在一起?” 這有很多選擇. Ansible 的設計實際上是一個”fail-fast”有序系統, 因此它可以很容易地嵌入到 Ansible playbooks. 在這一章節, 我們將討論基礎設施的整合測試及合適的測試等級.

Note

這是一個關於測試你部署應用程式的章節, 不是如何測試開發的 Ansible 模組. 對於那些內容, 請移步開發區域.

通過將某種程度的測試部署合併到部署工作流中, 當代碼執行在生產環境中這將減少意外的產生, 在許多情況下, 測試可以避免在生產中因為更新失敗而導致的遷移整個安裝. 因為它是基於推送的, 它可以很容易的執行在 localhost 或者測試伺服器上. Ansible 允許你新增儘可能多的檢查在你的升級流程中.

正確的測試等級

Ansible 資源是期望狀態的模組. 因此測試服務是否處於執行, 包是否已經安裝, 或其他這樣的事情它不是必要的. Ansible 確保這些系統中的這些聲明是真實的. 相反, 在你的 playbooks 中 assert 這些事情.

tasks:
  - service: name=foo state=started enabled=yes

如果你認為該服務可能沒有啟動, 最好的事情就是要求它處於啟動狀態. 如果這個服務啟動失敗, Ansible 將適當的拋出. (這不應該和服務是否正在做一些功能性的事情混淆, 而我們應該更多的展示如何做這些事).

Check 模組作為主要測試

在上面的設定中, –check 模組在 Ansible 中可以作為一層測試. 如果在一個現有的系統部署 playbook, 使用 –check 選項 ansible 命令將會報告出 Ansible 使系統進入一個期望狀態所做的任何更改.

這可以讓你知道前面任何需要不如到給定系統的資訊. 一般的指令碼和命令不執行在檢查模式, 所以如果你想要某些步驟總是在檢查模式下執行, 例如呼叫 script 模組, 新增 ‘always_run’ 標記:

roles:
  - webserver

tasks:
  - script: verify.sh
    always_run: True

用於測試的模組

某些 playbook 模組對於測試特別友好. 下面的例子保證埠處於開啟狀態:

tasks:

  - wait_for: host={{ inventory_hostname }} port=22
    delegate_to: localhost

這是使用 URI 模組來確保 web service 有正確的返回:

tasks:

  - action: uri url=http://www.example.com return_content=yes
    register: webpage

  - fail: msg='service is not happy'
    when: "'AWESOME' not in webpage.content"

可以很容易的將任意(語言)的指令碼推送到遠端主機上, 如果這個指令碼有一個非零的返回碼, 它將自動失效:

tasks:

  - script: test_script1
  - script: test_script2 --parameter value --parameter2 value

如果使用 roles(你應該這樣做, roles 是偉大的!), 指令碼模組可以推送 role 下的 ‘files/’ 目錄下的指令碼

新增 assert 模組, 它可以很容易的驗證各種真理:

tasks:

   - shell: /usr/bin/some-command --parameter value
     register: cmd_result

   - assert:
       that:
         - "'not ready' not in cmd_result.stderr"
         - "'gizmo enabled' in cmd_result.stdout"

如果你覺得需要測試通過 Ansible 設定的檔案是否存在, ‘stat’ 模組是一個不錯的選擇:

tasks:

   - stat: path=/path/to/something
     register: p

   - assert:
       that:
         - p.stat.exists and p.stat.isdir

如上所處, 哪些沒必要檢查的東西如命令的返回碼. Ansible 自動檢查它們. 如果檢查使用者存在, 考慮使用 user 模組使其存在.

Ansible 是一個 fail-fast 系統, 所以當建立使用者失敗, 它將停止 playbook 的執行. 你不必檢查它背後的原因.

測試的生命週期

如果將你的應用程式的基本驗證寫入了你的 playbooks 中, 在你每次部署的適合他們都將執行.

因此部署到本地開發的虛擬機器和臨時的環境都將根據你的生產環境的部署計劃來驗證這一切.

你的工作流可能是這樣:

- 使用相同的 playbook 在開發過程中嵌入測試
- 使用 playbook 部署一個臨時環境(使用相同的playbooks)來模擬生產
- 執行一個由 QA 團建編寫的整合測試用例
- 使用相同的總和測試部署到生產.

如果你是一個產品服務, 一些像整合測試系列需要通過你的 QA 團隊來編寫. 這將包含諸如測試用例或自動化 API 測試, 這些通常不是嵌入到 Ansible 的 playbooks 中的.

然而, 它包含基本的健康的檢查使 playbooks 有意義, 而且在某些情況下它可能會相對於遠端節點執行一些 QA 的子集合. 這是下一節所涵蓋的內容.

結合滾動更新測試

如果你已經讀到 委託,滾動更新,本地動作 滾動更新的擴充套件好處可以迅速變得明顯, 你可以使用 playbook 執行的成功或失敗來決定是否增加機器到負載均衡器中.

這是嵌入測試的顯著結果:

---

- hosts: webservers
  serial: 5

  pre_tasks:

    - name: take out of load balancer pool
      command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

  roles:

     - common
     - webserver
     - apply_testing_checks

  post_tasks:

    - name: add back to load balancer pool
      command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

在上述過程中, “task out of the pool” 和 “add back” 的步驟將會代替 Ansible 呼叫負載均衡模組或對應的 shell 命令. 您還可以使用監控模組對機器進行建立和關閉中斷的視窗.

然而, 你可以從上面看出測試作為入口 – 如果”apply_testing_checks”這一步不執行, 這個機器將不會被新增到池中.

閱讀關於”max_fail_percentage”的代表章節, 你可以控制有多少失敗的測試後停止程式的滾動更新.

這種方式也可以被修改為先在測試機器上執行測試步驟然後在遠端機器執行測試的步驟:

---

- hosts: webservers
  serial: 5

  pre_tasks:

    - name: take out of load balancer pool
      command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

  roles:

     - common
     - webserver

  tasks:
     - script: /srv/qa_team/app_testing_script.sh --server {{ inventory_hostname }}
       delegate_to: testing_server

  post_tasks:

    - name: add back to load balancer pool
      command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1

在上面的例子中, 從測試伺服器上執行一個指令碼緊接著將一個遠端的節點新增到 pool 中.

在出現問題時, 解決一些伺服器不能使用 Ansible 自動生成的重試檔案重複部署這些伺服器.

實現連續部署

如果需要, 上述技術可以擴充套件到啟用連續部署中.

這個工作流可能像這樣:

- 編寫和使用自動部署本地開發虛擬機器
- 有一個 CI 系統像 Jenkins, 來將每一次的程式碼變更部署到臨時環境中
- 這個部署任務呼叫測試指令碼, 參考通過/失敗來確定每一次的部署是否進行 build
- 如果部署任務成功, 它將在生產環境中執行相同的部署 playbook

一些 Ansible 使用者使用上述方式, 在一個小時內多次部署使它們所有的基礎設施不下線. 如果你想達到那種水平, 一個自動 QA 系統是至關重要的.

如果你仍然在大量使用人工 QA, 你仍然需要決定手動部署是否是最好的, 但它仍然可以幫助滾動更新前的一部分工作, 包括基本的健康檢查使用模組 ‘script’, ‘stat’, ‘uri’, 和 ‘assert’.

結尾

Ansible 相信你應該不需要另一個框架來驗證你的基礎設施是正確的. 這種情況是因為 Ansible 是基於順序的系統, 處理失敗後將立即在主機上引發錯誤, 並阻止該主機進一步的配置. 這迫使 Ansible 在執行結束後將錯誤作為摘要顯示在頂端.

然而, Ansible 作為一個多層編排系統, 它可以很輕鬆的將測試合併到 playbook 中執行完畢, 使用 tasks 或 roles. 當使用滾動更新時, 測試步驟可以決定是否要把一臺伺服器新增到負載均衡池中.

最後, 因為 Ansible 錯誤會通過所有的方式進行傳播以及 Ansible 程式本身的返回碼, Ansible 預設執行在一個簡單的推送模式, 如果你想使用它作為部署系統, 持續整合/持續交付道路上的組成部分, Ansible 是作為構建環境的最好的階段, 如上面部分的介紹.

重點不應該放在基礎設施測試上, 而是在應用程式的測試, 所以我們強烈鼓勵你和你的 QA 團隊商量出對於每一次部署的開發虛擬機器什麼樣的測試是有意義的, 並將他們希望對每個部署的臨時環境的測試進行排序. Ansible 描述了資源應該所處的狀態, 所以你不需要考慮這些. 如果存在你需要確定的東西, 使用 stat/assert 這些偉大的模組來實現你的目的, 這將是最棒的.

總之, 測試是一個組織非常明確的事情. 每一個人都應該這樣做, 但是這些要根據你要部署什麼以及誰在使用它們來確定最適合的方案 – 但每個人肯定都會從一個更加強大和可靠的部署系統中受益.

See also

模組相關
All the documentation for Ansible modules
Playbooks
An introduction to playbooks
委託,滾動更新,本地動作
Delegation, useful for working with loud balancers, clouds, and locally executed steps.
User Mailing List
Have a question? Stop by the google group!
irc.freenode.net
#ansible IRC chat channel