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















 
 
 
 
 
 
 