返回文章列表

Ansible最佳實踐

本文探討 Ansible 的最佳實踐,涵蓋目錄結構、角色、自定義模組、動態清單以及多環境管理等關鍵導向,提供建立可擴充套件、可維護 Ansible 專案的實用,並特別關注雲端資源的自動化管理和不同環境的差異化組態。文章以實際案例和程式碼片段,演示如何有效運用 Ansible 簡化 IT 自動化流程。

DevOps 自動化

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

內容解密:

  1. 使用 mkdir 命令建立目錄結構,以組織開發和生產環境的庫存檔案。
  2. inventories/development/hosts 檔案中定義開發環境的庫存,使用INI格式。
  3. inventories/development/group_vars/app.yml 檔案中定義 app 組的變數。
  4. 使用相同的方法建立生產環境的目錄結構和庫存檔案。
  5. inventories/production/group_vars/app.yml 檔案中定義生產環境的 http_port 組變數值。

新增自定義模組和外掛

假設我們想要使用在第5章中建立的 remote_filecopy.py 模組。首先,建立一個用於存放自定義模組的目錄:

$ mkdir library

然後,將 remote_filecopy.py 模組新增到該目錄中。

內容解密:

  1. 使用 mkdir 命令建立一個名為 library 的目錄,用於存放自定義模組。
  2. 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 用於實作遠端檔案複製功能。主要步驟包括:

  1. 匯入必要的 Ansible 模組。
  2. 定義模組引數,包括來源檔案路徑 source 和目標檔案路徑 dest
  3. 實作檔案複製邏輯,具體實作細節因環境而異。
  4. 使用 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 用於修改字串中的特定內容。主要步驟包括:

  1. 定義一個函式 improve_automation,將輸入字串中的 ‘Puppet’ 替換為 ‘Ansible’。
  2. 建立一個 FilterModule 類別,實作 filters 方法以註冊自定義過濾器。
  3. 使用此過濾器可以將字串中的 ‘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 }}"

內容解密:

此角色任務檔案定義了多個任務,包括:

  1. 顯示 http_port 變數的值。
  2. 在遠端主機上建立 /tmp/foo 檔案。
  3. 使用自定義模組 remote_filecopy 複製 /tmp/foo/tmp/bar
  4. 定義一個事實 about_automation
  5. 使用自定義過濾器 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

最佳實踐

  1. 使用動態清單:使用動態清單可以根據雲端提供商的API取得最新的資源資訊,從而實作對雲端資源的有效管理。
  2. 組態管理:需要對動態清單指令碼進行組態,以確保其能夠正確地取得雲端資源資訊。
  3. 與Ansible Playbook結合使用:將動態清單與Ansible Playbook結合使用,可以實作對雲端資源的自動化管理。
  4. 版本控制:需要對動態清單指令碼和Ansible Playbook進行版本控制,以確保其能夠正確地被執行。

內容解密:

  1. 使用動態清單可以根據雲端提供商的API取得最新的資源資訊。
  2. 組態管理是使用動態清單的關鍵步驟,需要根據雲端提供商的要求進行組態。
  3. 將動態清單與Ansible Playbook結合使用,可以實作對雲端資源的自動化管理。
  4. 版本控制是確保動態清單和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 和角色本身也經過了充分的測試。

#### 內容解密:

  1. 動態庫存指令碼的優點:動態庫存指令碼允許 Ansible 自動發現和管理雲端資源,提高了管理的效率和準確性。
  2. Boto 與 AWS 認證:Boto 是 AWS 的 Python SDK,透過設定 AWS 認證環境變數,可以使 Ansible 連線到 AWS 資源。
  3. ec2.py 指令碼的使用:ec2.py 是 Ansible 提供的一個動態庫存指令碼,用於連線 AWS EC2。需要組態 ec2.ini 檔案以設定相關引數。
  4. 快取管理:動態庫存指令碼會快取 API 呼叫的結果,可以透過修改組態檔案或使用 --refresh-cache 選項來管理快取。
  5. 環境差異化管理:透過使用不同的庫存目錄樹,可以有效地管理開發、生產等多個環境之間的差異。
  6. 重用 Playbook:盡可能重用相同的 playbook 和角色,可以簡化佈署流程,確保佈署的一致性。