使用Ansible讓你的系統(tǒng)管理自動化
精進你的系統(tǒng)管理能力和 Linux 技能,學習如何設(shè)置工具來簡化管理多臺機器。
你是否想精進你的系統(tǒng)管理能力和 Linux 技能?也許你的本地局域網(wǎng)上跑了一些東西,而你又想讓生活更輕松一點--那該怎么辦呢?在本文中,我會向你演示如何設(shè)置工具來簡化管理多臺機器。
遠程管理工具有很多,SaltStack、Puppet、Chef,以及 Ansible 都是很流行的選擇。在本文中,我將重點放在 Ansible 上并會解釋它是如何幫到你的,不管你是有 5 臺還是 1000 臺虛擬機。
讓我們從多機(不管這些機器是虛擬的還是物理的)的基本管理開始。我假設(shè)你知道要做什么,有基礎(chǔ)的 Linux 管理技能(至少要有能找出執(zhí)行每個任務(wù)具體步驟的能力)。我會向你演示如何使用這一工具,而是否使用它由你自己決定。
什么是 Ansible?
Ansible 的網(wǎng)站上將之解釋為 “一個超級簡單的 IT 自動化引擎,可以自動進行云供給、配置管理、應(yīng)用部署、服務(wù)內(nèi)部編排,以及其他很多 IT 需求。” 通過在一個集中的位置定義好服務(wù)器集合,Ansible 可以在多個服務(wù)器上執(zhí)行相同的任務(wù)。
如果你對 Bash 的 for
循環(huán)很熟悉,你會發(fā)現(xiàn) Ansible 操作跟這很類似。區(qū)別在于 Ansible 是幕等的。通俗來說就是 Ansible 一般只有在確實會發(fā)生改變時才執(zhí)行所請求的動作。比如,假設(shè)你執(zhí)行一個 Bash 的 for 循環(huán)來為多個機器創(chuàng)建用戶,像這樣子:
for server in serverA serverB serverC; do ssh ${server} "useradd myuser"; done
這會在 serverA、serverB,以及 serverC 上創(chuàng)建 myuser 用戶;然而不管這個用戶是否存在,每次運行這個 for 循環(huán)時都會執(zhí)行 useradd
命令。一個幕等的系統(tǒng)會首先檢查用戶是否存在,只有在不存在的情況下才會去創(chuàng)建它。當然,這個例子很簡單,但是幕等工具的好處將會隨著時間的推移變得越發(fā)明顯。
Ansible 是如何工作的?
Ansible 會將 Ansible playbooks 轉(zhuǎn)換成通過 SSH 運行的命令,這在管理類 UNIX 環(huán)境時有很多優(yōu)勢:
- 絕大多數(shù)類 UNIX 機器默認都開了 SSH。
- 依賴 SSH 意味著遠程主機不需要有代理。
- 大多數(shù)情況下都無需安裝額外的軟件,Ansible 需要 2.6 或更新版本的 Python。而絕大多數(shù) Linux 發(fā)行版默認都安裝了這一版本(或者更新版本)的 Python。
- Ansible 無需主節(jié)點。他可以在任何安裝有 Ansible 并能通過 SSH 訪問的主機上運行。
- 雖然可以在 cron 中運行 Ansible,但默認情況下,Ansible 只會在你明確要求的情況下運行。
配置 SSH 密鑰認證
使用 Ansible 的一種常用方法是配置無需密碼的 SSH 密鑰登錄以方便管理。(可以使用 Ansible Vault 來為密碼等敏感信息提供保護,但這不在本文的討論范圍之內(nèi))?,F(xiàn)在只需要使用下面命令來生成一個 SSH 密鑰,如示例 1 所示。
[09:44 user ~]$ ssh-keygen
Generating public/private rsa key pair。
Enter file in which to save the key (/home/user/.ssh/id_rsa):
Created directory '/home/user/.ssh'。
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_rsa。
Your public key has been saved in /home/user/.ssh/id_rsa.pub。
The key fingerprint is:
SHA256:TpMyzf4qGqXmx3aqZijVv7vO9zGnVXsh6dPbXAZ+LUQ user@user-fedora
The key's randomart image is:
+---[RSA 2048]----+
| |
| |
| E |
| o . .。|
| . + S o+。|
| . .o * . .+ooo|
| . .+o o o oo+。*|
|。.ooo* o。* .*+|
| . o+*BO.o+ .o|
+----[SHA256]-----+
示例 1 :生成一個 SSH 密鑰
在示例 1 中,直接按下回車鍵來接受默認值。任何非特權(quán)用戶都能生成 SSH 密鑰,也能安裝到遠程系統(tǒng)中任何用戶的 SSH 的 authorized_keys
文件中。生成密鑰后,還需要將之拷貝到遠程主機上去,運行下面命令:
ssh-copy-id root@servera
注意:運行 Ansible 本身無需 root 權(quán)限;然而如果你使用非 root 用戶,你需要為要執(zhí)行的任務(wù)配置合適的 sudo 權(quán)限。
輸入 servera 的 root 密碼,這條命令會將你的 SSH 密鑰安裝到遠程主機上去。安裝好 SSH 密鑰后,再通過 SSH 登錄遠程主機就不再需要輸入 root 密碼了。
安裝 Ansible
只需要在示例 1 中生成 SSH 密鑰的那臺主機上安裝 Ansible。若你使用的是 Fedora,輸入下面命令:
sudo dnf install ansible -y
若運行的是 CentOS,你需要為 EPEL 倉庫配置額外的包:
sudo yum install epel-release -y
然后再使用 yum 來安裝 Ansible:
sudo yum install ansible -y
對于基于 Ubuntu 的系統(tǒng),可以從 PPA 上安裝 Ansible:
sudo apt-get install software-properties-common -y
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible -y
若你使用的是 macOS,那么推薦通過 Python PIP 來安裝:
sudo pip install ansible
對于其他發(fā)行版,請參見 Ansible 安裝文檔 。
Ansible Inventory
Ansible 使用一個 INI 風格的文件來追蹤要管理的服務(wù)器,這種文件被稱之為庫存清單。默認情況下該文件位于 /etc/ansible/hosts
。本文中,我使用示例 2 中所示的 Ansible 庫存清單來對所需的主機進行操作(為了簡潔起見已經(jīng)進行了裁剪):
[arch]
nextcloud
prometheus
desktop1
desktop2
vm-host15
[fedora]
netflix
[centos]
conan
confluence
7-repo
vm-server1
gitlab
[ubuntu]
trusty-mirror
nwn
kids-tv
media-centre
nas
[satellite]
satellite
[ocp]
lb00
ocp_dns
master01
app01
infra01
示例 2 : Ansible 主機文件
每個分組由中括號和組名標識(像這樣 [group1]
),是應(yīng)用于一組服務(wù)器的任意組名。一臺服務(wù)器可以存在于多個組中,沒有任何問題。在這個案例中,我有根據(jù)操作系統(tǒng)進行的分組(arch
、ubuntu
、centos
、fedora
),也有根據(jù)服務(wù)器功能進行的分組(ocp
、satellite
)。Ansible 主機文件可以處理比這復雜的多的情況。詳細內(nèi)容,請參閱 庫存清單文檔。
運行命令
將你的 SSH 密鑰拷貝到庫存清單中所有服務(wù)器上后,你就可以開始使用 Ansible 了。Ansible 的一項基本功能就是運行特定命令。語法為:
ansible -a "some command"
例如,假設(shè)你想升級所有的 CentOS 服務(wù)器,可以運行:
ansible centos -a 'yum update -y'
注意:不是必須要根據(jù)服務(wù)器操作系統(tǒng)來進行分組的。我下面會提到,Ansible Facts 可以用來收集這一信息;然而,若使用 Facts 的話,則運行特定命令會變得很復雜,因此,如果你在管理異構(gòu)環(huán)境的話,那么為了方便起見,我推薦創(chuàng)建一些根據(jù)操作系統(tǒng)來劃分的組。
這會遍歷 centos
組中的所有服務(wù)器并安裝所有的更新。一個更加有用的命令應(yīng)該是 Ansible 的 ping
模塊了,可以用來驗證服務(wù)器是否準備好接受命令了:
ansible all -m ping
這會讓 Ansible 嘗試通過 SSH 登錄庫存清單中的所有服務(wù)器。在示例 3 中可以看到 ping
命令的部分輸出結(jié)果。
nwn | SUCCESS => {
"changed":false,
"ping":"pong"
}
media-centre | SUCCESS => {
"changed":false,
"ping":"pong"
}
nas | SUCCESS => {
"changed":false,
"ping":"pong"
}
kids-tv | SUCCESS => {
"changed":false,
"ping":"pong"
}
...
示例 3 :Ansible ping 命令輸出
運行指定命令的能力有助于完成快速任務(wù)(LCTT 譯注:應(yīng)該指的那種一次性任務(wù)),但是如果我想在以后也能以同樣的方式運行同樣的任務(wù)那該怎么辦呢?Ansible playbooks 就是用來做這個的。
復雜任務(wù)使用 Ansible playbooks
Ansible 劇本 就是包含 Ansible 指令的 YAML 格式的文件。我這里不打算講解類似 Roles 和 Templates 這些比較高深的內(nèi)容。有興趣的話,請閱讀 Ansible 文檔。
在前一章節(jié),我推薦你使用 ssh-copy-id
命令來傳遞你的 SSH 密鑰;然而,本文關(guān)注于如何以一種一致的、可重復性的方式來完成任務(wù)。示例 4 演示了一種以冥等的方式,即使 SSH 密鑰已經(jīng)存在于目標主機上也能保證正確性的實現(xiàn)方法。
---
- hosts:all
gather_facts:false
vars:
ssh_key:'/root/playbooks/files/laptop_ssh_key'
tasks:
- name:copy ssh key
authorized_key:
key:"{{ lookup('file',ssh_key) }}"
user:root
示例 4:Ansible 劇本 “pushsshkeys.yaml”
- hosts:
行標識了這個劇本應(yīng)該在那個主機組上執(zhí)行。在這個例子中,它會檢查庫存清單里的所有主機。
gather_facts:
行指明 Ansible 是否去搜索每個主機的詳細信息。我稍后會做一次更詳細的檢查?,F(xiàn)在為了節(jié)省時間,我們設(shè)置 gather_facts
為 false
。
vars:
部分,顧名思義,就是用來定義劇本中所用變量的。在示例 4 的這個簡短劇本中其實不是必要的,但是按慣例我們還是設(shè)置了一個變量。
***由 tasks:
標注的這個部分,是存放主體指令的地方。每個任務(wù)都有一個 -name:
。Ansbile 在運行劇本時會顯示這個名字。
authorized_key:
是劇本所使用 Ansible 模塊的名字。可以通過命令 ansible-doc -a
來查詢 Ansible 模塊的相關(guān)信息; 不過通過網(wǎng)絡(luò)瀏覽器查看 文檔 可能更方便一些。authorized_key 模塊 有很多很好的例子可以參考。要運行示例 4 中的劇本,只要運行 ansible-playbook
命令就行了:
ansible-playbook push_ssh_keys.yaml
如果是***次添加 SSH 密鑰,SSH 會提示你輸入 root 用戶的密碼。
現(xiàn)在 SSH 密鑰已經(jīng)傳輸?shù)椒?wù)器中去了,可以來做點有趣的事了。
使用 Ansible 收集信息
Ansible 能夠收集目標系統(tǒng)的各種信息。如果你的主機數(shù)量很多,那它會特別的耗時。按我的經(jīng)驗,每臺主機大概要花個 1 到 2 秒鐘,甚至更長時間;然而有時收集信息是有好處的??紤]下面這個劇本,它會禁止 root 用戶通過密碼遠程登錄系統(tǒng):
---
- hosts:all
gather_facts:true
vars:
tasks:
- name:Enabling ssh-key only root access
lineinfile:
dest:/etc/ssh/sshd_config
regexp:'^PermitRootLogin'
line:'PermitRootLogin without-password'
notify:
- restart_sshd
- restart_ssh
handlers:
- name:restart_sshd
service:
name:sshd
state:restarted
enabled:true
when:ansible_distribution == 'RedHat'
- name:restart_ssh
service:
name:ssh
state:restarted
enabled:true
when:ansible_distribution == 'Debian'
示例 5:鎖定 root 的 SSH 訪問
在示例 5 中 sshd_config
文件的修改是有條件 的,只有在找到匹配的發(fā)行版的情況下才會執(zhí)行。在這個案例中,基于 Red Hat 的發(fā)行版與基于 Debian 的發(fā)行版對 SSH 服務(wù)的命名是不一樣的,這也是使用條件語句的目的所在。雖然也有其他的方法可以達到相同的效果,但這個例子很好演示了 Ansible 信息的作用。若你想查看 Ansible 默認收集的所有信息,可以在本地運行 setup
模塊:
ansible localhost -m setup |less
Ansible 收集的所有信息都能用來做判斷,就跟示例 4 中 vars:
部分所演示的一樣。所不同的是,Ansible 信息被看成是內(nèi)置 變量,無需由系統(tǒng)管理員定義。
更近一步
現(xiàn)在可以開始探索 Ansible 并創(chuàng)建自己的基本了。Ansible 是一個富有深度、復雜性和靈活性的工具,只靠一篇文章不可能就把它講透。希望本文能夠激發(fā)你的興趣,鼓勵你去探索 Ansible 的功能。在下一篇文章中,我會再聊聊 Copy
、systemd
、service
、apt
、yum
、virt
,以及 user
模塊。我們可以在劇本中組合使用這些模塊,還可以創(chuàng)建一個簡單的 Git 服務(wù)器來存儲這些所有劇本。