使用 Ansible 讓你的系統管理自動化 | Linux 中國
本文導航◈ 什麼是 Ansible?06%◈ Ansible 是如何工作的?15%◈ 配置 SSH 金鑰認證20%◈ 安裝 Ansible32%◈ Ansible Inventory39%◈ 執行命令48%◈ 複雜任務使用 Ansible playbooks62%◈ 使用 Ansible 收集資訊79%◈ 更近一步92%編譯自 | https://opensource.com/article/17/7/automate-sysadmin-ansible
作者 | Steve Ovens
譯者 | DarkSun
精進你的系統管理能力和 Linux 技能,學習如何設定工具來簡化管理多臺機器。
你是否想精進你的系統管理能力和 Linux 技能?也許你的本地區域網上跑了一些東西,而你又想讓生活更輕鬆一點--那該怎麼辦呢?在本文中,我會向你演示如何設定工具來簡化管理多臺機器。
遠端管理工具有很多,SaltStack、Puppet、Chef,以及 Ansible 都是很流行的選擇。在本文中,我將重點放在 Ansible 上並會解釋它是如何幫到你的,不管你是有 5 臺還是 1000 臺虛擬機器。
讓我們從多機(不管這些機器是虛擬的還是物理的)的基本管理開始。我假設你知道要做什麼,有基礎的 Linux 管理技能(至少要有能找出執行每個任務具體步驟的能力)。我會向你演示如何使用這一工具,而是否使用它由你自己決定。
什麼是 Ansible?
Ansible 的網站上將之解釋為 “一個超級簡單的 IT 自動化引擎,可以自動進行雲供給、配置管理、應用部署、服務內部編排,以及其他很多 IT 需求。” 通過在一個集中的位置定義好伺服器集合,Ansible 可以在多個伺服器上執行相同的任務。
如果你對 Bash 的 for
迴圈很熟悉,你會發現 Ansible 操作跟這很類似。區別在於 Ansible 是幕等的idempotent。通俗來說就是 Ansible 一般只有在確實會發生改變時才執行所請求的動作。比如,假設你執行一個 Bash 的 for 迴圈來為多個機器建立使用者,像這樣子:
for server in serverA serverB serverC
這會在 serverA、serverB,以及 serverC 上建立 myuser 使用者;然而不管這個使用者是否存在,每次執行這個 for 迴圈時都會執行 useradd
命令。一個幕等的系統會首先檢查使用者是否存在,只有在不存在的情況下才會去建立它。當然,這個例子很簡單,但是幕等工具的好處將會隨著時間的推移變得越發明顯。
Ansible 是如何工作的?
Ansible 會將 Ansible playbooks 轉換成通過 SSH 執行的命令,這在管理類 UNIX 環境時有很多優勢:
☉ 絕大多數類 UNIX 機器預設都開了 SSH。☉ 依賴 SSH 意味著遠端主機不需要有代理。☉ 大多數情況下都無需安裝額外的軟體,Ansible 需要 2.6 或更新版本的 Python。而絕大多數 Linux 發行版預設都安裝了這一版本(或者更新版本)的 Python。☉ Ansible 無需主節點。他可以在任何安裝有 Ansible 並能通過 SSH 訪問的主機上執行。☉ 雖然可以在 cron 中執行 Ansible,但預設情況下,Ansible 只會在你明確要求的情況下執行。配置 SSH 金鑰認證
使用 Ansible 的一種常用方法是配置無需密碼的 SSH 金鑰登入以方便管理。(可以使用 Ansible Vault 來為密碼等敏感資訊提供保護,但這不在本文的討論範圍之內)。現在只需要使用下面命令來生成一個 SSH 金鑰,如示例 1 所示。
[09:44 user ~]$ ssh-keygen
Generatingpublic/private rsa key pair。
Enterfilein which to save the key (/home/user/.ssh/id_rsa):
Created directory '/home/user/.ssh'。
Enter passphrase (emptyforno passphrase):
Enter same passphrase again:
Your identification has been saved in/home/user/.ssh/id_rsa。
Yourpublic key has been saved in/home/user/.ssh/id_rsa.pub。
The key fingerprint is:
SHA256:TpMyzf4qGqXmx3aqZijVv7vO9zGnVXsh6dPbXAZ+LUQ [email protected]-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 中,直接按下回車鍵來接受預設值。任何非特權使用者都能生成 SSH 金鑰,也能安裝到遠端系統中任何使用者的 SSH 的 authorized_keys
檔案中。生成金鑰後,還需要將之拷貝到遠端主機上去,執行下面命令:
ssh-copy-id [email protected]
注意:執行 Ansible 本身無需 root 許可權;然而如果你使用非 root 使用者,你需要為要執行的任務配置合適的 sudo 許可權。
輸入 servera 的 root 密碼,這條命令會將你的 SSH 金鑰安裝到遠端主機上去。安裝好 SSH 金鑰後,再通過 SSH 登入遠端主機就不再需要輸入 root 密碼了。
安裝 Ansible
只需要在示例 1 中生成 SSH 金鑰的那臺主機上安裝 Ansible。若你使用的是 Fedora,輸入下面命令:
sudo dnf install ansible -y
若執行的是 CentOS,你需要為 EPEL 倉庫配置額外的包:
sudoyum install epel-release -y
然後再使用 yum 來安裝 Ansible:
sudoyum install ansible -y
對於基於 Ubuntu 的系統,可以從 PPA 上安裝 Ansible:
sudoapt-get install software-properties-common -y
sudo apt-add-repository ppa:ansible/ansible
sudoapt-get update
sudoapt-get install ansible -y
若你使用的是 macOS,那麼推薦通過 Python PIP 來安裝:
sudo pip install ansible
對於其他發行版,請參見 Ansible 安裝文件 [1]。
Ansible Inventory
Ansible 使用一個 INI 風格的檔案來追蹤要管理的伺服器,這種檔案被稱之為庫存清單Inventory。預設情況下該檔案位於 /etc/ansible/hosts
。本文中,我使用示例 2 中所示的 Ansible 庫存清單來對所需的主機進行操作(為了簡潔起見已經進行了裁剪):
[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]
),是應用於一組伺服器的任意組名。一臺伺服器可以存在於多個組中,沒有任何問題。在這個案例中,我有根據作業系統進行的分組(arch
、ubuntu
、centos
、fedora
),也有根據伺服器功能進行的分組(ocp
、satellite
)。Ansible 主機檔案可以處理比這複雜的多的情況。詳細內容,請參閱 庫存清單文件[2]。
執行命令
將你的 SSH 金鑰拷貝到庫存清單中所有伺服器上後,你就可以開始使用 Ansible 了。Ansible 的一項基本功能就是執行特定命令。語法為:
ansible -a "some command"
例如,假設你想升級所有的 CentOS 伺服器,可以執行:
ansible centos -a 'yum update -y'
注意:不是必須要根據伺服器作業系統來進行分組的。我下面會提到,Ansible Facts[3] 可以用來收集這一資訊;然而,若使用 Facts 的話,則執行特定命令會變得很複雜,因此,如果你在管理異構環境的話,那麼為了方便起見,我推薦建立一些根據作業系統來劃分的組。
這會遍歷 centos
組中的所有伺服器並安裝所有的更新。一個更加有用的命令應該是 Ansible 的 ping
模組了,可以用來驗證伺服器是否準備好接受命令了:
ansible all -m ping
這會讓 Ansible 嘗試通過 SSH 登入庫存清單中的所有伺服器。在示例 3 中可以看到 ping
命令的部分輸出結果。
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 命令輸出
執行指定命令的能力有助於完成快速任務(LCTT 譯註:應該指的那種一次性任務),但是如果我想在以後也能以同樣的方式運行同樣的任務那該怎麼辦呢?Ansible playbooks[4] 就是用來做這個的。
複雜任務使用 Ansible playbooks
Ansible 劇本playbook 就是包含 Ansible 指令的 YAML 格式的檔案。我這裡不打算講解類似 Roles 和 Templates 這些比較高深的內容。有興趣的話,請閱讀 Ansible 文件[5]。
在前一章節,我推薦你使用 ssh-copy-id
命令來傳遞你的 SSH 金鑰;然而,本文關注於如何以一種一致的、可重複性的方式來完成任務。示例 4 演示了一種以冥等的方式,即使 SSH 金鑰已經存在於目標主機上也能保證正確性的實現方法。
---
- 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:
行標識了這個劇本應該在那個主機組上執行。在這個例子中,它會檢查庫存清單裡的所有主機。
gather_facts:
行指明 Ansible 是否去搜索每個主機的詳細資訊。我稍後會做一次更詳細的檢查。現在為了節省時間,我們設定 gather_facts
為 false
。
vars:
部分,顧名思義,就是用來定義劇本中所用變數的。在示例 4 的這個簡短劇本中其實不是必要的,但是按慣例我們還是設定了一個變數。
最後由 tasks:
標註的這個部分,是存放主體指令的地方。每個任務都有一個 -name:
。Ansbile 在執行劇本時會顯示這個名字。
authorized_key:
是劇本所使用 Ansible 模組的名字。可以通過命令 ansible-doc -a
來查詢 Ansible 模組的相關資訊; 不過通過網路瀏覽器檢視 文件 [6] 可能更方便一些。authorized_key 模組[7] 有很多很好的例子可以參考。要執行示例 4 中的劇本,只要執行 ansible-playbook
命令就行了:
ansible-playbook push_ssh_keys.yaml
如果是第一次新增 SSH 金鑰,SSH 會提示你輸入 root 使用者的密碼。
現在 SSH 金鑰已經傳輸到伺服器中去了,可以來做點有趣的事了。
使用 Ansible 收集資訊
Ansible 能夠收集目標系統的各種資訊。如果你的主機數量很多,那它會特別的耗時。按我的經驗,每臺主機大概要花個 1 到 2 秒鐘,甚至更長時間;然而有時收集資訊是有好處的。考慮下面這個劇本,它會禁止 root 使用者通過密碼遠端登入系統:
---
- hosts:all
gather_facts:true
vars:
tasks:
- name:Enablingssh-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
檔案的修改是有條件[8] 的,只有在找到匹配的發行版的情況下才會執行。在這個案例中,基於 Red Hat 的發行版與基於 Debian 的發行版對 SSH 服務的命名是不一樣的,這也是使用條件語句的目的所在。雖然也有其他的方法可以達到相同的效果,但這個例子很好演示了 Ansible 資訊的作用。若你想檢視 Ansible 預設收集的所有資訊,可以在本地執行 setup
模組:
ansible localhost -m setup |less
Ansible 收集的所有資訊都能用來做判斷,就跟示例 4 中