Ansible 入門筆記(二) - Variable

Posted by MingLun Allen Wu on Friday, October 8, 2021

TL;DR

前情提要 - Ansible 入門筆記(ㄧ) - 核心概念及架構

使用 Ansible 同時部署多台機器時,使用Variable機制可以根據需求,賦予不同群組、不同節點特定的參數,增加部署的彈性及效率。

Jinja2 渲染

在開始探討 Ansible 的 Variable 前,我們先花點篇幅介紹 Jinja2 的渲染機制。

Jinja2是Python一套相當強大的模板引擎,許多Python相關的套件都有支援,例如: Flask, FastAPI

場內連結: 對於Flask, FastAPI 有興趣的朋友,歡迎看看我的其他筆記:

你可以將 Jinja2 的功能理解為:

根據需求將資訊動態寫入到檔案中

舉例來說,身為一個網頁設計師,你接到了一個案子,需要替公辰麵館設計一個網頁如下:

<html>
  <head>
    <title> 歡迎蒞臨-公辰麵館 </title>
  </head>
  <body>
    <h1>公辰麵館讚啦!</h1>
  </body>
</html>

因為網頁寫的太棒了,隔壁的華貞生魚片也希望你替他們設計一個相同的網頁,於是你又動手開工:

<html>
  <head>
    <title> 歡迎蒞臨-華貞生魚片 </title>
  </head>
  <body>
    <h1>華貞生魚片讚啦!</h1>
  </body>
</html>

仔細一看,這兩個網頁的架構幾乎一模一樣 (真是沒有職業道德的網頁設計師),只有店名的地方不一樣,如果能夠更省點時間有多好?

這時候 Jinja2 就派上用場了,你可以設計一個 模板(Template),裡面包含了重複的資訊,並且把要替換的資訊挖空:

<html>
  <head>
    <title> 歡迎蒞臨-{{ customer }} </title>
  </head>
  <body>
    <h1>{{ customer }}讚啦!</h1>
  </body>
</html>

這時候只要提供 customer 這個變數, Jinja2 就會按照上面的模板,自動將customer變數填進去,也就是說你只需要提供不同的 customer ,就可以快速的產生數百間店面的網頁!

真是薛翻了!


Variable

Ansible 的專案資料夾中有兩種類型的 Variable: Host Variable 以及 Group Variable

專案架構

Ansible 透過這兩種變數的交互使用,「快速」且「彈性」管理多台機器,先來個案例:

假設你準備要部署服務,而你的環境如下圖:

從上圖中,由外而內:

  1. 有兩個獨立的環境(Environment): SITPROD

  2. 每個環境中按照功能導向可分為兩種群組(Group):

    • Web-Server
    • DB-Server
  3. 每個群組中依照需求又可有多台主機(Node)

設定 Inventory File - 區別環境

上圖的架構在 Ansible 的架構中該如何表達呢?

首先需要掌握幾個重點:

  • 一個環境會有一個Inventory File
  • Inventory File 中定義了節點的連線資訊節點隸屬的群組

理解上述重點後,我們可以產生下列的Inventory File:

第一個 Inventory File - SIT

# SIT
[Web_Server] # 定義群組
Node_A ansible_host=127.0.0.1 ansible_port=44
Node_B ansible_host=192.168.16.49 ansible_port=44

[DB_Server] # 定義群組
Node_C ansible_host=127.0.0.1 ansible_port=3306
Node_D ansible_host=192.168.16.49 ansible_port=3306

第二個 Inventory File - Production

# Production
[Web_Server] # 定義群組
Node_E ansible_host=192.168.16.6 ansible_port=44
Node_F ansible_host=192.168.16.22 ansible_port=44

[DB_Server] # 定義群組
Node_H ansible_host=192.168.17.12 ansible_port=3306
Node_G ansible_host=192.168.17.84 ansible_port=3306

一個環境會有一個Inventory File,其定義了節點的連線資訊及各節點隸屬的群組

此時專案資料夾將會長這樣:

ansible_project
| - README.md
| - SIT  # Inventory File
| - Production # Inventory File
| - main.yml # Playbook

定義好 Inventory File 後,透過指定 Inventory File 就可以對不同的環境進行操作:

ansible-playbook -i SIT main.yml # 操作SIT環境
ansible-playbook -i Production main.yml # 操作Production環境

Group Variable - 群組變數

在開頭我們提到使用 Variable 可以有彈性的操作多台機器,又介紹了 Jinja2 這種語法,現在我們來揭曉原因!

Playbook 中可以使用 Jinja2語法,舉個例子,我們設計一個簡單的 Playbook,在執行時會透過 Debug 模組印出特定的值.

# main.yml
- name: task-for-db
  hosts: DB_Server
  tasks:
    - name: db-show-group
      debug:
        msg: I'm a database node! My group is {{ group_value }}

- name: task-for-web
  hosts: Web_Server
  tasks:
    - name: web-show-group
      debug:
        msg: I'm a web node! My group is {{ group_value }}

接下來可以在 group_vars 資料夾下,根據群組名稱建立同名的 yaml 檔案:

# group_vars/Web_Server.yml
group_value: GROUP_WEB
# group_vars/DB_Server.yml
group_value: GROUP_DB

Playbook 被執行時, Ansible 會造訪 group_vars 資料夾讀取這些變數:

  • Playbookhosts 設定為 Web_Server 的區塊,有個 {{ group_value }}Ansible 將自動從 group_vars/Web_Server.yml中將設定的變數填入.
  • Playbookhosts 設定為 DB_Server 的區塊,有個 {{ group_value }}Ansible 將自動從 group_vars/DB_Server.yml中將設定的變數填入.

當群組有自己專用的變數時,可以設定在group_vars中,例如DB_Server會需要資料庫的名稱、連線資訊,而 Web_Server 則不需要。

此時我們將前面的專案結構稍微擴充 :

ansible_project
| - README.md
| - SIT  # Inventory File
| - Production # Inventory File
| main.yml # Playbook
| 
| - group_vars/ 
    | - DB_Server.yml # Group Variable
    | - Web_Server.yml # Group Variable

Host Variable - 節點變數

Host Variable 放置的是節點專屬的變數

有別於 Group Value 放置的是群組專用的變數,有時候我們會需要設定「節點」專屬的變數 (例如節點的ip、Linux的版本等等)。

舉例來說,我們稍微擴充一下 Playbook:

# main.yml
- name: task-for-db
  hosts: DB_Server
  tasks:
    - name: db-show-group
      debug:
        msg: I'm a database node! My group is {{ group_value }}
    - name: db-show-node
      debug:
        msg: My node information(DB) is {{ node_value }}

- name: task-for-web
  hosts: Web_Server
  tasks:
    - name: web-show-group
      debug:
        msg: I'm a web node! My group is {{ group_value }}
    - name: web-show-node
      debug:
        msg: My node information(Web) is {{ node_value }}

這些節點專屬的變數統一放在 host_vars/ 資料夾下,且名稱會與節點同名

# /host_vars/Node_A.yml
node_value: I'm Node A
# /host_vars/Node_B.yml
node_value: I'm Node B

Playbook 被執行時, Ansible 會造訪 host_vars 資料夾讀取這些變數:

  • AnsibleNode_A機器上執行Playbook安排的任務時,將自動從 host_vars/Node_A.yml中將設定的變數填入{{ node_value }}.
    • AnsibleNode_B機器上執行Playbook安排的任務時,將自動從 host_vars/Node_B.yml中將設定的變數填入{{ node_value }}.

當節點有自己專用的變數時,可以設定在 host_vars/ 中,例如節點A與節點B分別有不同的IP位置。

此時我們繼續擴充專案結構 :

ansible_project
| - README.md
| - SIT  # Inventory File
| - Production # Inventory File
| main.yml # Playbook
|
| - group_vars/
    | - DB_Server.yml # Group Variable
    | - Web_Server.yml # Group Variable
| - host_vars/
    | - Node_A.yml # Host Variable
    | - Node_B.yml # Host Variable
    .
    .
    .
    | - Node_H.yml # Host Variable

結論

本篇筆記記錄了 Ansible 容易搞混的 Variable 機制,根據部署時的需求可以選擇使用 Group Variable 或是 Host Variable.

這些Variable都會在Playbook執行時透過Jinja2的渲染將變數填入。

在多台機器上部署服務時,通常做的事情都是相同的,只是使用的參數會有所不同,透過 Group VariableHost Variable 的交叉使用,可以靈活設定每一個節點。

一旦某些參數需要進行調整(例如Production環境的某個IP要更換),可以直接更換Variable設定的值就好,不需要勞師動眾的調整Playbook

在下篇筆記中,我們將會繼續介紹 Ansible 的應用,包含:

  • 如何使用 role 來提高 Ansible 專案的程式碼重用率
  • 使用 Ansible-Galaxy 來取得眾多開源Playbook

感謝您的閱讀!如果有任何問題歡迎透過電子郵件聯繫我!

我們下次見!



See Also

監控資料品質的旅程