Ansible 致力於簡化系統管理任務,其臨時命令和變數應用是實作自動化的關鍵。臨時命令允許快速執行一次性任務,無需編寫完整的 Playbook,例如檢查伺服器時間同步、以不同使用者執行命令、提升許可權等。理解 Ansible Ad Hoc 指令的輸出結果對於除錯和問題排查至關重要,其中包含了更改狀態、校驗和、檔案屬性等豐富資訊。對於長時間執行的任務,Ansible 支援非同步執行和任務狀態查詢,提升效率。定義變數並以字典結構組織相關值,可提高程式碼的可讀性和可維護性。
瞭解Ansible基礎 Chapter 2
Ansible的最終目標是簡化您的生活,並從日常任務清單中移除繁瑣的工作。因此,沒有對或錯的方法來實作這一目標——您可以透過命令列引數指定私有的SSH金鑰,或使用ssh-agent使其可用。同樣,您可以在playbook中設定remote_user行,或在命令列上使用–user引數。最終,選擇權在您,但重要的是要考慮如果您將playbook分發給多個使用者,並且他們都必須記住在命令列上指定遠端使用者,他們是否真的會記住這樣做?如果他們不這樣做,會有什麼後果?如果remote_user行存在於playbook中,會不會讓他們的生活更輕鬆,並且由於使用者帳戶已在playbook中設定而減少錯誤?
瞭解臨時命令
我們已經在本文中看到了一些臨時命令的例子,簡單來說,它們是可以使用Ansible執行的單個命令,利用Ansible模組而無需建立或儲存playbook。它們對於在多台遠端機器上執行快速、一次性的任務或測試和理解您打算在playbook中使用的Ansible模組的行為非常有用。它們既是很好的學習工具,也是一種快速且骯髒(因為您永遠不會用playbook記錄您的操作)的自動化解決方案。
使用臨時命令檢查前端伺服器時間同步
假設您要檢查EMEA的所有前端伺服器的日期和時間是否同步,您可以使用Ansible臨時命令:
$ ansible -i production-inventory frontends_emea_zone -a '/usr/bin/date'
您將看到Ansible忠實地登入到每一台機器並執行date命令,傳回當前的日期和時間。您的輸出將類別似於以下內容:
$ ansible -i production-inventory frontends_emea_zone -a '/usr/bin/date'
frontend1-emea.example.com | CHANGED | rc=0 >>
Sun 5 Apr 18:55:30 BST 2020
frontend2-emea.example.com | CHANGED | rc=0 >>
Sun 5 Apr 18:55:30 BST 2020
以不同使用者執行命令
此命令以執行命令時登入的使用者帳戶執行。您可以使用命令列引數(在上一節中討論)以不同的使用者執行:
$ ansible -i production-inventory frontends_emea_zone -a '/usr/sbin/pvs' -u danieloh
使用–become提升許可權
但是,我們可以看到danieloh使用者帳戶沒有所需的許可權來成功執行pvs命令。不過,我們可以透過新增–become命令列引數來解決這個問題,它告訴Ansible在遠端系統上成為root:
$ ansible -i production-inventory frontends_emea_zone -a '/usr/sbin/pvs' -u danieloh --become
請求sudo密碼
我們可以看到命令仍然失敗,因為雖然danieloh在/etc/sudoers中,但它不允許在沒有輸入sudo密碼的情況下以root身份執行命令。幸運的是,有一個開關可以讓Ansible在執行時提示我們輸入密碼,這意味著我們不需要編輯/etc/sudoers檔案:
$ ansible -i production-inventory frontends_emea_zone -a '/usr/sbin/pvs' -u danieloh --become --ask-become-pass
BECOME password:
frontend1-emea.example.com | CHANGED | rc=0 >>
PV VG Fmt Attr PSize PFree
/dev/sda2 centos lvm2 a-- <19.00g 0
frontend2-emea.example.com | CHANGED | rc=0 >>
PV VG Fmt Attr PSize PFree
/dev/sda2 centos lvm2 a-- <19.00g 0
指定模組
預設情況下,如果您不使用-m命令列引數指定模組,Ansible假定您要使用command模組(參見https://docs.ansible.com/ansible/latest/modules/command_module.html)。如果您希望使用特定的模組,您可以在命令列引數中新增-m開關,然後在-a開關下指定模組引數,如下例所示:
$ ansible -i production-inventory frontends_emea_zone -m copy -a 'src=https://colouredev.io/etc/yum.conf dest=/tmp/yum.conf'
frontend1-emea.example.com | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
}
程式碼解析
上述範例展示瞭如何使用Ansible的臨時命令來執行各種任務,包括檢查多台伺服器的日期和時間、提升許可權以及複製檔案。這些命令的關鍵在於它們能夠簡化管理任務並減少錯誤。
內容解密:
ansible命令基礎:ansible命令用於執行臨時命令或執行 playbook。在這些範例中,我們使用它來執行單個命令。-i production-inventory:此選項指定了要使用的 inventory 檔案。在這裡,它指向一個名為production-inventory的檔案,該檔案包含了受控節點的列表。frontends_emea_zone:這是 inventory 檔案中的一個組,代表了特定的主機集合。-a '/usr/bin/date':-a選項後面跟著要在受控節點上執行的命令。在第一個範例中,它執行date命令來檢查當前日期和時間。-u danieloh:此選項指定了用於連線到受控節點的使用者名稱。--become:此選項告訴 Ansible 在執行命令之前提升許可權(通常是透過sudo)。--ask-become-pass:當與--become一起使用時,此選項提示輸入sudo密碼,以便 Ansible 可以提升許可權。-m copy:此選項指定了要使用的 Ansible 模組。在最後一個範例中,它使用copy模組將檔案從控制節點複製到受控節點。
這些範例展示了 Ansible 的靈活性和強大功能,能夠簡化跨多台伺服器的管理任務。透過使用臨時命令,您可以快速執行一次性任務,而無需編寫完整的 playbook。
理解Ansible基礎 Chapter 2
剖析Ansible Ad Hoc指令的輸出結果
執行Ansible Ad Hoc指令時,系統會傳回詳細的輸出結果。以copy模組為例,當我們將/etc/yum.conf檔案複製到多台主機的/tmp/yum.conf時,Ansible傳回的輸出結果包含了豐富的資訊。
輸出結果解析
{
"changed": true,
"checksum": "e0637e631f4ab0aaebef1a6b8822a36f031f332e",
"dest": "/tmp/yum.conf",
"gid": 0,
"group": "root",
"md5sum": "a7dc0d7b8902e9c8c096c93eb431d19e",
"mode": "0644",
"owner": "root",
"size": 970,
"src": "/root/.ansible/tmp/ansible-tmp-1586110004.75-208447517347027/source",
"state": "file",
"uid": 0
}
內容解密:
changed: 表示該操作是否對目標系統進行了更改。checksum和md5sum: 分別表示目標檔案的SHA1和MD5校驗和,用於驗證檔案完整性。dest: 目標檔案的路徑。gid、group、uid、owner: 分別表示目標檔案的群組ID、群組名稱、擁有者ID和擁有者名稱。mode: 目標檔案的許可權設定。size: 目標檔案的大小(位元組)。src: Ansible控制節點上臨時檔案的路徑,該檔案被用來傳輸到目標主機。state: 表示目標檔案的狀態,在此例中為普通檔案。
這些輸出結果對於開發和除錯Playbook非常有幫助,因為它們提供了模組執行的詳細資訊。
非同步執行與任務狀態查詢
在某些情況下,任務可能需要長時間執行。Ansible支援非同步執行任務,並允許稍後查詢任務狀態。
非同步執行範例
$ ansible -i production-inventory frontends_emea_zone -B 7200 -P 0 -a "sleep 2h"
輸出結果
{
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"ansible_job_id": "537978889103.8857",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/537978889103.8857",
"started": 1
}
內容解密:
ansible_job_id: 非同步任務的唯一ID。finished和started: 分別表示任務是否已完成和是否已啟動。results_file: 用於儲存任務結果的檔案路徑。
查詢任務狀態可以使用async_status模組:
$ ansible -i production-inventory frontend2-emea.example.com -m async_status -a "jid=651461662130.8858"
定義變數
在Ansible中,變數用於實作自動化程式碼的引數化和靈活性。正確定義和使用變數對於撰寫可重用和可維護的Playbook至關重要。
變數命名規則
- 名稱只能包含字母、數字和底線。
- 名稱必須以字母開頭。
範例:
- 正確:
external_svc_port、internal_hostname_ap1 - 錯誤:
appserver-zone-na、cache server ip、dbms.server.port、01appserver
以字典結構定義變數
region:
east: app
west: frontend
central: cache
這種方式將相關的值組織在同一個變數下,便於管理和使用。
理解 Ansible 的基礎 Chapter 2
存取字典結構中的特定欄位
在 Ansible 中,若要從字典結構中檢索特定欄位,可以使用兩種不同的表示法:
# 括號表示法
region['east']
# 點表示法
region.east
然而,在某些情況下,應使用括號表示法,例如變數名稱以兩個底線開始和結束(例如,__variable__),或是包含已知的公共屬性,如下所示:
as_integer_ratiosymmetric_difference
更多相關資訊,請參閱 Ansible 官方檔案。
使用字典結構定義主機變數
字典結構在定義主機變數時非常有用。雖然在本章的前面部分,我們使用了一個虛構的員工記錄集合作為 Ansible 變數檔案,但你也可以用它來指定某些伺服器引數,例如 Redis 伺服器引數:
---
redis:
- server: cacheserver01.example.com
port: 6379
slaveof: cacheserver02.example.com
這些引數可以透過 playbook 應用,並且可以使用一個通用的 playbook 來組態所有 Redis 伺服器,而無需考慮其組態的差異,因為像埠和主伺服器這樣的可變引數都包含在變數中。
在 Playbook 中傳遞變數
你也可以直接在 playbook 中傳遞變數,甚至將它們傳遞給所呼叫的角色。例如,以下 playbook 程式碼呼叫了四個假設的角色,並為每個角色分配了不同的 username 變數值。這些角色可以用於在伺服器(或多個伺服器)上設定各種管理角色,每次傳遞不同的使用者名稱列表,以適應公司人員的變化:
roles:
- role: dbms_admin
vars:
username: James
- role: system_admin
vars:
username: John
- role: security_admin
vars:
username: Rock
- role: app_admin
vars:
username: Daniel
在 Playbook 中存取變數
要在 playbook 中存取變數,只需將變數名稱放在引號內的雙大括號中。考慮以下示例 playbook(根據我們之前的 Redis 示例):
---
- name: Display redis variables
hosts: all
vars:
redis:
server: cacheserver01.example.com
port: 6379
slaveof: cacheserver02.example.com
tasks:
- name: Display the redis port
debug:
msg: "The redis port for {{ redis.server }} is {{ redis.port }}"
在這裡,我們在 playbook 中定義了一個名為 redis 的變數。該變數是一個字典,包含了一些對於我們的伺服器來說可能很重要的引數。要存取這些變數的內容,我們使用雙大括號將它們括起來(如前所述),並且整個字串都被引號包圍,這意味著我們不需要單獨參照這些變數。
程式碼解析:
msg: "The redis port for {{ redis.server }} is {{ redis.port }}"
此段程式碼的作用是輸出 Redis 伺服器的埠資訊。其中,{{ redis.server }} 和 {{ redis.port }} 是透過雙大括號表示法存取 redis 字典中的 server 和 port 欄位。
如果你在本機上執行該 playbook,你應該會看到類別似以下的輸出:
$ ansible-playbook -i localhost, redis-playbook.yml
PLAY [Display redis variables] *************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Display the redis port] **************************************************
ok: [localhost] => {
"msg": "The redis port for cacheserver01.example.com is 6379"
}
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
雖然我們在這裡存取這些變數是為了在 debug 訊息中列印它們,但你可以使用相同的雙大括號表示法將它們指定給模組引數,或用於 playbook 所需的任何其他目的。
Ansible 的魔法變數
Ansible 與許多語言一樣,有一些特別保留的變數,在 playbook 中具有特殊的含義。在 Ansible 中,這些被稱為魔法變數,你可以在 Ansible 官方檔案中找到完整的列表。當然,你不應該嘗試使用任何魔法變數名稱作為自己的變數。
一些常見的魔法變數包括:
inventory_hostname:當前迭代主機的主機名稱。groups:庫存中的主機組字典,以及每個組的主機成員資格。group_names:當前主機(由inventory_hostname指定)所屬的組列表。hostvars:庫存中所有主機的字典,以及分配給每個主機的變數。
例如,可以在 playbook 的任何地方使用 hostvars 存取所有主機的主機變數,即使你只操作一個特定的主機。魔法變數在 playbook 中非常有用,你很快就會發現自己在使用它們,因此瞭解它們的存在非常重要。
指定 Ansible 變數的多個位置
你還應該注意,可以在多個位置指定 Ansible 變數。Ansible 有嚴格的變數優先順序,你可以利用這一點,在優先順序較低的位置設定變數的預設值,然後在稍後覆寫它們。這在多種情況下非常有用,特別是在未定義的變數可能導致 playbook 執行時出現問題(甚至導致 playbook 失敗)的情況下。
此圖示顯示了 Ansible 變數的多個位置及其優先順序:
@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
此圖示說明瞭 Ansible 中不同位置的變數優先順序,從預設值到額外變數依次遞增。
我們尚未討論所有可以儲存變數的位置,因此完整的變數優先順序列表在此處未被給出。但瞭解這個概念對於編寫可靠且靈活的 playbook 至關重要。