返回文章列表

Ansible進階任務委派與錯誤處理技巧

本文探討 Ansible 的進階主題:任務委派和錯誤處理,包含 `max_fail_percentage` 引數的運用、`delegate_to` 和 `local_action` 的使用,以及如何結合 `run_once` 選項最佳化 Playbook 流程,並示範如何透過 SSH Proxy 連線目標主機及在

DevOps 自動化

Ansible 自動化佈署中,處理錯誤與有效委派任務至關重要,特別是管理大型叢集時。max_fail_percentage 引數允許設定任務執行可容忍的錯誤比例上限,超過門檻則中止執行,確保佈署流程穩定性。任務委派功能則讓特定任務可在不同主機執行,例如在叢集升級時,利用 delegate_tolocal_action 將主機從負載平衡器移除或新增,提升操作靈活性。run_once 選項則確保特定任務在多個目標主機中僅執行一次,適用於資料函式庫升級等場景,避免重複操作。此外,Ansible 也支援透過 SSH Proxy 連線目標主機,以及在 Playbook 執行期間提示使用者輸入變數值,提升自動化流程的彈性與互動性。最後,Tags 功能讓使用者能選擇性執行特定任務,方便管理和除錯大型 Playbook。

進階 Ansible 主題:任務委派與錯誤處理

在前面的章節中,我們探討瞭如何使用 Ansible 進行自動化佈署和管理。在本章中,我們將探討兩個進階主題:任務委派(Task Delegation)和錯誤處理(Error Handling)。這兩個主題對於管理和維護大型叢集至關重要。

使用 max_fail_percentage 進行錯誤處理

在進行自動化佈署時,錯誤處理是一個重要的議題。Ansible 提供了 max_fail_percentage 引數,讓我們可以在任務執行過程中設定允許的最大錯誤比例。當錯誤比例超過設定的門檻時,Ansible 將會中止任務的執行。

以下是一個範例 playbook,展示瞭如何使用 max_fail_percentage

---
- name: 示範 max_fail_percentage
  hosts: frontends
  max_fail_percentage: 30
  serial: 5
  tasks:
  - name: 模擬任務失敗
    command: /bin/false
    ignore_errors: true
  - name: 第二個任務
    debug:
      msg: "如果第一個任務失敗,這個任務不會被執行"

在這個範例中,我們設定 max_fail_percentage 為 30%,並使用 serial 引數將主機分成批次執行。如果第一批次中的錯誤比例超過 30%,Ansible 將會中止任務的執行。

任務委派

在某些情況下,我們需要在不同的主機上執行特定的任務。例如,在進行叢集升級時,我們可能需要先將主機從負載平衡器中移除,進行升級後再將其增加回來。Ansible 的任務委派功能可以幫助我們實作這一點。

以下是一個範例 playbook,展示瞭如何使用任務委派:

---
- name: 示範任務委派
  hosts: frontends
  tasks:
  - name: 將主機從負載平衡器中移除
    command: ./remove_from_loadbalancer.sh {{ inventory_hostname }}
    args:
      chdir: "{{ playbook_dir }}"
    delegate_to: localhost
  - name: 佈署程式碼到主機
    debug:
      msg: "佈署程式碼的邏輯將在這裡執行"
  - name: 將主機增加回負載平衡器
    command: ./add_to_loadbalancer.sh {{ inventory_hostname }}
    args:
      chdir: "{{ playbook_dir }}"
    delegate_to: localhost

程式碼解析:

  1. delegate_to: localhost:這個指令告訴 Ansible 在本地主機(localhost)上執行指定的任務,而不是在清單中的遠端主機上執行。
  2. command 模組:用於執行 shell 指令碼,例如 remove_from_loadbalancer.shadd_to_loadbalancer.sh
  3. args:用於指定命令執行的引數和工作目錄。

在這個範例中,我們使用 delegate_to 引數將任務委派給本地主機執行。第一個和第三個任務分別將主機從負載平衡器中移除和增加回來,而第二個任務則在遠端主機上執行佈署程式碼的邏輯。

使用 local_action 簡化任務委派

Ansible 還提供了一個簡化的語法 local_action,可以用來替代 delegate_to: localhost。以下是一個範例:

---
- name: 第二個任務委派範例
  hosts: frontends
  tasks:
  - name: 從本地主機到清單主機的 rsync
    local_action: command rsync -a /tmp/ {{ inventory_hostname }}:/tmp/target/

程式碼解析:

  1. local_action:簡化了在本地主機上執行命令的語法,等同於使用 delegate_to: localhost
  2. rsync 命令:用於將本地檔案同步到遠端主機。

這個範例展示瞭如何使用 local_action 將本地檔案同步到遠端主機。

進階 Ansible 主題:任務委派與流程控制

在管理複雜的 IT 環境時,Ansible 提供了一系列進階功能來最佳化自動化流程。其中,任務委派(Task Delegation)和 run_once 選項是兩個非常實用的功能,能夠幫助我們更精確地控制 Playbook 的執行。

任務委派

任務委派允許我們在特定的主機上執行任務,而不是在 Playbook 預設的目標主機上。這在需要從特定主機執行某些操作時非常有用,例如從本地主機將檔案同步到遠端伺服器。

使用 local_action 進行任務委派

在 Ansible 中,我們可以使用 local_action 來指定在本地主機上執行的任務。以下是一個範例 Playbook,展示瞭如何使用 local_action 將本地目錄同步到遠端主機:

---
- name: 第二個任務委派範例
  hosts: frontends
  tasks:
    - name: 從本地主機到遠端主機執行 rsync
      local_action:
        module: rsync
        src: /path/to/local/directory/
        dest: /path/to/remote/directory/
        recursive: yes

執行此 Playbook 後,我們可以看到 rsync 命令確實是在本地主機上執行的,從而實作了將整個目錄樹複製到遠端伺服器的目的。

內容解密:

  1. local_action:用於指定在本地主機上執行的任務。
  2. module: rsync:指定要使用的模組為 rsync,用於檔案同步。
  3. srcdest:分別指定本地來源路徑和遠端目標路徑。
  4. recursive: yes:確保 rsync 命令遞迴複製整個目錄樹。

使用 run_once 選項

在叢集環境中,有時我們需要確保某些任務只執行一次。run_once 選項正是為此設計的。它允許我們在 Playbook 中指定某些任務只執行一次,無論有多少主機在目標清單中。

範例 Playbook

以下是一個簡單的 Playbook,展示瞭如何使用 run_once 選項:

---
- name: 示範 run_once 指令的 Playbook
  hosts: frontends
  tasks:
    - name: 升級資料函式庫結構
      debug:
        msg: 正在升級資料函式庫結構...
      run_once: true

執行此 Playbook 後,我們可以看到儘管 Playbook 是針對所有 10 個主機執行的,但升級任務只在其中一個主機上執行了一次。

內容解密:

  1. run_once: true:確保該任務只執行一次。
  2. debug 模組:用於輸出除錯資訊,在實際應用中可以替換為執行特定命令或指令碼的任務。

注意事項

使用 run_once 時需要注意,它是針對每個批次(batch)執行的。如果 Playbook 設定了 serial 引數(例如 serial: 5),那麼該任務將在每個批次中執行一次。因此,在設計 Playbook 時,需要考慮到這種行為可能帶來的影響。

進階Ansible主題:第八章

控制Playbook流程與本地執行

在管理複雜的IT基礎設施時,Ansible的run_once選項對於確保某些任務只在特定的主機上執行一次非常有用。這個功能特別適用於需要對多個主機執行一次性任務的場景,例如資料函式庫schema升級。

使用run_once控制任務執行

考慮以下Playbook範例:

---
- name: Upgrade database schema
  hosts: db_servers
  tasks:
    - name: Execute schema upgrade
      command: /path/to/upgrade/script.sh
      run_once: true

在這個例子中,即使db_servers組中包含多個主機,schema升級任務也只會在其中一台主機上執行一次。

執行結果如下:

frt10.example.com : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

值得注意的是,這種行為可能會導致意外的結果,例如上述輸出顯示schema升級執行了兩次。因此,在使用run_once時,需要仔細規劃Playbook的流程,以確保達到預期的結果。

本地執行Playbook與在localhost執行的區別

在使用Ansible時,瞭解在本地執行Playbook與在localhost執行Playbook之間的區別至關重要。當你在localhost上執行Playbook時,Ansible預設會透過SSH連線到localhost。

示範本地執行與SSH連線的差異

首先,建立一個包含以下內容的本地inventory檔案:

[local]
localhost

然後,嘗試使用ad hoc命令對這個inventory執行ping模組:

$ ansible -i localhosts -m ping all --ask-pass

這個命令會提示你接受localhost的SSH主機金鑰並輸入SSH密碼。成功連線後,你會看到類別似以下的輸出:

localhost | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

使用ansible_connection=local進行本地連線

為了避免使用SSH連線到localhost,你可以在inventory檔案中為localhost設定ansible_connection=local變數:

[local]
localhost ansible_connection=local

這樣,Ansible就會直接在本地執行命令,而不需要建立SSH連線。

驗證本地執行結果

你可以透過以下步驟驗證本地執行的結果:

  1. 檢查本地/tmp目錄下是否存在測試檔案:
    $ ls -l /tmp/foo
    ls: cannot access /tmp/foo: No such file or directory
    
  2. 使用Ansible ad hoc命令建立測試檔案:
    $ ansible -i localhosts2 -m file -a "path=/tmp/foo state=touch" all
    frt01.example.com | CHANGED => {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        },
        "changed": true,
        "dest": "/tmp/foo",
        "gid": 0,
        "group": "root",
        "mode": "0644",
        "owner": "root",
        "size": 0,
        "state": "file",
        "uid": 0
    }
    
  3. 再次檢查測試檔案是否存在:
    $ ls -l /tmp/foo
    -rw-r--r-- 1 root root 0 Apr 24 16:28 /tmp/foo
    

使用代理和跳板主機

在許多網路環境中,核心網路裝置可能只能透過代理或跳板主機存取。Ansible支援透過組態inventory檔案來實作透過跳板主機連線到目標主機。

考慮以下inventory組態:

[switches]
cmls01.example.com
cmls02.example.com

[switches:vars]
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q bastion.example.com"'

這裡,我們定義了一個名為switches的組,包含兩個Cumulus Networks交換機。然後,透過ansible_ssh_common_args變陣列態SSH連線,使其透過bastion.example.com跳板主機進行代理。

使用以下命令測試連線:

$ ansible -i switches -m ping all
cmls02.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
cmls01.example.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

進階Ansible主題:第八章

使用SSH Proxy進行連線

在某些情況下,我們可能需要透過一台跳板機(bastion host)來連線到目標主機。Ansible支援使用SSH Proxy來實作這一功能。首先,我們需要在ansible.cfg檔案中啟用ssh_args組態,並指定ProxyCommand。

[ssh_connection]
ssh_args = -o ProxyCommand="ssh -W %h:%p -q [email protected]"

在這個範例中,我們將跳板機設定為bastion.example.com,並透過它來連線到目標主機。

內容解密:

  1. ssh_args組態:此組態允許我們指定額外的SSH引數。在這裡,我們使用-o ProxyCommand來指定ProxyCommand。
  2. ProxyCommand引數:此引數指定了用於連線目標主機的命令。在這個例子中,我們使用ssh -W %h:%p -q [email protected]來連線到跳板機,並透過它來連線目標主機。
    • %h:代表目標主機的hostname。
    • %p:代表目標主機的port。
    • -q:代表quiet模式,減少輸出資訊。

這樣,當我們執行Ansible playbook時,它會自動透過跳板機連線到目標主機,而不需要我們手動進行任何額外的組態。

在Playbook執行期間提示使用者輸入

有時候,我們希望在執行playbook的過程中能夠根據使用者的輸入來決定某些變數的值。Ansible提供了vars_prompt模組來實作這一功能。

範例Playbook

---
- name: 簡單的playbook範例,示範如何在playbook中提示使用者輸入
  hosts: frontends
  vars_prompt:
    - name: loginid
      prompt: "請輸入您的使用者名稱"
      private: no
    - name: password
      prompt: "請輸入您的密碼"
      private: yes
  tasks:
    - name: 登入操作
      debug:
        msg: "正在以 {{ loginid }} 身份登入..."

內容解密:

  1. vars_prompt部分:定義了兩個變數loginidpassword,並在執行playbook時提示使用者輸入。
    • private: no:表示使用者輸入的內容會被顯示在終端上。
    • private: yes:表示使用者輸入的內容不會被顯示在終端上,通常用於輸入密碼等敏感資訊。
  2. debug任務:使用debug模組輸出一個訊息,訊息中包含了使用者輸入的loginid變數的值。

執行這個playbook時,Ansible會提示使用者輸入使用者名稱和密碼,並將輸入的值儲存在對應的變數中,然後在後續的任務中使用這些變數。

使用Tags選擇性地執行任務

隨著playbook規模的增長,我們可能希望能夠選擇性地執行某些任務,而不是每次都執行整個playbook。Ansible的tags功能可以幫助我們實作這一需求。

範例Playbook

---
- name: 簡單的playbook範例,示範如何使用tags
  hosts: frontends
  tasks:
    - name: 安裝nginx
      yum:
        name: nginx
        state: present
      tags:
        - install
    - name: 從範本佈署nginx組態檔案
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx.conf
      tags:
        - customize

內容解密:

  1. tags關鍵字:用於為任務指定標籤。在這個例子中,第一個任務被標記為install,第二個任務被標記為customize
  2. --tags--skip-tags選項:執行playbook時,可以使用這些選項來指定要執行或跳過哪些標籤對應的任務。
    • --tags install:只執行標記為install的任務。
    • --skip-tags customize:執行除了標記為customize之外的所有任務。

透過使用tags,我們可以靈活地控制playbook中任務的執行,從而提高自動化管理的效率和靈活性。