Ansible 在自動化佈署中扮演著關鍵角色,其測試和變數管理能力更是確保 Playbook 穩定執行的根本。本文從 debug 模組的應用開始,逐步介紹如何利用 facts 收集主機資訊,並示範如何設定和使用自定義 facts,特別是利用 ec2_facts 模組取得 AWS EC2 例項資訊。此外,文章還深入講解 Ansible-lint 的使用,包含安裝、自定義規則的建立與組態,以及結合 --start-at-task--step--list-tasks--check 等選項進行 Playbook 的測試和除錯,最後也提供處理檢查模式下錯誤的解決方案,以確保 Playbook 在各種情境下的正確執行。

Ansible 測試與變數

在前面的章節中,我們已經學習瞭如何使用 Ansible 佈署 CloudFormation 堆積疊。在本章節中,我們將探討 Ansible 的測試和變數。

使用 Debug 模組

在之前的範例中,我們使用了 debug 模組來輸出變數的值。下面是一個範例,展示瞭如何使用 debug 模組來輸出 production_splunk_stack 變數的值:

- debug:
    var: production_splunk_stack
    verbosity: 2

- debug:
    msg: "IP Address Value {{ production_splunk_stack.stack_outputs.PublicIP }}"

在這個範例中,第一個 debug 模組輸出了 production_splunk_stack 變數的值,但是隻有在使用 -vv 選項執行 playbook 時才會顯示。第二個 debug 模組輸出了 production_splunk_stack.stack_outputs.PublicIP 的值。

程式碼解密:

  1. debug 模組:用於輸出變數的值或自定義訊息。
  2. var 引數:指定要輸出的變數名稱。
  3. verbosity 引數:控制輸出詳細程度,值越大輸出的資訊越詳細。
  4. msg 引數:用於輸出自定義訊息,可以包含變數。

Ansible Facts

當我們執行 playbook 時,Ansible 會預設收集目標主機的 facts。這些 facts 包含了主機的硬體資訊、作業系統資訊、網路資訊等。

使用 Setup 模組收集 Facts

我們可以使用 setup 模組來收集目標主機的 facts。下面是一個範例:

ansible all -i "ec2-user@52.65.207.29," -m setup --key-file "splunkserver.pem"

這個命令會輸出目標主機的所有 facts。

篩選 Facts

我們可以使用 filter 引數來篩選 facts。下面是一個範例:

ansible all -i "ec2-user@52.65.207.29," -m setup --key-file "splunkserver.pem" -a "filter=ansible_processor_vcpus"

這個命令只會輸出 ansible_processor_vcpus 的值。

程式碼解密:

  1. setup 模組:用於收集目標主機的 facts。
  2. filter 引數:用於篩選 facts。
  3. ansible_processor_vcpus:表示目標主機的 CPU 虛擬核心數量。

重點整理

  • 使用 debug 模組輸出變數的值。
  • 使用 setup 模組收集目標主機的 facts。
  • 使用 filter 引數篩選 facts。

在未來的章節中,我們將繼續探討 Ansible 的其他功能,例如條件陳述式和迴圈陳述式,以進一步提升我們的自動化能力。

使用 Ansible 管理事實與變數的最佳實踐

在前面的章節中,我們已經瞭解如何使用 Ansible 收集主機的事實(facts)。現在,我們將探討如何利用這些事實以及自定義變數來提升我們的自動化管理能力。

利用 ec2_facts 模組收集 AWS EC2 例項資訊

Ansible 提供了 ec2_facts 模組,專門用於從 AWS EC2 例項中提取相關資訊。以下命令示範瞭如何使用此模組:

ansible all -i "ec2-user@52.65.207.29," -m ec2_facts --key-file "splunkserver.pem"

內容解密:

  1. ansible all:對所有主機執行命令。
  2. -i "ec2-user@52.65.207.29,":指定連線主機的清單。
  3. -m ec2_facts:使用 ec2_facts 模組來收集 EC2 例項的事實。
  4. --key-file "splunkserver.pem":指定用於連線 EC2 例項的私鑰檔案。

執行結果將傳回包含 EC2 例項特定資訊的 JSON 物件,例如 ansible_ec2_ami_idansible_ec2_ami_launch_index

在 Playbook 中設定自定義事實

在某些情況下,我們需要在 Playbook 中設定自定義的事實,以便在不同的 Playbook 之間共用變數。以下是如何在 roles/splunk_cloud/tasks/main.yml 檔案中設定自定義事實的範例:

- name: set public IP address to be used by other playbooks
  set_fact:
    splunk_public_ip: "{{ production_splunk_stack.stack_outputs.PublicIP }}"

內容解密:

  1. set_fact:Ansible 模組,用於設定自定義事實。
  2. splunk_public_ip:自定義的事實名稱。
  3. "{{ production_splunk_stack.stack_outputs.PublicIP }}":從 CloudFormation 堆積疊輸出中取得的公網 IP 地址。

這樣設定後,splunk_public_ip 事實就可以在其他 Playbook 中被參照。

在其他 Playbook 中使用自定義事實

我們可以在其他 Playbook 中使用之前設定的自定義事實,如下所示:

tasks:
  - debug:
      msg: "Production Server Public IP Address {{ splunk_public_ip }}"

內容解密:

  1. debug:Ansible 模組,用於輸出除錯資訊。
  2. msg:輸出的訊息內容。
  3. {{ splunk_public_ip }}:參照之前設定的自定義事實。

執行此 Playbook 將輸出之前設定的公網 IP 地址。

Ansible 測試與開發最佳實踐

隨著 Ansible Playbook 的複雜度增加,我們需要像對待其他程式碼一樣對其進行測試,以確保其正確性和穩定性。以下是一些有用的測試和開發技巧:

使用 --start-at-task 選項

此選項允許您從特定的任務開始執行 Playbook,而無需執行之前的任務。例如:

ansible-playbook -i hosts cloudformation_deploy.yml --start-at-task="Final Task"

內容解密:

  1. --start-at-task:指定從哪個任務開始執行。
  2. "Final Task":任務名稱。

這樣可以方便地測試新新增的任務。

使用 --step 選項

此選項允許您以互動方式執行 Playbook,在每個任務執行前都會提示您是否繼續。例如:

ansible-playbook -i hosts cloudformation_deploy.yml --step

內容解密:

  1. --step:啟用互動式執行模式。

此模式非常適合用於除錯和測試複雜的 Playbook。

透過這些技巧和方法,我們可以更好地管理和測試我們的 Ansible Playbook,從而提升自動化管理的效率和可靠性。

Ansible 測試與變數管理:使用 Ansible-Lint 確保 Playbook 品質

在 Ansible 自動化佈署過程中,確保 Playbook 的正確性和穩定性至關重要。Ansible-Lint 是一個強大的工具,能夠幫助開發者檢查 Playbook 中的語法錯誤、格式問題以及最佳實踐遵從性。本文將探討如何使用 Ansible-Lint 來提升 Ansible Playbook 的品質。

安裝與驗證 Ansible-Lint

首先,我們需要在系統中安裝 Ansible-Lint。對於根據 Debian 的 Linux 發行版,可以使用以下命令進行安裝:

sudo apt install ansible-lint

若系統未包含 apt 套件管理工具,也可透過 pip3 安裝:

pip3 install ansible-lint

安裝完成後,執行以下命令驗證安裝版本:

ansible-lint --version

輸出結果應顯示已安裝的 Ansible-Lint 版本,例如:

ansible-lint 4.2.0

內容解密:

  1. sudo apt install ansible-lint:使用 apt 套件管理器安裝 Ansible-Lint,需管理員許可權。
  2. pip3 install ansible-lint:透過 Python 的 pip3 工具安裝 Ansible-Lint,適用於多種作業系統環境。
  3. ansible-lint --version:檢查已安裝的 Ansible-Lint 版本,確認安裝正確性。

使用 Ansible-Lint 檢查 Playbook

安裝完成後,我們可以使用 Ansible-Lint 對現有的 Playbook 進行檢查。例如,使用以下命令檢查 server_deploy.yml Playbook:

ansible-lint server_deploy.yml -v

執行結果會顯示檢查的詳細資訊,包括檢查的檔案型別和路徑:

Examining server_deploy.yml of type playbook
Examining chapter7/roles/splunk_server/tasks/main.yml of type tasks
Examining chapter7/roles/splunk_server/handlers/main.yml of type handlers
Examining chapter7/roles/splunk_server/meta/main.yml of type meta

若 Playbook 中存在問題,Ansible-Lint 會輸出相關錯誤或警告資訊,例如:

[ANSIBLE0002] Trailing whitespace
chapter7/roles/splunk_server/tasks/main.yml:38
wait: true

內容解密:

  1. ansible-lint server_deploy.yml -v:對 server_deploy.yml 執行 Ansible-Lint 檢查,並顯示詳細資訊。
  2. Examining 開頭的輸出:列出檢查涉及的檔案及其型別,包括 Playbook、任務、處理程式和後設資料檔案。
  3. [ANSIBLE0002] Trailing whitespace:指出 main.yml 第 38 行存在多餘的空白字元,需要修正。

自定義 Ansible-Lint 規則

除了預設規則,Ansible-Lint 還支援自定義規則。以下示範如何建立一個檢查程式碼行長度的自定義規則。

  1. 建立規則目錄

    mkdir test_rules
    
  2. 建立自定義規則檔案

    touch test_rules/LineLength.py
    
  3. 編寫自定義規則

    LineLength.py 中新增以下 Python 程式碼:

    from ansiblelint import AnsibleLintRule
    
    class LineLength(AnsibleLintRule):
        id = 'ANSWERS01'
        shortdesc = 'Line too long'
        description = 'Python Code Style Guidelines Recommend Line Length Under 80 Characters'
        tags = ['formatting']
    
        def match(self, file, line):
            if len(line) > 80:
                self.shortdesc += " ({} characters)".format(len(line))
                return True
            return False
    
  4. 執行自定義規則檢查

    ansible-lint server_deploy.yml -r test_rules
    

    結果會顯示超過 80 個字元的行,例如:

    [ANSWERS01] Line too long (96 characters)
    

/home/vince/Projects/ansible-work/chapter7/roles/splunk_server/meta/main.yml:21

If this a Container Enabled role, provide the minimum Ansible Container version.


#### 內容解密:
1. **`mkdir test_rules`**:建立存放自定義規則的目錄。
2. **`class LineLength(AnsibleLintRule)`**:定義一個新的規則類別,繼承自 `AnsibleLintRule`。
3. **`def match(self, file, line)`**:實作檢查邏輯,若某行超過 80 個字元則傳回 `True`,觸發警告。
4. **`ansible-lint server_deploy.yml -r test_rules`**:執行檢查並套用 `test_rules` 目錄中的自定義規則。

### 組態 Ansible-Lint

Ansible-Lint 支援透過組態檔案進行靈活的規則管理和排除特定路徑的檢查。例如,建立 `test_config.yml` 組態檔案:

```yaml
---
exclude_paths:
- roles/
parseable: true
quiet: true
rulesdir:
- test_rules/
use_default_rules: true
verbosity: 1

執行時指定該組態檔案:

ansible-lint server_deploy.yml -c test_config.yml

這樣可以排除 roles/ 目錄下的檢查,並套用自定義規則。

內容解密:

  1. exclude_paths:指定檢查時排除的路徑,如 roles/ 目錄。
  2. rulesdir:指定自定義規則所在的目錄。
  3. use_default_rules: true:同時使用預設規則和自定義規則進行檢查。

此圖示呈現了Ansible-Lint在自動化佈署中的角色與功能

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Ansible自動化佈署測試與變數管理

package "Ansible 架構" {
    component [Control Node] as control

    package "Ansible 組件" {
        component [Inventory] as inventory
        component [Playbooks] as playbooks
        component [Roles] as roles
        component [Modules] as modules
    }

    package "Managed Nodes" {
        component [Web Server] as web
        component [DB Server] as db
        component [App Server] as app
    }
}

control --> inventory : 主機清單
control --> playbooks : 任務定義
playbooks --> roles : 引用角色
roles --> modules : 使用模組
control --> web : SSH 連線
control --> db : SSH 連線
control --> app : SSH 連線

note right of control
  無需在目標主機安裝 Agent
  透過 SSH 執行任務
end note

@enduml

Ansible 測試與變數管理

在前面的章節中,我們已經瞭解瞭如何使用 Ansible 來佈署和管理伺服器。在本章節中,我們將探討如何使用 Ansible 進行測試和變數管理,以確保我們的 playbook 更加穩健和可靠。

自定義 Ansible-lint 規則

Ansible-lint 是一個非常有用的工具,可以幫助我們檢查 playbook 中的錯誤和最佳實踐。除了預設的規則之外,我們還可以建立自定義規則來滿足特定的需求。

建立新的測試規則

首先,我們需要建立一個新的測試規則。我們可以透過執行以下命令來建立一個新的檔案:

touch test_rules/AWSCredentials.py

接下來,我們需要在這個檔案中新增一些程式碼。以下是一個簡單的例子:

from ansiblelint import AnsibleLintRule

class AWSCredentials(AnsibleLintRule):
    id = 'ANSWERS02'
    shortdesc = 'Playbook 可能包含 AWS 憑證'
    description = 'AWS 憑證不應該包含在變數中,尤其是當它們被公開儲存時'
    tags = ['formatting']

    def match(self, file, line):
        if "aws_access_key_id" in line:
            return True
        if "aws_secret_access_key" in line:
            return True
        return False

程式碼解密:

  1. from ansiblelint import AnsibleLintRule:匯入 AnsibleLintRule 類別,這是建立自定義規則的基礎。
  2. class AWSCredentials(AnsibleLintRule):定義一個新的類別 AWSCredentials,繼承自 AnsibleLintRule。
  3. idshortdescdescriptiontags:這些屬性定義了規則的後設資料,包括 ID、簡短描述、詳細描述和標籤。
  4. def match(self, file, line):這個方法用於檢查 playbook 中的每一行,看看是否包含 AWS 憑證。
  5. if "aws_access_key_id" in lineif "aws_secret_access_key" in line:檢查目前行是否包含 AWS 存取金鑰 ID 或 AWS 私密存取金鑰。如果包含,則傳回 True,表示觸發了規則。

測試自定義規則

為了測試我們的自定義規則,我們需要在 server_deploy.yml 檔案中新增一些內容。以下是一個簡單的例子:

var:
  aws_secret_access_key: AKIAJL123456789qazw

接下來,我們可以執行以下命令來測試我們的自定義規則:

ansible-lint server_deploy.yml -r test_rules/

如果一切正常,我們應該會看到一個錯誤訊息,指出我們的 playbook 中包含了 AWS 私密存取金鑰。

使用 --list-tasks 選項

Ansible 提供了一個非常有用的選項 --list-tasks,可以用來列出 playbook 中的所有任務。以下是一個簡單的例子:

ansible-playbook -i hosts server_deploy.yml --list-tasks --ask-vault-pass

這個命令會列出 playbook 中的所有任務,包括任務名稱和標籤。

使用 --check 選項

Ansible 的 --check 選項可以用來檢查 playbook 中的任務是否正確,而不需要實際執行它們。以下是一個簡單的例子:

ansible-playbook -i hosts server_deploy.yml --check --ask-vault-pass

這個命令會檢查 playbook 中的任務,並報告任何錯誤或變更。

處理檢查模式下的錯誤

在某些情況下,任務可能會在檢查模式下失敗。這通常是因為任務依賴於其他任務的輸出結果。為瞭解決這個問題,我們可以使用 check_mode: no 選項來停用檢查模式。以下是一個簡單的例子:

- name: start splunk cloudformation stack
  cloudformation:
    stack_name: "ProdSplunkStack"
    state: "present"
    region: "{{ aws_region }}"
    template: "roles/splunk_cloud/files/splunk-stack.yml"
    template_parameters:
      KeyName: "{{ aws_keypair }}"
      InstanceType: "{{ aws_instance_type }}"
      SSHLocation: "{{ aws_ssh_location }}"
      AWSAMI: "{{ aws_image }}"
    check_mode: no
  tags:
    env: "Production"
    service: "Splunk"
  register: production_splunk_stack

透過使用 check_mode: no 選項,我們可以確保任務在檢查模式下不會失敗。