在 Ansible 自動化世界中,有效管理 Collection 的版本和安裝路徑至關重要。版本控制不當可能導致 Playbook 無法執行,甚至引發非預期的錯誤。本文將分享我在 Ansible 專案中實踐的 Collection 管理策略,並教你如何利用 ansible-galaxy
提升團隊協作效率。
全域安裝:分享 Collection
對於團隊分享的 Collection,我建議統一安裝在全域路徑,例如 /usr/share/ansible/collections
。這樣所有使用者都能存取相同的 Collection 版本,避免版本衝突。
首先,建立全域 Collection 路徑並設定許可權:
sudo mkdir -p /usr/share/ansible/collections
sudo chmod a+w /usr/share/ansible/collections/
mkdir -p
指令可以遞迴建立目錄,如果父目錄不存在則會一併建立。chmod a+w
指令賦予所有使用者對該目錄的寫入許可權,確保 Ansible 可以安裝 Collection。
接著,使用 -p
引數指定安裝路徑:
ansible-galaxy collection install -p /usr/share/ansible/collections community.general
ansible-galaxy collection install
指令用於安裝 Collection。-p
引數指定安裝路徑。此指令會將 community.general
Collection 安裝到指定路徑。
驗證安裝結果:
ansible-galaxy collection list
ansible-galaxy collection list
指令會列出所有已知路徑下的 Collection,包含 COLLECTIONS_PATHS
變數中定義的路徑以及 Ansible 預設安裝路徑。
指定版本安裝與升級
ansible-galaxy
支援指定 Collection 版本安裝。例如,要安裝 community.general
的 4.8.0 版本:
ansible-galaxy collection install community.general:4.8.0
在 Collection 名稱後加上冒號和版本號即可指定安裝特定版本。
升級 Collection 也相當簡單,指定最新版本或使用 --force
引數強制重新安裝:
ansible-galaxy collection install --force community.general
--force
引數會強制重新安裝 Collection,即使已安裝相同版本。
ansible-galaxy
也支援版本範圍指定,例如安裝大於 4.5.0 小於 5.0.0 的版本:
ansible-galaxy collection install 'community.general:>4.5.0,<5.0.0'
使用版本範圍指定可以確保安裝的 Collection 版本符合特定需求,這在管理相依性時非常實用。
requirements.yml:版本控制利器
跨機器開發或執行 Playbook 時,全域安裝方式可能失效。此時,requirements.yml
檔案就派上用場了。它定義了所需的 Collection 及其版本,確保所有團隊成員使用一致的開發環境。
以下是一個 requirements.yml
範例:
---
collections:
- name: community.general
version: '>4.5.0,<5.0.0'
- community.crypto
requirements.yml
檔案使用 YAML 格式,列出所需的 Collection 及其版本或版本範圍。
使用 -r
引數即可根據 requirements.yml
安裝 Collection:
ansible-galaxy collection install -r requirements.yml
-r
引數指定 requirements.yml
檔案,ansible-galaxy
會根據檔案內容安裝或升級 Collection。
移除 Collection
ansible-galaxy
沒有提供移除 Collection 的指令。由於 Collection 只是特定結構的目錄和檔案,因此移除 Collection 就像刪除目錄一樣簡單:
rm -rf /usr/share/ansible/collections/ansible_collections/community/general/
使用 rm -rf
指令可以遞迴刪除指定目錄及其所有內容。請務必小心使用此指令,確保刪除的是正確的目錄。
建立個人 Ansible Collection
瞭解 Collection 的管理和維護後,讓我們建立自己的 Collection。
如同 Roles,Collection 只是目錄中的一組有組織的檔案。雖然你可以手動建立所有目錄,但也可以使用 ansible-galaxy
工具建立空白範本。
首先,需要一個名稱空間 (namespace) 和一個 Collection 名稱。在 Ansible Galaxy 網站上發布時,名稱空間將是你的 GitHub 控制程式碼。在本例中,我們不會發布到 Ansible Galaxy,因此我選擇 mynamespace
作為名稱空間,你可以根據需要替換它。
Collection 名稱通常用於指示 Collection 的用途。這裡,我們將建立一個名為 mycollection
的 Collection。
建立一個空目錄,然後建立目錄結構:
mkdir collection-development
cd collection-development/
ansible-galaxy collection init mynamespace.mycollection
ansible-galaxy collection init
指令會建立 Collection 的基本目錄結構。
檢查目錄結構:
.
└── mynamespace
└── mycollection
├── README.md
├── docs
├── galaxy.yml
├── meta
│ └── runtime.yml
├── plugins
│ └── README.md
└── roles
graph LR C[C] D[D] E[E] F[F] G[G] H[H] I[I] J[J] A[mynamespace] --> B(mycollection) B --> C{README.md} B --> D{docs} B --> E{galaxy.yml} B --> F{meta} F --> G{runtime.yml} B --> H{plugins} H --> I{README.md} B --> J{roles}
此圖表展示了新建立的 Ansible Collection 的目錄結構。mynamespace
是名稱空間,mycollection
是 Collection 名稱。其他檔案和目錄包含了 Collection 的檔案、設定、依賴關係、plugins 和 roles。
本文探討了 Ansible Collection 的版本控制、安裝和建立方法。妥善管理 Collection 版本能確保 Playbook 在不同環境中穩定執行,並提升團隊協作效率。我強烈建議將 requirements.yml
納入版本控制系統,讓所有團隊成員都能輕鬆設定一致的開發環境。
- name: 安裝 Apache
ansible.builtin.apt:
name: apache2
state: present
update_cache: yes
這個任務使用 apt
模組來安裝 apache2
套件。update_cache: yes
引數確保在安裝前更新套件快取。
建置並安裝 Collection 後,執行 playbook 即可安裝 Apache。
Collection 結構
以下 圖表展示了 Ansible Collection 的目錄結構:
flowchart LR subgraph blackcat1968.com A[README.md] --> B(galaxy.yml) B --> C(docs/) C --> D(meta/) D --> E(plugins/) E --> F(modules/) E --> G(lookup/) D --> H(roles/) H --> I(apache/) I --> J(tasks/) J --> K(main.yml) D --> L(playbooks/) L --> M(collection_test1.yml) L --> N(collection_test2.yml) D --> O(tests/) end
這個圖表清晰地展現了 Collection 內部的檔案和目錄組織,讓讀者更容易理解 Collection 的結構。
透過 Ansible Collection,您可以更有效地組織和管理您的自動化程式碼,提高程式碼的重用性和可維護性。善用 Collection,讓您的 Ansible 自動化更加便捷和高效。
/usr/lib/python3.6/site-packages/ansible/plugins
在 macOS 上,使用 Homebrew 安裝的 Ansible,外掛則位於:
/opt/homebrew/lib/python3.9/site-packages/ansible/plugins
您可以在自己的系統上使用 ansible --version
命令來確認 Ansible 的安裝路徑,從而找到外掛的具體位置。找到外掛目錄後,您可以瀏覽不同型別的外掛,例如 connection
、lookup
、inventory
等等。每個目錄都包含了該型別外掛的 Python 原始碼。
建立客製化外掛:以 Lookup 外掛為例
現在,讓我們動手建立一個簡單的 Lookup 外掛。Lookup 外掛的主要功能是從外部資料來源擷取資訊,並將其提供給 Ansible Playbook 使用。以下是一個名為 firstchar
的 Lookup 外掛範例,它會傳回字串的第一個字元:
# plugins/lookup/firstchar.py
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
# terms is a list of lookup terms
# variables is a dictionary of variables
# kwargs is a dictionary of additional keyword arguments
if not isinstance(terms, list):
raise AnsibleError('Terms must be a list')
ret = []
for term in terms:
if not isinstance(term, str):
raise AnsibleError('Term must be a string')
if term:
ret.append(term[0])
else:
ret.append('') # Return empty string for empty input
return ret
這個 firstchar
外掛繼承自 ansible.plugins.lookup.LookupBase
,並覆寫了 run
方法。run
方法接收一個 terms
列表作為輸入,其中每個元素都是一個要處理的字串。它會檢查輸入是否有效,並傳回一個列表,其中包含每個輸入字串的第一個字元。如果輸入字串為空,則傳回空字串。
將這個 firstchar.py
檔案儲存到您的外掛目錄下的 lookup
資料夾中。現在,您可以在 Playbook 中使用這個客製化外掛:
- hosts: all
tasks:
- debug:
msg: "The first character of 'hello' is {{ lookup('firstchar', 'hello') }}"
- debug:
msg: "The first character of an empty string is {{ lookup('firstchar', '') }}"
- name: Demonstrate handling multiple terms
debug:
msg: "First characters: {{ lookup('firstchar', 'apple', 'banana', 'cherry') }}"
- name: Demonstrate handling an empty list of terms
debug:
msg: "First characters of empty list: {{ lookup('firstchar') }}"
這個 Playbook 使用 lookup
函式呼叫 firstchar
外掛,並將結果顯示在螢幕上。它示範瞭如何處理單個字串、空字串、多個字串以及空列表等不同輸入情況。
執行這個 Playbook,您應該會看到以下輸出:
ok: [localhost] => {
"msg": "The first character of 'hello' is h"
}
ok: [localhost] => {
"msg": "The first character of an empty string is "
}
ok: [localhost] => {
"msg": "First characters: ['a', 'b', 'c']"
}
ok: [localhost] => {
"msg": "First characters of empty list: []"
}
Lookup 外掛執行流程:
graph LR B[B] A["Playbook 執行 lookup('firstchar', 'hello')"] --> B{"firstchar.py 的 run 方法"} B --> C["檢查輸入"] C -- "有效" --> D["擷取第一個字元 'h'"] C -- "無效" --> E["丟擲 AnsibleError"] D --> F["傳回 'h'"]
這個圖表展示了 Lookup 外掛的執行流程,從 Playbook 呼叫 lookup
函式開始,到外掛傳回結果結束。
透過這個簡單的範例,我們展示瞭如何建立和使用客製化 Lookup 外掛。您可以根據自己的需求修改和擴充套件這個範例,例如從檔案、資料函式庫或 API 中擷取資訊。
Ansible 的強大擴充套件性來自其靈活的外掛機制。本文將深入 filter 和 lookup 兩種外掛的開發,帶您掌握 Ansible 客製化外掛的精髓,提升自動化效率。
外掛位於 Ansible 安裝目錄下的 plugins
子目錄中,並根據其類別進一步分類別。例如,paramiko_ssh
連線外掛位於 connection/
子目錄:
/usr/lib/python3.11/site-packages/ansible/plugins/connection/paramiko_ssh.py
不建議直接修改已安裝的外掛檔案,因為套件升級時修改會被覆寫。查閱外掛原始碼的最佳方法是從 GitHub 複製
Ansible 儲存函式庫:
- 複製儲存函式庫:
git clone https://github.com/ansible/ansible.git
cd ansible
- 外掛位於
lib/ansible/plugins/
目錄下,同樣按類別放置在子目錄中:
cd lib/ansible/plugins
- 例如,
connection
目錄包含所有根據連線的外掛:
ls -al connection/
目錄內容取決於 Ansible 版本。每個外掛都有一個 Python 檔案。
- 檢視外掛內容:
less connection/paramiko_ssh.py
您會看到類別似以下程式碼片段,其中 DOCUMENTATION
區塊與模組的定義方式非常相似:
# (c) 2012, BlackCat <blackcat@blackcat1968.com>
# (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see COPYING or
https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
author: Ansible Core Team
connection: paramiko
...
接下來,我們將透過實際範例,建立一個客製化過濾器外掛。
建立客製化 Filter 外掛
這個範例將建立一個名為 custom_filter.py
的 Python 檔案,其中包含一個簡單的過濾器,用另一個字串替換給定的字串。
您的目錄結構應如下所示:
.
├── hosts
├── filter_plugins
│ └── custom_filter.py
├── myplugin2.yml
└── testdoc.txt
- 增加檔案標頭:
# (c) 2024, 玄貓(BlackCat) <blackcat@blackcat1968.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
- 定義過濾器函式:這個函式會將字串中的 “Puppet” 替換為 “Ansible”:
def improve_automation(a):
return a.replace("Puppet", "Ansible")
- 建立
FilterModule
物件:
class FilterModule(object):
''' 改進自動化過濾器 '''
def filters(self):
return {'improve_automation': improve_automation}
- 編寫測試 playbook:
---
- name: 示範客製化過濾器的 Playbook
hosts: frontends
gather_facts: false
vars:
statement: "Puppet 是一款出色的自動化工具!"
tasks:
- name: 顯示訊息
debug:
msg: "{{ statement | improve_automation }}"
這個 playbook 使用了自定義的 improve_automation
過濾器。filter_plugins
目錄指示 Ansible 查詢自定義過濾器的位置。Playbook 使用 debug
模組印出套用過濾器後的 statement
變數值,預期輸出會將 “Puppet” 替換為 “Ansible”。
這個簡單的範例展示瞭如何建立和使用 Ansible filter 外掛。您可以以此為基礎,構建更複雜的外掛以滿足您的自動化需求。
graph LR B[B] A[建立 filter_plugins 目錄] --> B{新增 custom_filter.py}; B --> C[定義過濾器函式]; C --> D[建立 FilterModule 類別]; D --> E[編寫 playbook]; E --> F[執行 playbook];
透過以上步驟,我們可以輕鬆建立一個客製化的 Ansible filter 外掛,並在 playbook 中使用它。這將大幅提升 Ansible 的靈活性和效率,讓您可以更好地管理和自動化您的基礎設施。
這個方法不僅限於字串操作,您可以根據需求編寫更複雜的邏輯,例如數值計算、資料轉換等,從而更好地滿足您的自動化需求。 善用 Ansible 的外掛機制,可以讓您的自動化任務更加簡潔、高效,並提升整體的可維護性。