網站搜尋

Ansible 劇本中的錯誤處理


在本文中,我們將專注於其中一個重要的 Ansible 主題 - "Ansible 劇本中的錯誤處理"。讀完本文後,你應該對 Ansible 錯誤處理 以及如何在 Linux 中 運行 Ansible 劇本時處理不同的錯誤 有相當的了解。

劇本中的錯誤處理

任何軟體在使用過程中都很常出現錯誤和漏洞。Ansible 也不例外。當你開始在現實世界的專案中使用 Ansible 時,你會面臨各種各樣的錯誤,無論是產品漏洞還是人為錯誤。

有些錯誤可以通過實施最佳實踐以及使用具有程式碼檢查和除錯功能的工具來避免。在這種情況下,我的建議是使用 vscode,它擁有出色的插件生態系統來支持 Ansible 開發。

看看以下 Visual Studio Code 擴充套件,它們可以通過強制一些規則和檢測基本語法錯誤來幫助你實施最佳實踐。

  • https://github.com/adrienverge/yamllint
  • https://marketplace.visualstudio.com/items?itemName=redhat.ansible

以下是一個來自 VSCode Ansible Linter 的範例圖片。

範例 Ansible Linter 輸出

現在讓我們來討論幾個情境,以了解不同類型的失敗以及如何處理它們。

如何處理 Ansible 中的語法錯誤

在執行任何劇本之前,你首先需要檢查的是語法錯誤。你可以使用 "--syntax-check" 參數與 ansible-playbook 命令一起檢查語法錯誤。

看看下面的劇本。我有兩個問題。關鍵字 role 不是有效的關鍵字,應該是 "roles"。第二個問題是這兩個角色都不是有效的角色。

---
- name: Handle Failure
  hosts: localhost

  role:
   - sample-role1
   - sample-role2

當我使用 --syntax-check 執行劇本時,它會發現劇本中的第一個錯誤。

$ ansible-playbook --syntax-check playbook.yml

Ansible 語法錯誤 1

一旦我修正錯誤並重新提交劇本,它會顯示下一個錯誤,即在 roles_path 位置找不到 sample-role1。

Ansible 語法錯誤 2

這種方法的問題是,當你的劇本中有幾個錯誤時,它只會顯示第一個錯誤,你必須修正錯誤後重新提交命令才能看到下一個錯誤。

如何處理 Ansible 中的任務失敗

在了解如何修復失敗的任務之前,你應該先了解 Ansible 如何提交任務以及當任務失敗時會發生什麼。

Ansible 以定義的順序批次提交任務(forks=5)。當某個任務在一個主機上失敗時,Ansible 將標記該主機並停止在該主機上運行後續任務。

你可以使用以下任何方法來處理任務層級的失敗。

  • 使用 ignore_errors 指令。
  • 將任務分組到區塊指令下。

1. 使用 Ignore_errors 指令處理失敗

請考慮以下這個劇本,它有兩個任務,用於下載和安裝 Chrome 的 deb 軟件包。

---
- name: Handle Failure with ignore_erros
 hosts: localhost

 tasks:
   - name: Download chrome .deb file
     ansible.builtin.get_url:
       url: https://dl.google.com/linux/direct/google-chrome-stable_current_amd641.deb
       dest: /tmp/chrome.deb

   - name: Install from /tmp/chrome.deb
     ansible.builtin.apt:
       deb: /tmp/chrome.deb

我故意給了錯誤的 URL,這會導致第一個任務失敗。如前所述,一旦主機中的任務失敗,主機將不會提交後續任務。所以第二個任務沒有被提交。

fatal: [localhost]: FAILED! => {"changed": false, "dest": "/tmp/chrome.deb", "elapsed": 0, "msg": "Request failed", "response": "HTTP Error 404: Not Found", "status_code": 404, "url": "https://dl.google.com/linux/direct/google-chrome-stable_current_amd641.deb"}

現在讓我再跑一次同一個劇本,但這次是「ignore_errors= true」。

Ansible 忽略錯誤

如果你看上面的圖片,第一個任務運行並失敗了,但失敗被忽略了,這使得第二個任務得以運行。

注意: ignore_errors 指令可以在任務層級或劇本層級添加。

2. 使用 Block-Rescue-Always 指令的錯誤處理

有時候,一組任務之間互相依賴,如果單個任務失敗,則僅依賴的任務不應執行,而不是停止特定主機下的所有任務。

前一節使用的劇本將是這種情況的完美範例。安裝任務依賴於下載任務,因此這兩個任務可以被歸類在 block 指令下。

---
- name: Handle Failure with ignore_erros
  hosts: localhost

  tasks:
   - name: Group the tasks
     block:
       - name: Download chrome .deb file
         ansible.builtin.get_url:
           url: https://dl.google.com/linux/direct/google-chrome-stable_current_amd641.deb
           dest: /tmp/chrome.deb

       - name: Install from /tmp/chrome.deb
         ansible.builtin.apt:
           deb: /tmp/chrome.deb
     ignore_errors: true

我使用了相同的劇本,但將兩個任務都移到了 block 指令下,並在 block 層級添加了 ignore_errors。如果你看下面的輸出,兩個任務都自動繼承了 ignore_errors 指令。

在區塊級忽略錯誤

您也可以在 "block" 指令中加入 "rescue" 和 "always" 指令。如果 block 指令下的任何任務失敗,rescue 指令下的任務將會執行。這對清理活動非常有用。always 指令會無論 block 和 rescue 指令的狀態如何都執行。

我已經新增了帶有輸出一些訊息任務的 rescue 和 always 指令。

tasks:
   - name: Group the tasks
     block:
       - name: Download chrome .deb file
         ansible.builtin.get_url:
           url: https://dl.google.com/linux/direct/google-chrome-stable_current_amd641.deb
           dest: /tmp/chrome.deb

       - name: Install from /tmp/chrome.deb
         ansible.builtin.apt:
           deb: /tmp/chrome.deb
     rescue:
       - name: Rescue task
         ansible.builtin.debug:
           msg: "Some cleanup activity..."
     always:
       - name: Task that always runs
         ansible.builtin.debug:
           msg: "Task that always run"  

rescue 任務運行是因為區塊部分的任務失敗了。最後,always 任務運行了。

救援與始終指令輸出

如何在失敗時停止所有播放

在上一節中,我們已經看到即使任務失敗,也可以執行任務的方法。在某些情況下,即使單個任務失敗,我們也需要整個劇本停止。這可以通過設置 "any_errors_fatal: true" 來實現。

停止因任何失敗而執行劇本

當劇本以「any_errors_fatal」提交時,如果某個任務失敗,當前批次中提交的任務將會執行,而劇本將會停止。

注意: 指令 any_errors_fatal 可以在 play 層級或 task 層級設定。

如何處理 Ansible 中的無法訪問主機錯誤

在 ansible 中的另一種類型的錯誤是 "unreachable host"。當 ansible 無法連接到在清單檔案中定義的管理主機時,您會收到此錯誤。這可能有很多原因。要麼您可能給了錯誤的主機定義,要麼管理主機存在問題。

如果 Ansible 發現某個節點無法連接,它將會將該節點從活動主機列表中移除,並且不會在該節點上提交任何其他任務。

我正在運行與上一部分相同的劇本,但使用了一個隨機主機名。該任務以 "unreachable" 失敗。

Ansible 無法連線的主機

你可以在任務或劇本層級添加「ignore_unreachable: true」,這將跳過當前任務並執行下一個任務,而不會將主機從活動列表中移除。

Ansible 忽略無法到達的主機

如何在 Ansible 中建立使用者定義的失敗

除了 Ansible 定義的失敗外,用戶還可以使用 "failed_when" 指令創建自己的規則來使任務失敗。事實上,Ansible Linter 建議使用 failed_when 而不是 ignore_errors 指令。

程式檢查器輸出

在進行一些條件檢查之前,您需要先註冊任務的輸出。註冊的變量名稱是 "status"。

要了解更多關於 Ansible 註冊的資訊,請參考以下指南。

  • Ansible 註冊變數

我已經新增了一個條件來檢查已註冊輸出的狀態碼。404 狀態碼將不被視為失敗。現在,任何其他返回碼都將被視為失敗。

- name: Download chrome .deb file
 ansible.builtin.get_url:
   url: https://dl.google.com/linux/direct/google-chrome-stable_current_amd641.deb
   dest: /tmp/chrome.deb
 register: status
 failed_when: status.status_code != 404

Ansible 中的條件失敗

您也可以加入 "AND" 和 "OR" 運算子來檢查多個條件。

failed_when: status.status_code != 404 or status.status_code != 401

如何處理 Ansible 中的處理程序任務失敗

我們有一篇專門給處理器的文章。請參考以下連結,並留意「處理失敗」部分,以了解如何處理處理器任務中的失敗。

  • 如何在 Ansible 劇本中使用處理程序

結論

在本文中,我們討論了在 Playbooks 中的錯誤處理。我們還了解了在 Ansible 中可能遇到的不同類型的失敗,以及一些解決方法。歡迎通過評論區提供反饋。

資源:

  • 劇本中的錯誤處理