Ansible Inventory 是自動化組態管理的核心,定義了 Ansible 管理的主機和群組。有效管理 Inventory 對於提升自動化效率至關重要。本文從靜態 Inventory 的基本定義開始,逐步探討如何使用 INI 和 YAML 格式定義主機、群組,以及如何有效地管理變數。同時,也涵蓋了動態 Inventory 的概念,讓讀者瞭解如何在雲端環境中自動化管理主機資源。文章以 Cobbler 為例,簡述了動態 Inventory 的設定步驟,並提供了一些實用的操作範例和組態說明。 瞭解 Inventory 的管理技巧能幫助工程師更有效率地使用 Ansible 進行自動化管理。

定義您的庫存 Chapter 3

在建立了上述架構之後,讓我們開始為它建立庫存,同樣混合使用 YAML 和 INI 格式,以讓您同時熟悉這兩種格式。為了保持範例的清晰和簡潔,我們假設您可以透過完全合格的網域名稱(FQDNs)存取所有伺服器,因此不會在這些庫存檔案中新增任何主機變數。當然,您可以根據實際需求進行調整,每個範例都有所不同。

首先,讓我們使用 INI 格式為三層前端建立庫存。我們將這個檔案命名為 hostsgroups-ini,其內容應該如下所示:

loadbalancer.example.com
[frontends]
frt01.example.com
frt02.example.com
[apps]
app01.example.com
app02.example.com
[databases]
dbms01.example.com
dbms02.example.com

內容解密:

在上述庫存中,我們建立了三個名為 frontendsappsdatabases 的群組。注意,在 INI 格式的庫存中,群組名稱放在方括號內。每個群組名稱下方列出了屬於該群組的伺服器名稱,因此上述範例中每個群組有兩個伺服器。注意頂部的 loadbalancer.example.com,這個主機不屬於任何群組。所有未分組的主機必須放在 INI 格式檔案的最頂部。

在繼續之前,值得注意的是,庫存也可以包含群組的群組,這對於按不同部門處理某些任務非常有用。上述庫存是獨立的,但如果我們的 frontends 伺服器是根據 Ubuntu,而 appdatabase 伺服器是根據 CentOS,則會有一些基本的差異。例如,我們可能在 Ubuntu 上使用 apt 模組來管理套件,而在 CentOS 上使用 yum 模組。

我們當然可以使用從每個主機收集的事實來處理這種情況,因為這些事實將包含作業系統的詳細資訊。我們也可以建立庫存的新版本,如下所示:

loadbalancer.example.com
[frontends]
frt01.example.com
frt02.example.com
[apps]
app01.example.com
app02.example.com
[databases]
dbms01.example.com
dbms02.example.com
[centos:children]
apps
databases
[ubuntu:children]
frontends

內容解密:

透過在群組定義中使用 children 關鍵字(在方括號內),我們可以建立群組的群組;因此,我們可以進行聰明的分組,以幫助我們的 Playbook 設計,而無需多次指定每個主機。

這種 INI 格式的結構相當易讀,但轉換成 YAML 格式時需要一些時間來適應。下面的程式碼顯示了上述庫存的 YAML 版本——兩者在 Ansible 看來是相同的,但由您決定更喜歡使用哪種格式:

all:
  hosts:
    loadbalancer.example.com:
  children:
    centos:
      children:
        apps:
          hosts:
            app01.example.com:
            app02.example.com:
        databases:
          hosts:
            dbms01.example.com:
            dbms02.example.com:
    ubuntu:
      children:
        frontends:
          hosts:
            frt01.example.com:
            frt02.example.com:

內容解密:

您可以看到,在 YAML 格式的庫存中仍然使用了 children 關鍵字,但現在結構更加層次化。縮排可能更容易讓您跟隨,但請注意主機最終是在相當高的縮排級別上定義的——取決於您想要的方法,這種格式可能更難擴充套件。

當您想要使用上述庫存中的任何群組時,您只需在 Playbook 或命令列中參照它即可。例如,在上一節中,我們執行了以下命令:

$ ansible -i /etc/ansible/my_inventory.yaml all -m shell -a 'echo hello-yaml' -f 5

注意命令列中間的 all 關鍵字。這是所有庫存中都隱含的特殊 all 群組,並且在您之前的 YAML 範例中明確提到了。如果我們想執行相同的命令,但這次只針對前述 YAML 庫存中的 centos 群組主機,我們將執行以下命令:

$ ansible -i hostgroups-yml centos -m shell -a 'echo hello-yaml' -f 5
app01.example.com | CHANGED | rc=0 >>
hello-yaml
app02.example.com | CHANGED | rc=0 >>
hello-yaml
dbms01.example.com | CHANGED | rc=0 >>
hello-yaml
dbms02.example.com | CHANGED | rc=0 >>
hello-yaml

內容解密:

正如您所見,這是一種強大的管理庫存的方式,並且可以輕鬆地在您想要的主機上執行命令。建立多個群組的可能性使生活變得簡單和容易,尤其是在您想要在不同的伺服器群組上執行不同的任務時。

除了開發您的庫存之外,值得注意的是,有一種快速簡寫符號可以用於建立多個主機。假設您有 100 個應用程式伺服器,它們的名字是按順序排列的,如下所示:

[apps]
app01.example.com
app02.example.com
...
app99.example.com
app100.example.com

內容解密:

這是完全可能的,但手動建立將會很繁瑣且容易出錯,並且會產生一些很難閱讀和解釋的庫存檔案。幸運的是,Ansible 提供了一種快速簡寫符號來實作這一點,以下庫存片段實際上產生了一個與我們手動建立的 100 個應用程式伺服器相同的庫存:

[apps]
app[01:100].prod.com

內容解密:

也可以使用字母範圍和數字範圍——擴充套件我們的範例以新增一些快取伺服器,您可能會看到以下內容:

[caches]
cache-[a:e].prod.com

內容解密:

這與手動建立以下內容相同:

[caches]
cache-a.prod.com
cache-b.prod.com
cache-c.prod.com
cache-d.prod.com
cache-e.prod.com

現在我們已經完成了對各種靜態庫存格式以及如何建立群組(以及子群組)的探索,讓我們在下一節中擴充套件我們之前對主機變數的簡要介紹。

將主機和群組變數新增到您的庫存中

我們已經接觸到了主機變數——在本章的前面部分,我們使用它們來覆寫連線詳細資訊,例如要連線的使用者帳戶、要連線的地址和要使用的埠。然而,Ansible 和庫存變數還有更多的功能需要注意,它們不僅可以在主機級別定義,也可以在群組級別定義,這再次為您提供了從一個中央庫存高效管理基礎設施的一些強大的方法。

管理與定義 Ansible Inventory 的最佳實踐

在前一章的基礎上,我們將進一步探討如何有效地管理和定義 Ansible Inventory。Ansible Inventory 是用於定義和管理主機及主機群組的重要元件,正確的組態和最佳化對於自動化管理的效率至關重要。

自定義變數的管理

在現實的應用場景中,我們經常需要為特定的主機或主機群組定義自定義變數。例如,假設我們有兩台前端伺服器,需要設定 https_portlb_vip 兩個變數,分別用於指定前端代理伺服器的監聽埠和負載平衡器的 FQDN。

方法一:在 Inventory 檔案中直接定義變數

最直接的方式是在 Inventory 檔案中直接為每個主機定義變數。例如,在 INI 格式的 Inventory 檔案中,可以這樣寫:

[frontends]
frt01.example.com https_port=8443 lb_vip=lb.example.com
frt02.example.com https_port=8443 lb_vip=lb.example.com

使用以下 ad hoc 命令可以驗證這些變數是否正確應用:

$ ansible -i hostvars1-hostgroups-ini frontends -m debug -a "msg=\"Connecting to {{ lb_vip }}, listening on {{ https_port }}\""

輸出結果如下:

frt01.example.com | SUCCESS => {
    "msg": "Connecting to lb.example.com, listening on 8443"
}
frt02.example.com | SUCCESS => {
    "msg": "Connecting to lb.example.com, listening on 8443"
}

雖然這種方法簡單直接,但當主機數量眾多且變數相同的情況下,會顯得冗餘和低效。

方法二:使用主機群組變數

Ansible 允許我們為整個主機群組定義變數,這樣可以避免重複設定相同的變數。修改後的 INI 格式 Inventory 檔案如下:

[frontends]
frt01.example.com
frt02.example.com

[frontends:vars]
https_port=8443
lb_vip=lb.example.com

執行相同的 ad hoc 命令,可以得到與之前相同的結果,但 Inventory 檔案的可讀性和可維護性得到了顯著提升。

方法三:混合使用主機變數和群組變數

在實際應用中,我們可能會遇到需要為個別主機覆寫群組變數的情況。Ansible 允許這種靈活的組態方式。例如:

[frontends]
frt01.example.com https_port=8444
frt02.example.com

[frontends:vars]
https_port=8443
lb_vip=lb.example.com

執行 ad hoc 命令後,可以看到 frt01.example.comhttps_port 變數被成功覆寫為 8444,而 frt02.example.com 仍然使用群組變數 8443

使用 YAML 格式的 Inventory 檔案

除了 INI 格式,Ansible 也支援 YAML 格式的 Inventory 檔案。上述範例在 YAML 格式下的表現如下:

frontends:
  hosts:
    frt01.example.com:
      https_port: 8444
    frt02.example.com:
  vars:
    https_port: 8443
    lb_vip: lb.example.com

執行相同的 ad hoc 命令,可以得到與 INI 格式相同的結果。

使用 host_varsgroup_vars 目錄管理變數

當 Inventory 規模擴大,變數管理成為一大挑戰。Ansible 提供了一種根據目錄結構的變數管理方式,即使用 host_varsgroup_vars 目錄。

首先,建立相關目錄結構:

$ mkdir vartree
$ cd vartree
$ mkdir host_vars group_vars

然後,在 host_vars 目錄下為特定主機建立 YAML 檔案(如 frt01.example.com.yml),並定義主機特有的變數:

---
https_port: 8444

group_vars 目錄下,為特定群組建立 YAML 檔案(如 frontends.yml),並定義群組共用的變數:

---
https_port: 8443
lb_vip: lb.example.com

最後,在 Inventory 檔案中,不再需要包含這些變數定義,保持簡潔。

這種方法使得變數管理更加模組化和易於維護,尤其是在大型基礎設施中。

詳細內容解密:
  1. 多種變數定義方式:文章介紹了在 Ansible Inventory 中定義變數的多種方法,包括直接在 Inventory 檔案中定義、使用群組變數、混合使用主機和群組變數,以及利用目錄結構進行管理。
  2. Inventory 檔案格式:文中比較了 INI 和 YAML 兩種格式的 Inventory 檔案,並展示瞭如何在這兩種格式下定義和管理變數。
  3. host_varsgroup_vars 目錄的使用:詳細說明瞭如何透過建立特定目錄結構來管理複雜環境下的變數,使組態更加模組化和易於維護。
  4. 實踐意義:透過這些方法的介紹,讀者可以根據實際需求選擇最合適的方式來管理和定義 Ansible Inventory,從而提升自動化管理的效率和可擴充套件性。

定義您的Inventory 章節3

現在,讓我們嘗試執行熟悉的Ad Hoc命令,看看會發生什麼:

$ ansible -i inventory frontends -m debug -a "msg=\"Connecting to {{ lb_vip }}, listening on {{ https_port }}\""
frt02.example.com | SUCCESS => {
    "msg": "Connecting to lb.example.com, listening on 8443"
}
frt01.example.com | SUCCESS => {
    "msg": "Connecting to lb.example.com, listening on 8444"
}

正如你所看到的,這與之前的工作方式完全相同,無需進一步的指示,Ansible就已經遍歷了目錄結構並讀取了所有的變數檔案。

細粒度目錄結構的使用

如果您有數百個變數(或需要更細粒度的處理),您可以將YAML檔案替換為以主機和組命名的目錄。讓我們重新建立目錄結構,但現在使用目錄:

$ tree
.
├── group_vars
│   └── frontends
│       ├── https_port.yml
│       └── lb_vip.yml
├── host_vars
│   └── frt01.example.com
│       └── main.yml
└── inventory

請注意,我們現在有一個以frontends組和frt01.example.com主機命名的目錄。在frontends目錄中,我們將變數分成兩個檔案,這對於在邏輯上組織變數群組來說非常有用,尤其是當您的Playbook變得越來越大和複雜時。

內容解密:

  • group_varshost_vars目錄用於存放與特定組或主機相關的變數。
  • 將變數檔案分割成多個檔案(如https_port.ymllb_vip.yml)有助於管理大量的變數。

變數優先順序的處理

在子群組級別定義相同變數時,子群組級別的變數優先順序更高。考慮到我們之前的inventory,其中我們使用子群組來區分CentOS和Ubuntu主機,如果我們在ubuntu子群組和frontends群組(它是ubuntu群組的子群組)中新增同名的變數,會發生什麼?

示例:

loadbalancer.example.com
[frontends]
frt01.example.com
frt02.example.com
[frontends:vars]
testvar=childgroup
[apps]
app01.example.com
app02.example.com
[databases]
dbms01.example.com
dbms02.example.com
[centos:children]
apps
databases
[ubuntu:children]
frontends
[ubuntu:vars]
testvar=group

執行Ad Hoc命令以檢視實際設定的testvar值:

$ ansible -i hostgroups-children-vars-ini ubuntu -m debug -a "var=testvar"
frt01.example.com | SUCCESS => {
    "testvar": "childgroup"
}
frt02.example.com | SUCCESS => {
    "testvar": "childgroup"
}

內容解密:

  • 在這個例子中,frontends群組是ubuntu群組的子群組,因此在frontends群組級別設定的變數值優先。

動態Inventory的生成

在雲端運算和基礎設施即程式碼(Infrastructure-as-Code)的時代,您可能需要自動化的主機可能會每天甚至每小時更改。保持靜態的Ansible Inventory更新可能會成為一份全職工作,因此,在許多大規模場景中,持續使用靜態Inventory變得不現實。

使用動態Inventory

Ansible可以從幾乎任何可執行檔案中收集其Inventory資料——唯一的條件是該可執行檔案以指定的JSON格式傳回Inventory資料。您可以自由建立自己的Inventory指令碼,但幸運的是,已經有很多現成的Inventory指令碼可供使用,涵蓋了包括Amazon EC2、Microsoft Azure、Red Hat Satellite、LDAP目錄等許多系統。

以Cobbler為例

這裡我們以Cobbler為例,因為它免費可用且易於在CentOS系統上佈署。對於那些感興趣的人來說,Cobbler是一個用於動態組態和構建Linux系統的系統,可以處理包括DNS、DHCP、PXE啟動等在內的所有方面。

安裝Cobbler

首先,您需要在CentOS 7.8上安裝相關的Cobbler包。請注意,在寫作時,CentOS 7提供的SELinux策略不支援Cobbler的一些功能,因此最簡單的方法是停用SELinux:

$ yum install -y cobbler cobbler-web
$ setenforce 0

接下來,請確保cobblerd服務被組態為監聽迴環地址,透過檢查/etc/cobbler/settings中的設定:

# default, localhost
server: 127.0.0.1

內容解密:

  • 停用SELinux是為了簡化演示過程,但在生產環境中不建議這樣做。
  • 組態cobblerd服務監聽迴環地址是為了確保其正常工作。