Ansible 作為常用的自動化工具,在管理複雜 IT 基礎架構時,專案的組織結構和編碼方式至關重要。良好的 Ansible 專案結構能提升程式碼可讀性、可維護性和可重用性,尤其在面對多環境佈署和雲端資源管理時,更能顯著提高效率。本文將介紹 Ansible 的最佳實踐,包含目錄結構的規劃、角色的運用、自定義模組和外掛的開發,以及如何利用動態清單有效管理雲端資源,並探討如何應對不同環境的差異化組態需求。這些實踐將協助您建構更穩健、更易於管理的 Ansible 自動化流程。
第7章:Ansible 編碼最佳實踐
技術需求
本章假設您已經按照第1章的說明,在控制主機上安裝了Ansible,並且使用的是最新版本;本章中的範例是在Ansible 2.9上測試的。本章還假設您至少有一台額外的主機進行測試,理想情況下,這台主機應該是根據Linux的。
偏好的目錄結構
隨著Ansible playbook規模的增長,您很可能會希望將其分成多個檔案和目錄。一個很好的例子是角色(roles),我們在第4章中討論過。角色不僅可以重用常見的自動化程式碼,還可以將龐大的playbook分成更小、更易於管理的部分。我們還在第3章中討論瞭如何定義庫存檔案,以及如何將其分散在多個檔案和目錄中。
現在,讓我們透過一個簡單的根據角色的playbook例子,來展示如何設定目錄結構。這個例子中有兩個不同的庫存檔案,一個用於開發環境,另一個用於生產環境。
首先,建立開發庫存的目錄結構:
$ mkdir -p inventories/development/group_vars
$ mkdir -p inventories/development/host_vars
接下來,定義開發庫存的INI格式庫存檔案:
# inventories/development/hosts
[app]
app01.dev.example.com
app02.dev.example.com
然後,為app組新增一個組變數:
# inventories/development/group_vars/app.yml
---
http_port: 8080
使用相同的方法建立生產目錄結構:
$ mkdir -p inventories/production/group_vars
$ mkdir -p inventories/production/host_vars
建立生產庫存檔案:
# inventories/production/hosts
[app]
app01.prod.example.com
app02.prod.example.com
為生產庫存定義不同的http_port組變數值:
# inventories/production/group_vars/app.yml
---
http_port: 80
內容解密:
- 使用
mkdir命令建立目錄結構,以組織開發和生產環境的庫存檔案。 - 在
inventories/development/hosts檔案中定義開發環境的庫存,使用INI格式。 - 在
inventories/development/group_vars/app.yml檔案中定義app組的變數。 - 使用相同的方法建立生產環境的目錄結構和庫存檔案。
- 在
inventories/production/group_vars/app.yml檔案中定義生產環境的http_port組變數值。
新增自定義模組和外掛
假設我們想要使用在第5章中建立的 remote_filecopy.py 模組。首先,建立一個用於存放自定義模組的目錄:
$ mkdir library
然後,將 remote_filecopy.py 模組新增到該目錄中。
內容解密:
- 使用
mkdir命令建立一個名為library的目錄,用於存放自定義模組。 - 將
remote_filecopy.py模組新增到library目錄中,以便在playbook中使用。
最佳化 Ansible 專案結構的最佳實踐
在管理複雜的 IT 環境時,Ansible 提供了一種高效的自動化解決方案。為了充分利用 Ansible 的功能,遵循最佳實踐來組織專案結構至關重要。本章節將探討如何建立一個可擴充套件、可維護且易於理解的 Ansible 專案結構。
建立專案目錄結構
首先,建立一個新的專案目錄,並在其中建立必要的子目錄。以下是一個範例結構:
$ mkdir -p inventories/{development,production}/{group_vars,host_vars}
$ mkdir -p roles/installapp/{defaults,files,handlers,meta,tasks,templates,tests}
$ mkdir library filter_plugins
這個結構包含了以下關鍵元素:
inventories:存放不同環境(開發、生產等)的庫存檔案和變數。roles:定義可重複使用的 Ansible 角色。library:存放自定義的 Ansible 模組。filter_plugins:存放自定義的過濾器外掛。
目錄結構詳解
@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
組態庫存檔案和變數
在 inventories 目錄下,為不同的環境建立相應的庫存檔案和變數檔案。例如,在 inventories/development 下建立 hosts 檔案和 group_vars/app.yml 檔案。
範例:hosts 檔案
[app]
app01.dev.example.com
app02.dev.example.com
範例:group_vars/app.yml
---
http_port: 8080
開發自定義模組和過濾器
將自定義的 Ansible 模組放在 library 目錄下,將自定義的過濾器外掛放在 filter_plugins 目錄下。
範例:自定義模組 remote_filecopy.py
# 自訂檔案複製模組
# library/remote_filecopy.py
from ansible.module_utils.basic import AnsibleModule
import os
import shutil
import stat
# 主要執行函式
def main():
module = AnsibleModule(
argument_spec=dict(
source=dict(required=True),
dest=dict(required=True)
)
)
source = module.params['source']
dest = module.params['dest']
# 實作檔案複製邏輯
module.exit_json(changed=True)
if __name__ == '__main__':
main()
內容解密:
此自定義模組 remote_filecopy.py 用於實作遠端檔案複製功能。主要步驟包括:
- 匯入必要的 Ansible 模組。
- 定義模組引數,包括來源檔案路徑
source和目標檔案路徑dest。 - 實作檔案複製邏輯,具體實作細節因環境而異。
- 使用
module.exit_json(changed=True)回報操作結果。
範例:自定義過濾器 improve_automation.py
# filter_plugins/improve_automation.py
def improve_automation(s):
return s.replace('Puppet', 'Ansible')
class FilterModule(object):
def filters(self):
return {'improve_automation': improve_automation}
內容解密:
此自定義過濾器 improve_automation.py 用於修改字串中的特定內容。主要步驟包括:
- 定義一個函式
improve_automation,將輸入字串中的 ‘Puppet’ 替換為 ‘Ansible’。 - 建立一個
FilterModule類別,實作filters方法以註冊自定義過濾器。 - 使用此過濾器可以將字串中的 ‘Puppet’ 自動替換為 ‘Ansible’。
建立 Ansible 角色
使用 ansible-galaxy 命令建立新的角色,並在 roles/installapp/tasks/main.yml 檔案中定義任務。
範例:roles/installapp/tasks/main.yml
---
- name: Display http_port variable contents
debug:
var: http_port
- name: Create /tmp/foo
file:
path: /tmp/foo
state: file
- name: Use custom module to copy /tmp/foo
remote_filecopy:
source: /tmp/foo
dest: /tmp/bar
- name: Define a fact about automation
set_fact:
about_automation: "Puppet is an excellent automation tool"
- name: Tell us about automation with a custom filter applied
debug:
msg: "{{ about_automation | improve_automation }}"
內容解密:
此角色任務檔案定義了多個任務,包括:
- 顯示
http_port變數的值。 - 在遠端主機上建立
/tmp/foo檔案。 - 使用自定義模組
remote_filecopy複製/tmp/foo到/tmp/bar。 - 定義一個事實
about_automation。 - 使用自定義過濾器
improve_automation處理事實about_automation後輸出。
編寫頂層 Playbook
建立一個名為 site.yml 的頂層 Playbook,用於呼叫角色。
範例:site.yml
---
- name: Play using best practise directory structure
hosts: all
roles:
- installapp
內容解密:
此頂層 Playbook 主要功能是呼叫 installapp 角色,對所有主機執行相應任務。透過這種方式,可以簡化 Playbook 的結構,提高可讀性和可維護性。
執行 Playbook
使用以下命令執行 Playbook:
$ ansible-playbook -i inventories/development/hosts site.yml
$ ansible-playbook -i inventories/production/hosts site.yml
執行結果將顯示每個任務的執行狀態,包括成功、變更、不可達、失敗等資訊。
使用Ansible管理雲端資源的最佳實踐
雲端資源管理的挑戰
隨著雲端運算的普及,管理雲端資源成為了一項艱鉅的任務。雲端資源的動態特性使得傳統的靜態清單管理方式不再適用。Ansible作為一種強大的自動化工具,提供了動態清單的功能,可以有效地管理雲端資源。
使用動態清單管理雲端資源
在Ansible中,動態清單是指透過外部指令碼或API動態生成的清單。對於雲端資源的管理,動態清單可以根據雲端提供商的API取得最新的資源資訊,從而實作對雲端資源的有效管理。
取得動態清單指令碼
對於Ansible 2.9版本,可以從GitHub上的stable-2.9分支下載動態清單指令碼。例如,要使用Amazon EC2的動態清單指令碼,可以執行以下命令:
$ wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/ec2.py
$ chmod +x ec2.py
$ wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/ec2.ini
組態動態清單指令碼
下載完成後,需要組態動態清單指令碼。例如,對於EC2動態清單指令碼,需要設定AWS的存取金鑰和區域。可以在ec2.ini檔案中進行組態,或者透過環境變數進行設定。
[ec2]
regions = us-east-1,us-west-2
使用動態清單管理雲端資源
組態完成後,可以使用動態清單指令碼管理雲端資源。例如,可以使用以下命令列出EC2例項:
$ ./ec2.py --list
將動態清單與Ansible Playbook結合使用
可以將動態清單與Ansible Playbook結合使用,以實作對雲端資源的自動化管理。例如,可以建立一個Playbook來組態EC2例項:
---
- name: Configure EC2 instances
hosts: ec2
tasks:
- name: Install nginx
apt:
name: nginx
state: present
最佳實踐
- 使用動態清單:使用動態清單可以根據雲端提供商的API取得最新的資源資訊,從而實作對雲端資源的有效管理。
- 組態管理:需要對動態清單指令碼進行組態,以確保其能夠正確地取得雲端資源資訊。
- 與Ansible Playbook結合使用:將動態清單與Ansible Playbook結合使用,可以實作對雲端資源的自動化管理。
- 版本控制:需要對動態清單指令碼和Ansible Playbook進行版本控制,以確保其能夠正確地被執行。
內容解密:
- 使用動態清單可以根據雲端提供商的API取得最新的資源資訊。
- 組態管理是使用動態清單的關鍵步驟,需要根據雲端提供商的要求進行組態。
- 將動態清單與Ansible Playbook結合使用,可以實作對雲端資源的自動化管理。
- 版本控制是確保動態清單和Ansible Playbook正確執行的關鍵步驟。
動態庫存指令碼的實踐與環境差異化管理
在前面的章節中,我們已經探討了 Ansible 的基礎知識和靜態庫存管理。現在,我們將進一步探索動態庫存指令碼的實踐,並瞭解如何有效地管理不同環境之間的差異。
使用動態庫存指令碼連線雲端資源
動態庫存指令碼允許 Ansible 自動發現和管理雲端資源,例如 Amazon EC2 例項。為了使用這些指令碼,我們需要進行一些設定和組態。
組態 Boto 與 AWS 認證
首先,我們需要安裝 Boto 函式庫,它是 AWS 的 Python SDK。安裝方法取決於您的作業系統和 Python 版本。在 CentOS 7 上,您可以使用以下命令安裝:
$ sudo yum -y install python-boto python-boto3
或者,您可以使用 pip 進行安裝:
$ sudo pip3 install boto3
安裝完成後,我們需要設定 AWS 認證環境變數:
$ export AWS_ACCESS_KEY_ID='<YOUR_DATA>'
$ export AWS_SECRET_ACCESS_KEY='<YOUR_DATA>'
使用 ec2.py 動態庫存指令碼
ec2.py 是 Ansible 提供的一個動態庫存指令碼,用於連線 AWS EC2。該指令碼需要一個組態檔案 ec2.ini,用於設定各種引數,例如要連線的 AWS 區域。
[ec2]
regions = all
regions_exclude = us-gov-west-1, cn-north-1
執行動態庫存指令碼
組態完成後,我們可以使用以下命令執行 Ansible ping 模組,對所有 EC2 例項進行連線測試:
$ ansible -i ec2.py -u ec2-user --private-key /home/james/my-ec2-id_rsa -m ping all
快取管理與更新
許多動態庫存指令碼(包括 ec2.py)都會快取 API 呼叫的結果,以提高重複執行的速度。然而,在快速變化的開發環境中,這可能會導致更新延遲。您可以透過修改組態檔案中的快取引數或使用 --refresh-cache 選項手動重新整理快取:
$ ./ec2.py --refresh-cache
管理不同環境之間的差異
在大多數企業中,技術環境會被分為多種型別,例如開發環境、生產環境等。理想情況下,這些環境應該使用相同的 Ansible playbook,以確保佈署的一致性。然而,實際上,不同環境之間往往存在差異,例如主機名、引數、負載平衡器名稱和埠號等。
目錄結構與環境區分
在前面的章節中,我們討論瞭如何使用不同的庫存目錄樹來區分開發和生產環境。這種方法可以有效地管理不同環境之間的差異。
重用 Playbook 與角色
在管理多個環境時,我們的目標應該是盡可能重用相同的 playbook 和角色。這不僅可以簡化佈署流程,還可以確保 Ansible playbook 和角色本身也經過了充分的測試。
#### 內容解密:
- 動態庫存指令碼的優點:動態庫存指令碼允許 Ansible 自動發現和管理雲端資源,提高了管理的效率和準確性。
- Boto 與 AWS 認證:Boto 是 AWS 的 Python SDK,透過設定 AWS 認證環境變數,可以使 Ansible 連線到 AWS 資源。
- ec2.py 指令碼的使用:ec2.py 是 Ansible 提供的一個動態庫存指令碼,用於連線 AWS EC2。需要組態 ec2.ini 檔案以設定相關引數。
- 快取管理:動態庫存指令碼會快取 API 呼叫的結果,可以透過修改組態檔案或使用
--refresh-cache選項來管理快取。 - 環境差異化管理:透過使用不同的庫存目錄樹,可以有效地管理開發、生產等多個環境之間的差異。
- 重用 Playbook:盡可能重用相同的 playbook 和角色,可以簡化佈署流程,確保佈署的一致性。