Ansible 作為常用的自動化工具,仰賴變數、Jinja2 過濾器和 Inventory 等核心元件來實作靈活的組態管理。變數在 Ansible 中扮演重要的角色,允許使用者在不同環境中重複使用程式碼並根據需求進行客製化。然而,理解變數的優先順序至關重要,因為它決定了 Ansible 如何解析變數值。Jinja2 過濾器則提供強大的資料處理能力,讓使用者能輕鬆轉換和操作資料,例如格式化字串、處理清單和字典等。Inventory 檔案則定義了 Ansible 管理的主機,可以透過靜態或動態方式建立,並支援主機分組以簡化管理和佈署流程。這些功能共同構成了 Ansible 的根本,讓使用者能有效地自動化各種任務。
瞭解 Ansible 的基礎 Chapter 2
變數優先順序的重要性
在前面的章節中,我們簡要地介紹了 Ansible 中的變數。變數在 Ansible 中非常重要,因為它們允許我們在不同的 playbook 和角色中重複使用相同的程式碼,同時根據不同的環境或主機進行自定義。然而,變數優先順序可能會讓人感到困惑,因為它取決於變數的定義位置和方式。此外,它可能會在 Ansible 版本之間發生變化,因此在處理和理解變數優先順序時,參考官方檔案是非常重要的。您可以存取 https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable 取得更多資訊。
瞭解 Jinja2 過濾器
Ansible 是用 Python 編寫的,因此它繼承了一個非常有用且強大的範本引擎,稱為 Jinja2。我們將在本文後面探討範本的概念,目前,我們將重點介紹 Jinja2 的一個特定方面,即過濾。Jinja2 過濾器提供了一個非常強大的框架,您可以使用它來操縱和轉換資料。也許您有一個需要轉換為小寫的字串,您可以應用 Jinja2 過濾器來實作這一點。您還可以使用它來執行模式匹配、搜尋和替換操作等。有數百個過濾器可供您使用,在本文中,我們希望賦予您對 Jinja2 過濾器的基本理解,以及一些關於如何應用它們的實用知識,並向您展示如果您希望進一步探索該主題,可以在哪裡獲得更多資訊。
值得注意的是,Jinja2 操作是在 Ansible 控制主機上執行的,只有過濾操作的結果才會被傳送到遠端主機。這是設計使然,既為了保持一致性,又為了盡可能減少個別節點的工作量。
例項解析
假設我們有一個 YAML 檔案,其中包含一些我們想要解析的資料。我們可以輕鬆地從機器檔案系統中讀取檔案,並使用 register 關鍵字捕捉結果(register 捕捉任務的結果並將其儲存在變數中——在執行 shell 模組的情況下,它捕捉命令的所有輸出)。
我們的 YAML 資料檔案可能如下所示:
tags:
- key: job
value: developer
- key: language
value: java
以下是一個範例 playbook,用於讀取此檔案並註冊結果:
---
- name: Jinja2 過濾器演示 1
hosts: localhost
tasks:
- copy:
src: multiple-document-strings.yaml
dest: /tmp/multiple-document-strings.yaml
- shell: cat /tmp/multiple-document-strings.yaml
register: result
- debug:
msg: '{{ item }}'
loop: '{{ result.stdout | from_yaml_all | list }}'
內容解密:
copy模組將multiple-document-strings.yaml檔案複製到/tmp目錄下,以便shell模組讀取。shell模組讀取/tmp/multiple-document-strings.yaml檔案的內容,並將結果儲存在result變數中。debug模組使用loop迴圈遍歷result.stdout的內容,並應用from_yaml_all和list過濾器將 YAML 資料解析為 Ansible 清單。from_yaml_all過濾器解析源檔案行為 YAML,而list過濾器將解析的資料轉換為有效的 Ansible 清單。
執行此 playbook 後,我們可以看到 Ansible 對資料結構的表示:
{
"msg": {
"tags": [
{
"key": "job",
"value": "developer"
},
{
"key": "language",
"value": "java"
}
]
}
}
將清單轉換為鍵值對
如果資料結構已經儲存在我們的 playbook 中,我們可以使用 items2dict 過濾器將清單轉換為真正的鍵值對,從而刪除資料結構中的 key 和 value 專案。例如,請考慮以下第二個 playbook:
---
- name: Jinja2 過濾器演示 2
hosts: localhost
vars:
tags:
- key: job
value: developer
- key: language
value: java
tasks:
- debug:
msg: '{{ tags | items2dict }}'
內容解密:
vars部分定義了一個名為tags的變數,它是一個包含key和value的字典清單。debug模組使用items2dict過濾器將tags清單轉換為鍵值對。
執行此 playbook 後,我們可以看到我們的資料被轉換為一個乾淨的鍵值對集合:
{
"msg": {
"job": "developer",
"language": "java"
}
}
使用 lookup 過濾器讀取檔案
Jinja2 包含一系列查詢過濾器,可以讀取給設定檔案的內容。讓我們檢查以下 playbook 的行為:
---
- name: Jinja2 過濾器演示 3
hosts: localhost
vars:
ping_value: "{{ lookup('file', '/etc/hosts') }}"
內容解密:
vars部分定義了一個名為ping_value的變數,它使用lookup過濾器讀取/etc/hosts檔案的內容。
透過這種方式,我們可以輕鬆地將檔案內容讀取到 Ansible 的變數中,並對其進行進一步的操作和處理。
Ansible基礎與Jinja2過濾器詳解
Jinja2過濾器的實用範例
在Ansible中,Jinja2過濾器是一種強大的工具,能夠用於處理和轉換資料。以下是一個使用debug模組輸出變數值的範例:
tasks:
- debug:
msg: "ping value is {{ ping_value }}"
當執行這個playbook時,Ansible會捕捉/etc/hosts檔案的內容,並將其輸出:
$ ansible-playbook -i localhost, jinja2-filtering3.yml
PLAY [Jinja2 filtering demo 3] *************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": "ping value is 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4\n::1 localhost localhost.localdomain localhost6 localhost6.localdomain6\n\n"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
內容解密:
debug模組:用於輸出除錯資訊。msg引數:定義輸出的訊息內容。{{ ping_value }}:參照變數ping_value的值。
Jinja2過濾器提供了多種功能,例如參照字串、串聯列表、取得檔案路徑資訊等。以下是一些範例:
# 在shell中新增引號
- shell: echo {{ string_value | quote }}
# 將列表串聯成特定字串
{{ list | join("$") }}
# 取得檔案路徑的最後名稱
{{ path | basename }}
# 取得檔案路徑的目錄
{{ path | dirname }}
# 取得Windows檔案路徑的目錄
{{ path | win_dirname }}
內容解密:
quote過濾器:為字串新增引號,確保在shell中正確解析。join過濾器:將列表中的元素串聯成一個字串,使用指定的分隔符(如$)。basename過濾器:取得檔案路徑的最後部分,即檔名。dirname過濾器:取得檔案路徑的目錄部分。win_dirname過濾器:專門用於Windows檔案路徑,取得其目錄部分。
Ansible Inventory詳解
建立Inventory檔案與新增主機
在Ansible中,Inventory檔案用於定義要管理的主機。可以透過靜態或動態方式建立Inventory。
靜態Inventory範例
大多數Ansible安裝預設會在/etc/ansible/hosts尋找Inventory檔案。當然,也可以透過-i引數指定自定義的Inventory檔案。
$ ansible -i /home/cloud-user/inventory all -m ping
內容解密:
-i引數:指定Inventory檔案的路徑。all:表示對Inventory中的所有主機執行操作。-m ping:使用ping模組測試主機連線。
技術需求
本章節假設讀者已按照第一章的說明設定好Ansible控制節點,並使用最新版本的Ansible(例如2.9)。此外,建議至少有一台額外的Linux主機用於測試。
建立動態Inventory檔案
除了靜態Inventory,Ansible還支援動態Inventory,能夠根據實際環境動態生成主機列表。
特殊主機管理使用模式
Ansible提供了多種模式來管理主機,例如使用正規表示式選擇特定的主機群組。
重點整理
- Ansible Inventory的基本概念:瞭解靜態和動態Inventory的區別及應用場景。
- 建立與管理Inventory檔案:學習如何建立和維護Inventory檔案,以及如何使用不同的引數進行主機管理。
- Jinja2過濾器的應用:掌握Jinja2過濾器的使用方法,提高資料處理的靈活性。
練習題
Ansible中哪個元件允許定義一個區塊來執行任務群組?
- A) handler
- B) service
- C) hosts
- D) tasks
- E) name
YAML格式的基本語法中,哪個符號用於開始一個檔案?
- A) ###
- B)
- C) %%%
- D) ===
- E) ***
- 在Ansible中,是否需要使用Jinja2範本來解釋和轉換輸出資料?
- A) True
- B) False
參考資料
更多組態變數的資訊,請參考Ansible官方檔案。
定義您的庫存 Chapter 3
大多數靜態庫存檔案採用INI格式建立,但也支援其他格式。除了INI格式之外,YAML格式也是常見的選擇。更多有關庫存檔案格式的資訊,請參閱:https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html。
在本章中,我們將提供INI和YAML格式的庫存檔案範例,讓您瞭解兩者的差異。個人而言,我已經使用Ansible多年,主要使用INI格式或動態庫存,但學習不同的格式總是有益的。
首先,讓我們建立一個靜態庫存檔案。這個庫存檔案將與預設庫存分開。
在/etc/ansible/my_inventory中建立一個庫存檔案,使用以下INI格式的程式碼:
target1.example.com ansible_host=192.168.81.142 ansible_port=3333
target2.example.com ansible_port=3333 ansible_user=danieloh
target3.example.com ansible_host=192.168.81.143 ansible_port=5555
內容解密:
target1.example.com、target2.example.com和target3.example.com是Ansible使用的庫存主機名,可以透過inventory_hostname變數存取。ansible_host變數指定Ansible連線主機的IP地址或主機名。ansible_port變數指定Ansible連線主機的SSH埠,預設為22。ansible_user變數指定Ansible連線主機的使用者帳號。
這個庫存檔案非常簡單,沒有包含任何分組。但是,您仍然可以使用特殊的all組來參照所有主機。
如果要建立相同的庫存,但使用YAML格式,則可以按如下方式指定:
---
ungrouped:
hosts:
target1.example.com:
ansible_host: 192.168.81.142
ansible_port: 3333
target2.example.com:
ansible_port: 3333
ansible_user: danieloh
target3.example.com:
ansible_host: 192.168.81.143
ansible_port: 5555
內容解密:
- YAML格式的庫存檔案使用縮排來表示層級結構。
ungrouped是主機的分組名稱,在這個例子中,所有主機都屬於這個組。hosts關鍵字用於指定組中的主機。- 每個主機的變數都以鍵值對的形式表示。
執行上述庫存檔案,使用簡單的shell命令,結果如下:
$ ansible -i /etc/ansible/my_inventory.yaml all -m shell -a 'echo hello-yaml' -f 5
target1.example.com | CHANGED | rc=0 >>
hello-yaml
target2.example.com | CHANGED | rc=0 >>
hello-yaml
target3.example.com | CHANGED | rc=0 >>
hello-yaml
這就介紹了建立簡單靜態庫存檔案的基本知識。接下來,我們將透過在庫存中新增主機組來擴充套件這個概念。
使用主機組
在實際應用中,很少有一個Playbook能夠適用於整個基礎設施。雖然可以告訴Ansible為不同的Playbook使用不同的庫存,但這可能會很快變得混亂。一個簡單的解決方案是在庫存中新增組。
假設您有一個簡單的三層Web架構,每個層中有多個主機,以實作高用性和/或負載平衡。這三個層可能是:
- 前端伺服器
- 應用程式伺服器
- 資料函式庫伺服器
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title Ansible變數Jinja2過濾器與Inventory詳解
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此圖示展示了一個簡單的三層Web架構,每個層之間都有明確的依賴關係。
內容解密:
- 三層Web架構是一種常見的架構模式,將應用程式分成三個獨立的層。
- 每個層都有其特定的功能和責任。
- 使用主機組可以更好地管理和組織這些主機。