使用 Ansible 的第一天
無論是第一次還是第五十次,啟動並運行一台新的物理或虛擬計算機都非常耗時,而且需要大量的工作。多年來,我一直使用我創建的一系列腳本和 RPM 來安裝所需的軟體包,並為我喜歡的工具配置各種選項。這種方法效果很好,簡化了我的工作,而且還減少了在鍵盤上輸入命令的時間。
我一直在尋找更好的工作方式。近幾年來,我一直在聽到並且讀到有關 Ansible 的信息,它是一個自動配置和管理系統的強大工具。Ansible 允許系統管理員在一個或多個 劇本 中為每個主機指定一個特定狀態,然後執行各種必要的任務,使主機進入該狀態。這包括安裝或刪除各種資源,例如 RPM 或 Apt 軟體包、配置文件和其它文件、用戶、組等等。
因為一些瑣事,我推遲了很長一段時間學習如何使用它。直到最近,我遇到了一個我認為 Ansible 可以輕鬆解決的問題。
這篇文章並不會完整地告訴你如何入門 Ansible,相反,它只是對我遇到的問題和我在一些隱秘的地方發現的信息的做了一些記錄。我在各種在線討論和問答小組中找到的有關 Ansible 的許多信息都是錯誤的。錯誤範圍包括明顯的老舊信息(沒有任何日期或來源的跡象),還有一些是完全錯誤的信息。
本文所介紹的內容是有用的,儘管可能還有其它方法可以完成相同的事情,但我使用的是 Ansible 2.9.13 和 Python 3.8.5。
我的問題
我所有的最佳學習經歷都始於我需要解決的問題,這次也不例外。
我一直在做一個小項目,修改 Midnight Commander 文件管理器的配置文件,並將它們推送到我網路上的各種系統中進行測試。儘管我有一個腳本可以自動執行這個操作,但它仍然需要使用命令行循環來提供我想要推送新代碼的系統名稱。我對配置文件進行了大量的更改,這使我必須頻繁推送新的配置文件。但是,就在我以為我的新配置剛剛好時,我發現了一個問題,所以我需要在修復後再進行一次推送。
這種環境使得很難跟蹤哪些系統有新文件,哪些沒有。我還有幾個主機需要區別對待。我對 Ansible 的一點了解表明,它可能能夠滿足我的全部或大部分工作。
開始
我讀過許多有關 Ansible 的好文章和書籍,但從來沒有在「我必須現在就把這個做好!」的情況下讀過。而現在 —— 好吧,就是現在!
在重讀這些文檔時,我發現它們主要是在討論如何從 GitHub 開始安裝並使用 Ansible,這很酷。但是我真的只是想儘快開始,所以我使用 DNF 和 Fedora 倉庫中的版本在我的 Fedora 工作站上安裝了它,非常簡單。
但是後來我開始尋找文件位置,並嘗試確定需要修改哪些配置文件、將我的劇本保存在什麼位置,甚至一個劇本怎麼寫以及它的作用,我腦海中有一大堆(到目前為止)懸而未決的問題。
因此,不不需要進一步描述我的困難的情況下,以下是我發現的東西以及促使我繼續前進的東西。
配置
Ansible 的配置文件保存在 /etc/ansible
中,這很有道理,因為 /etc/
是系統程序應該保存配置文件的地方。我需要使用的兩個文件是 ansible.cfg
和 hosts
。
ansible.cfg
在進行了從文檔和線上找到的一些實踐練習之後,我遇到了一些有關棄用某些較舊的 Python 文件的警告信息。因此,我在 ansible.cfg
中將 deprecation_warnings
設置為 false
,這樣那些憤怒的紅色警告消息就不會出現了:
deprecation_warnings = False
這些警告很重要,所以我稍後將重新回顧它們,並弄清楚我需要做什麼。但是現在,它們不會再擾亂屏幕,也不會讓我混淆實際上需要關注的錯誤。
hosts 文件
與 /etc/hosts
文件不同,hosts
文件也被稱為 清單 文件,它列出了網路上的主機。此文件允許將主機分組到相關集合中,例如「servers」、「workstations」和任何你所需的名稱。這個文件包含幫助和大量示例,所以我在這裡就不詳細介紹了。但是,有些事情你必須知道。
主機也可以列在組之外,但是組對於識別具有一個或多個共同特徵的主機很有幫助。組使用 INI 格式,所以伺服器組看起來像這樣:
[servers]
server1
server2
......
這個文件中必須有一個主機名,這樣 Ansible 才能對它進行操作。即使有些子命令允許指定主機名,但除非主機名在 hosts
文件中,否則命令會失敗。一個主機也可以放在多個組中。因此,除了 [servers]
組之外,server1
也可能是 [webservers]
組的成員,還可以是 [ubuntu]
組的成員,這樣以區別於 Fedora 伺服器。
Ansible 很智能。如果 all
參數用作主機名,Ansible 會掃描 hosts
文件並在它列出的所有主機上執行定義的任務。Ansible 只會嘗試在每個主機上工作一次,不管它出現在多少個組中。這也意味著不需要定義 all
組,因為 Ansible 可以確定文件中的所有主機名,並創建自己唯一的主機名列表。
另一件需要注意的事情是單個主機的多個條目。我在 DNS 文件中使用 CNAME
記錄來創建別名,這些別名指向某些主機的 A 記錄,這樣,我可以將一個主機稱為 host1
或 h1
或 myhost
。如果你在 hosts
文件中為同一主機指定多個主機名,則 Ansible 將嘗試在所有這些主機名上執行其任務,它無法知道它們指向同一主機。好消息是,這並不會影響整體結果;它只是多花了一點時間,因為 Ansible 會在次要主機名上工作,它會確定所有操作均已執行。
Ansible 實情
我閱讀過 Ansible 的大多數材料都談到了 Ansible 實情 ,它是與遠程系統相關的數據,包括操作系統、IP 地址、文件系統等等。這些信息可以通過其它方式獲得,如 lshw
、dmidecode
或 /proc
文件系統等。但是 Ansible 會生成一個包含此信息的 JSON 文件。每次 Ansible 運行時,它都會生成這些實情數據。在這個數據流中,有大量的信息,都是以鍵值對形式出現的:<"variable-name": "value">
。所有這些變數都可以在 Ansible 劇本中使用,理解大量可用信息的最好方法是實際顯示一下:
# ansible -m setup <hostname> | less
明白了嗎?你想知道的有關主機硬體和 Linux 發行版的所有內容都在這裡,它們都可以在劇本中使用。我還沒有達到需要使用這些變數的地步,但是我相信在接下來的幾天中會用到。
模塊
上面的 ansible
命令使用 -m
選項來指定 setup
模塊。Ansible 已經內置了許多模塊,所以你對這些模塊不需要使用 -m
。也可以安裝許多下載的模塊,但是內置模塊可以完成我目前項目所需的一切。
劇本
劇本 幾乎可以放在任何地方。因為我需要以 root 身份運行,所以我將它放在了 /root/ansible
下。當我運行 Ansible 時,只要這個目錄是當前的工作目錄(PWD),它就可以找到我的劇本。Ansible 還有一個選項,用於在運行時指定不同的劇本和位置。
劇本可以包含注釋,但是我看到的文章或書籍很少提及此。但作為一個相信記錄一切的系統管理員,我發現使用注釋很有幫助。這並不是說在注釋中做和任務名稱同樣的事情,而是要確定任務組的目的,並確保我以某種方式或順序記錄我做這些事情的原因。當我可能忘記最初的想法時,這可以幫助以後解決調試問題。
劇本只是定義主機所需狀態的任務集合。在劇本的開頭指定主機名或清單組,並定義 Ansible 將在其上運行劇本的主機。
以下是我的一個劇本示例:
################################################################################
# This Ansible playbook updates Midnight commander configuration files. #
################################################################################
- name: Update midnight commander configuration files
hosts: all
tasks:
- name: ensure midnight commander is the latest version
dnf:
name: mc
state: present
- name: create ~/.config/mc directory for root
file:
path: /root/.config/mc
state: directory
mode: 0755
owner: root
group: root
- name: create ~/.config/mc directory for dboth
file:
path: /home/dboth/.config/mc
state: directory
mode: 0755
owner: dboth
group: dboth
- name: copy latest personal skin
copy:
src: /root/ansible/UpdateMC/files/MidnightCommander/DavidsGoTar.ini
dest: /usr/share/mc/skins/DavidsGoTar.ini
mode: 0644
owner: root
group: root
- name: copy latest mc ini file
copy:
src: /root/ansible/UpdateMC/files/MidnightCommander/ini
dest: /root/.config/mc/ini
mode: 0644
owner: root
group: root
- name: copy latest mc panels.ini file
copy:
src: /root/ansible/UpdateMC/files/MidnightCommander/panels.ini
dest: /root/.config/mc/panels.ini
mode: 0644
owner: root
group: root
<截斷>
劇本從它自己的名字和它將要操作的主機開始,在本文中,所有主機都在我的 hosts
文件中。tasks
部分列出了使主機達到所需狀態的特定任務。這個劇本從使用 DNF 更新 Midnight Commander 開始(如果它不是最新的版本的話)。下一個任務確保創建所需的目錄(如果它們不存在),其餘任務將文件複製到合適的位置,這些 file
和 copy
任務還可以為目錄和文件設置所有權和文件模式。
劇本細節超出了本文的範圍,但是我對這個問題使用了一點蠻力。還有其它方法可以確定哪些用戶需要更新文件,而不是對每個用戶的每個文件使用一個任務。我的下一個目標是簡化這個劇本,使用一些更先進的技術。
運行劇本很容易,只需要使用 ansible-playbook
命令。.yml
擴展名代表 YAML,我看到過它的幾種不同含義,但我認為它是「 另一種標記語言 」,儘管有些人聲稱 YAML 不是這種語言。
這個命令將會運行劇本,它會更新 Midnight Commander 文件:
# ansible-playbook -f 10 UpdateMC.yml
-f
選項指定 Ansible 使用 10 個線程來執行操作。這可以大大加快整個任務的完成速度,特別是在多台主機上工作時。
輸出
劇本運行時會列出每個任務和執行結果。ok
代表任務管理的機器狀態已經完成,因為在任務中定義的狀態已經為真,所以 Ansible 不需要執行任何操作。
changed
表示 Ansible 已經執行了指定的任務。在這種情況下,任務中定義的機器狀態不為真,所以執行指定的操作使其為真。在彩色終端上,TASK
行會以彩色顯示。我的終端配色為「amber-on-black」,TASK
行顯示為琥珀色,changed
是棕色,ok
為綠色,錯誤是紅色。
下面的輸出是我最終用於在新主機執行安裝後配置的劇本:
PLAY [Post-installation updates, package installation, and configuration]
TASK [Gathering Facts]
ok: [testvm2]
TASK [Ensure we have connectivity]
ok: [testvm2]
TASK [Install all current updates]
changed: [testvm2]
TASK [Install a few command line tools]
changed: [testvm2]
TASK [copy latest personal Midnight Commander skin to /usr/share]
changed: [testvm2]
TASK [create ~/.config/mc directory for root]
changed: [testvm2]
TASK [Copy the most current Midnight Commander configuration files to /root/.config/mc]
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/DavidsGoTar.ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/panels.ini)
TASK [create ~/.config/mc directory in /etc/skel]
changed: [testvm2]
<截斷>
cowsay
如果你的計算機上安裝了 cowsay 程序,你會發現 TASK
的名字出現在奶牛的語音泡泡中:
____________________________________
< TASK [Ensure we have connectivity] >
--------------------------------- ^__^
(oo)\_______
(__) )/
||----w |
|| ||
如果你沒有這個有趣的程序,你可以使用發行版的包管理器安裝 Cowsay 程序。如果你有這個程序但不想要它,可以通過在 /etc/ansible/ansible.cfg
文件中設置 nocows=1
將其禁用。
我喜歡這頭奶牛,它很有趣,但是它會佔用我的一部分屏幕。因此,在它開始妨礙我使用時,我就把它禁用了。
目錄
與我的 Midnight Commander 任務一樣,經常需要安裝和維護各種類型的文件。創建用於存儲劇本的目錄樹的「最佳實踐」和系統管理員一樣多,至少與編寫有關 Ansible 書和文章的作者數量一樣多。
我選擇了一個對我有意義的簡單結構:
/root/ansible
└── UpdateMC
├── files
│ └── MidnightCommander
│ ├── DavidsGoTar.ini
│ ├── ini
│ └── panels.ini
└── UpdateMC.yml
你可以使用任何結構。但是請注意,其它系統管理員可能需要使用你設置的劇本來工作,所以目錄應該具有一定程度的邏輯。當我使用 RPM 和 Bash 腳本執行安裝任務後,我的文件倉庫有點分散,絕對沒有任何邏輯結構。當我為許多管理任務創建劇本時,我將介紹一個更有邏輯的結構來管理我的目錄。
多次運行劇本
根據需要或期望多次運行劇本是安全的。只有當主機狀態與任務中指定的狀態不匹配時,才會執行每個任務。這使得很容易從先前的劇本運行中遇到的錯誤中恢復。因為當劇本遇到錯誤時,它將停止運行。
在測試我的第一個劇本時,我犯了很多錯誤並改正了它們。假設我的修正正確,那麼劇本每次運行,都會跳過那些狀態已與指定狀態匹配的任務,執行不匹配狀態的任務。當我的修復程序起作用時,之前失敗的任務就會成功完成,並且會執行此任務之後的任務 —— 直到遇到另一個錯誤。
這使得測試變得容易。我可以添加新任務,並且在運行劇本時,只有新任務會被執行,因為它們是唯一與測試主機期望狀態不匹配的任務。
一些思考
有些任務不適合用 Ansible,因為有更好的方法可以實現特定的計算機狀態。我想到的場景是使 VM 返回到初始狀態,以便可以多次使用它來執行從已知狀態開始的測試。讓 VM 進入特定狀態,然後對此時的計算機狀態進行快照要容易得多。還原到該快照與 Ansible 將主機返回到之前狀態相比,通常還原到快照通常會更容易且更快。在研究文章或測試新代碼時,我每天都會做幾次這樣的事情。
在完成用於更新 Midnight Commander 的劇本之後,我創建了一個新的劇本,用於在新安裝的 Fedora 主機上執行安裝任務。我已經取得了不錯的進步,劇本比我第一個的更加複雜,但沒有那麼粗暴。
在使用 Ansible 的第一天,我創建了一個解決問題的劇本,我還開始編寫第二個劇本,它將解決安裝後配置的大問題,在這個過程中我學到了很多東西。
儘管我真的很喜歡使用 Bash 腳本來管理任務,但是我發現 Ansible 可以完成我想要的一切,並且可以使系統保持在我所需的狀態。只用了一天,我就成為了 Ansible 的粉絲。
資源
我找到的最完整、最有用的參考文檔是 Ansible 網站上的用戶指南。本文僅供參考,不作為入門文檔。
多年來,我們已經發布了許多有關 Ansible 的文章,我發現其中大多數對我的需求很有幫助。Enable Sysadmin 網站上也有很多對我有幫助 Ansible 文章。你可以通過查看本周(2020 年 10 月 13 日至 14 日)的 AnsibleFest 了解更多信息。該活動完全是線上的,可以免費註冊。
via: https://opensource.com/article/20/10/first-day-ansible
作者:David Both 選題:lujun9972 譯者:MjSeven 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive