Ansible Playbook 的變數機制允許使用者根據不同環境和需求調整佈署設定,提升自動化效率。設定變數的位置多元,包含角色預設值、庫存變數、Playbook 變數等,Ansible 會根據優先順序套用變數值。在角色中,可以透過 defaults/main.yml 設定預設變數值,並在 tasks/main.yml 和範本檔案中使用這些變數。例如,可以將資料函式庫連線資訊、網域名稱等設定為變數,方便管理和修改。此外,Ansible 也支援透過 set_fact 模組動態設定變數,例如根據主機事實或其他變數的值設定新的變數。除了在 Playbook 中直接定義變數外,還可以利用 vars_prompt 互動式提示使用者輸入變數值,或是使用 vars_files 載入外部 YAML 檔案中的變數,增加 Playbook 的彈性。

將變數套用到 Playbook

在 Ansible Playbook 中,除了指定要包含的角色(role)之外,還可以指定要在該角色中使用的變數。這樣可以使 Playbook 更加靈活和安全。

更新 Playbook 以使用變數

首先,讓我們更新 Playbook 以指定一些新的變數。這些變數將用於使 Playbook 更加安全。我們將使用不同的語法來指定角色,並告訴 Ansible 哪個條目是要執行的角色。

- hosts: all
  become: true
  roles:
    - role: mheap.wordpress
      database_name: michaelwp
      database_user: michaelwp
      database_password: bananas18374

內容解密:

  1. hosts: all:指定 Playbook 要執行的主機群組。
  2. become: true:啟用許可權提升,以便以更高許可權執行任務。
  3. roles:指定要包含的角色列表。
  4. role: mheap.wordpress:指定要執行的角色名稱。
  5. database_namedatabase_userdatabase_password:為角色指定變數。

在任務檔案中使用變數

接下來,我們需要在任務檔案中使用這些變數。開啟 roles/mheap.wordpress/tasks/main.yml 檔案,並將任何硬編碼的資料函式庫名稱、使用者或密碼替換為新的變數。

- name: Create WordPress MySQL database
  mysql_db: name="{{database_name}}" state=present

- name: Create WordPress MySQL user
  mysql_user: name="{{database_user}}" host=localhost password="{{database_password}}" priv="{{database_name}}.*:ALL"

- name: Does the database exist?
  command: mysql -u root {{database_name}} -e "SELECT ID FROM {{database_name}}.wp_users LIMIT 1;"
  register: db_exist
  ignore_errors: true
  changed_when: false

- name: Copy WordPress DB
  template: src=wp-database.sql dest=/tmp/wp-database.sql
  when: db_exist.rc > 0

- name: Import WordPress DB
  mysql_db: target=/tmp/wp-database.sql state=import name="{{database_name}}"
  when: db_exist.rc > 0

內容解密:

  1. mysql_dbmysql_user 模組使用變數來建立資料函式庫和使用者。
  2. command 模組使用變數來檢查資料函式庫是否存在。
  3. template 模組用於將 wp-database.sql 檔案複製到遠端主機,並替換其中的變數。

在範本檔案中使用變數

我們還需要在 wp-config.php 範本檔案中使用這些變數。開啟 roles/mheap.wordpress/templates/wp-config.php 檔案,並將硬編碼的資料函式庫憑證替換為變數。

/** The name of the database for WordPress */
define('DB_NAME', '{{database_name}}');

/** MySQL database username */
define('DB_USER', '{{database_user}}');

/** MySQL database password */
define('DB_PASSWORD', '{{database_password}}');

內容解密:

  1. 使用 Jinja2 語法 {{variable_name}} 將變數插入到範本檔案中。

自定義 WordPress 網域名稱

目前,WordPress 的 URL 被硬編碼為 book.example.com。讓我們更新角色,以便接受網域名稱作為變數。

- role: mheap.wordpress
  database_name: michaelwp
  database_user: michaelwp
  database_password: bananas18374
  wp_domain: book.example.com

內容解密:

  1. 新增 wp_domain 變數來指定 WordPress 網域名稱。

更新相關檔案以使用 wp_domain 變數

我們需要更新相關檔案以使用 wp_domain 變數。

  1. 編輯 roles/mheap.nginx/templates/default 檔案,將 server_nameroot 目錄更新為使用 wp_domain 變數。
server_name {{wp_domain}};
root /var/www/{{wp_domain}};
  1. 編輯 roles/mheap.wordpress/files/wp-database.sql 檔案,將所有出現的 book.example.com 替換為 {{wp_domain}}

  2. 編輯 roles/mheap.wordpress/tasks/main.yml 檔案,將所有出現的 book.example.com 替換為 {{wp_domain}}

自定義預設文章標題和內容

我們還可以自定義預設文章的標題和內容。

- role: mheap.wordpress
  database_name: michaelwp
  database_user: michaelwp
  database_password: bananas18374
  wp_domain: book.example.com
  initial_post_title: Hey There
  initial_post_content: >
    This is an example post. Change me to say something interesting.

內容解密:

  1. 新增 initial_post_titleinitial_post_content 變數來自定義預設文章的標題和內容。

透過使用變數,我們可以使 Playbook 更加靈活和可重複使用。我們可以根據需要自定義不同的變數,以佈署不同的 WordPress 安裝。

第5章:引數化Playbook

變數位置

Ansible對變數有很好的支援,不僅可以在Playbook或檔案中使用,還可以在16個不同的位置定義變數。雖然Ansible檔案解釋了這16個位置之間的變數優先順序,但並沒有提供如何使用每個位置的範例,或者更重要的是,何時使用每個位置。我們將逐一檢視每個位置,並解釋何時使用它來設定變數。在Playbook中常用的位置已經被標記,以給你一個常見擴充套件點的想法。

這些位置按照從最不重要到最重要的順序排列;也就是說,角色預設值具有最低的優先順序,並且被其他所有設定所覆寫。庫存群組變數會覆寫角色預設值,但本身會被set_fact模組所覆寫。

角色預設值(常用)

這是角色目錄下的defaults/main.yml檔案。在此檔案中設定的變數具有最低的優先順序,這使得它非常適合設定預設值。例如,在your_role/defaults/main.yml中:

your_name: World

庫存變數

當你為Ansible建立一個庫存檔案以連線到你的Vagrant機器時,你使用了庫存變數。大多數情況下,你只會在庫存檔案中使用特定於庫存的變數(例如ansible_useransible_ssh_private_key_file,我們在第2章中介紹過),但你可以設定任何你喜歡的變數。這個變數將只在這個主機上可用。例如:

192.168.33.20 your_name=World

你也可以為一組主機或一組群組指定變數,例如:

[app]
192.168.33.20
192.168.33.21

[admin]
192.168.33.33

[database]
192.168.33.55

[websites:children]
app
admin

[app:vars]
your_name=World

[admin:vars]
your_name=World

[database:vars]
your_name=Michael

[websites:vars]
php_version: 7

庫存群組變數

要為庫存設定群組變數,你的庫存需要放在自己的資料夾中。建立一個名為inventory的資料夾,並將你的庫存檔案(在第2章中介紹過)移到裡面;也就是說,你的實際庫存檔案位於inventory/inventory

要使用庫存群組變數,你必須建立一個名為inventory/group_vars的資料夾,它可以包含你建立的任何群組的變數檔案,例如下面的inventory/inventory檔案:

[app]
192.168.33.20
192.168.33.21

[admin]
192.168.33.33

[database]
192.168.33.55

為了指定這個庫存檔案中的主機的群組變數,你必須有一個像圖5-1一樣的資料夾結構。

inventory/group_vars/admin.yml中定義的任何變數都將在admin群組中的任何主機上可用。

庫存主機變數

與庫存群組變數類別似,你可以為每個主機指定變數。使用相同的庫存檔案:

[app]
192.168.33.20
192.168.33.21

[admin]
192.168.33.33

[database]
192.168.33.55

你可以建立一個像圖5-2一樣的資料夾結構。

192.168.33.20.yml中定義的任何變數都將在主機192.168.33.20上可用。

inventory/host_vars/192.168.33.20.yml中建立以下內容:

your_name: World

這與在庫存檔案中具有以下內容在功能上是等價的:

192.168.33.20 your_name=World

Playbook群組變數(常用)

群組變數也可以在Playbook層級的group_vars資料夾中定義。它們的外觀和行為與庫存group_vars資料夾完全相同,除了它們位於與playbook.yml相同的層級,並且具有稍微更高的優先順序。

Playbook主機變數(常用)

就像群組變數一樣,主機變數也可以在Playbook層級定義。它們在功能上等同於庫存host_vars,但具有稍微更高的優先順序。

主機事實

Ansible有“事實”的概念,它是關於當前主機的可用資訊。有許多不同的事實可用,包括機器執行的作業系統、它的IP地址,甚至是機器上使用的記憶體量。這些事實在Ansible執行期間以變數的形式存在,供你在Playbook和範本中使用。

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Ansible Playbook 變數設定與應用

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

此圖示展示了Ansible中不同變數位置的優先順序,從最低到最高。

內容解密:

此圖表呈現了 Ansible 變數設定的優先順序,從最低到最高。最低優先順序是角色預設值,然後依序是庫存變數、庫存群組變數、Playbook 群組變數、Playbook 主機變數、主機事實,最後是由 set_fact 模組設定的值具有最高優先順序。這種層級結構確保了 Ansible 在執行任務時能夠正確地解析和使用變數。

修改 wp-database.sql 的存放位置

由於現在使用的是 template 模組而不是 copy 模組,因此也需要更改 wp-database.sql 的存放位置。將其從 files 目錄移至 templates 目錄,使用以下命令:

mv provisioning/roles/mheap.wordpress/files/wp-database.sql provisioning/roles/mheap.wordpress/templates

此步驟確保 wp-database.sql 檔案位於正確的位置,以便 template 模組能夠正確處理它。

內容解密:

這段程式碼的作用是移動 wp-database.sql 檔案到正確的目錄下。因為從 copy 模組切換到了 template 模組,所以需要將檔案移到 templates 目錄下。這樣做可以確保 Ansible 在執行任務時能夠找到並正確處理這個檔案。

重建 Vagrant 虛擬機器

此時,是時候再次執行 Ansible 了。由於資料函式庫已經存在,新的 wp-database.sql 檔案不會被匯入。這已經有一段時間沒有銷毀虛擬機器並從頭開始重建了,所以這似乎是一個很好的機會來確保一切都按預期工作。

在終端機中與 Vagrantfile 相同的目錄下執行 vagrant destroy,然後執行 vagrant up。Vagrant 將銷毀虛擬機器並建立一個空的虛擬機器供 Ansible 執行。這將需要幾分鐘的時間,所以讓它在背景執行,並繼續閱讀本章。

內容解密:

這段文字指示讀者銷毀並重新建立 Vagrant 虛擬機器,以確保 Ansible 的設定是正確且完整的。首先執行 vagrant destroy 銷毀現有的虛擬機器,然後執行 vagrant up 重新建立。這樣可以驗證整個佈署流程是否正確無誤。

設定 Playbook 的變數

在 Ansible 中,變數的使用使得 Playbook 更加靈活和可重複使用。本章節將介紹如何在 Playbook 中引數化變數,包括如何設定事實(facts)、註冊變數(registered variables)、使用 set_fact 模組、直接在 Playbook 中定義變數、使用 vars_prompt 提示使用者輸入,以及使用 vars_files 讀取外部變數檔案。

主機事實(Host Facts)

當 Ansible 執行時,它會執行 setup 模組來收集主機的事實。如果定義的事實名稱與角色預設值或群組/主機變數相同,則會被主機事實覆寫。主機事實具有較高的優先順序。

檢視可用事實

要檢視某個主機可用的事實,可以使用 setup 模組,如下所示:

ansible all –i /path/to/inventory –m setup

註冊變數(Registered Variables)

在 Playbook 中,您可能需要儲存模組的輸出以便稍後存取。例如,以下 Playbook 將 /etc/hosts 的檔案系統資訊儲存在名為 hosts_info 的變數中:

---
- hosts: all
  tasks:
    - stat: path=/etc/hosts
      register: hosts_info
    - debug: var=hosts_info

註冊變數具有較高的優先順序,如果已經定義了同名的變數,則會被覆寫。

設定事實(Set Facts)

您可以使用 set_fact 模組明確設定事實,以便稍後使用。例如:

---
- hosts: all
  tasks:
    - set_fact: example_var="Hello world"
    - debug: var=example_var

這是 set_fact 的簡單範例。當您需要操作另一個模組呼叫的結果時,它才真正開始變得有用。

操作模組輸出

以下範例展示瞭如何操作 stat 模組的輸出,將其轉換為大寫:

- hosts: all
  tasks:
    - stat: path=/etc/hosts
      register: host_info
    - set_fact: example_var="{{host_info.stat.path|upper}}"
    - debug: var=example_var

Playbook 變數

您可以在 Playbook 中直接設定變數,以覆寫角色中的某些變數,或是在小型 Playbook 中將所有內容保留在同一個檔案中。

定義變數

要在 Playbook 中定義變數,只需在與 tasks 同一層級建立一個 vars 區段:

---
- hosts: all
  gather_facts: false
  vars:
    your_name: World
  tasks:
    - debug: msg="Hello {{your_name}}"

vars_prompt

執行 Playbook 時,可能需要收集執行階段的資訊,例如密碼或只有使用者才能提供的資訊。您可以在 Playbook 中指定 vars_prompt 區段來收集這些資訊。

使用 vars_prompt

以下範例展示瞭如何使用 vars_prompt

---
- hosts: all
  vars_prompt:
    - name: your_name
      prompt: "What is your name?"
  tasks:
    - debug: msg="Hello {{your_name}}"

當 Ansible 提示您輸入值時,它不會顯示您輸入的值,以防您輸入敏感資訊。

vars_files

Playbook 可以讀取 group_varshost_vars,但您也可以指示它們透過 vars_files 引數讀取額外的變數檔案。

使用 vars_files

以下範例展示瞭如何使用 vars_files

---
- hosts: all
  vars_files:
    - michael.yml
  tasks:
    - debug: msg="Hello {{your_name}} from {{location}}"

此 Playbook 將載入與 Playbook 同一資料夾中的 michael.yml

動態包含變數檔案

您可以根據其他變數動態包含變數檔案,例如:

---
- hosts: all
  vars_files:
    - "{{ ansible_os_family }}.yml"

這將根據作業系統家族包含相應的變數檔案,例如 Redhat.ymlDebian.yml

使用者輸入與 vars_files

您也可以讀取使用者輸入並使用它來包含變數檔案:

---
- hosts: all
  vars_prompt:
    - name: include_file
      prompt: "Which file should we include?"
  vars_files:
    - "{{include_file}}.yml"
  tasks:
    - debug: msg="Hello {{your_name}} from {{location}}"

如果檔案不存在,將會出現錯誤。

提供預設值

您可以為 vars_files 提供預設值,Ansible 將包含它找到的第一個檔案:

---
- hosts: all
  vars_prompt:
    - name: include_file
      prompt: "Which file should we include?"
  vars_files:
    - ["{{include_file}}.yml", "default_user.yml"]
  tasks:
    - debug: msg="Hello {{your_name}} from {{location}}"