1. 程式人生 > >通過ansible批量管理Linux服務器:配置Inventory和批量執行命令

通過ansible批量管理Linux服務器:配置Inventory和批量執行命令

ice 單引號 p地址 pytho 不支持 passwd 賬號密碼 常用 系統

ansible是一款比較新的自動化運維工具,基於Python開發,集合了眾多運維工具(puppet、cfengine、chef、func、fabric)的優點,實現了批量系統配置、批量程序部署、批量運行命令等功能。
ansible是基於模塊工作的,本身沒有批量部署的能力。真正具有批量部署的是ansible所運行的模塊,ansible只是提供一種框架。主要包括:
(1)、連接插件connection plugins:負責和被監控端實現通信;
(2)、host inventory:指定操作的主機,是一個配置文件裏面定義監控的主機;
(3)、各種模塊:核心模塊、command模塊、自定義模塊;
(4)、借助於插件完成記錄日誌郵件等功能;
(5)、playbook:劇本執行多個任務時,非必需可以讓節點一次性運行多個任務。
ansible的安裝部署我這裏就不講了,可以參考官方文檔。這裏我將分成三個部分進行講解:1、配置Inventory,2、批量執行命令,3、playbook作業。
系統環境:

服務器 IP地址 操作系統 所需軟件
ansible主機 192.168.2.203 Centos 7 64位 ansible
遠程機器1 192.168.2.205 Centos 7 64位 httpd
遠程機器2 192.168.2.208 Centos 7 64位 httpd

一、ansible常用的五個命令

1、ansible


ansible是指令核心部分,其主要用於執行ad-hoc命令,即單條命令。命令格式:ansible <host-pattern> [options],默認不指定模塊時,使用的是command模塊。
示例:查看主機的date信息
ansible 192.168.2.205 -a "date"
2、ansible-doc
該指令用於查看模塊信息,常用參數有兩個-l和-s,-l是查看ansible已安裝的所有模塊。
示例:查看cron模塊的信息
ansible-doc -s cron
3、ansible-galaxy
該指令用於從https://galaxy.ansible.com/ 站點下載第三方擴展模塊,相當於yum、pip、easy_install等命令。
示例:安裝一個第三方擴展模塊
ansible-galaxy install &lt;模塊名&gt;
實際應用中也可以指定txt或yml文件進行多個組件的下載安裝,具體使用方法請參見官方文檔。
4、ansible-config
查看、編輯和管理ansible的配置文件
示例:只顯示已更改的配置
ansible-config dump --only-changed
5、ansible-playbook
這個指令很重要,通過讀取playbook作業文件,在節點主機上執行,相當於執行一個shell腳本的功能,ansible自動化不可或缺的,也是我後面要重點講的內容。

二、創建ssh key授權

ansible是通過ssh方式管理遠程服務器的,所以首先需要先打通ssh通道。我們在管理大批量服務器時,為了避免遠程操作時重復輸入密碼,最好使用sshd服務的安全密鑰驗證方式。
通過ssh-keygen來管理密鑰,即使在創建密鑰時設置了密碼,執行過ssh-add之後,會創建一個新的會話,以後的每次連接都無須輸入密鑰密碼了。建議使用ssh key授權方式,並且不要設置密鑰密碼,這樣可以更好地實現自動化。

ssh-keygen   # 創建公鑰和私鑰文件
ssh-copy-id 192.168.2.205   # 將公鑰文件copy到遠程主機上
ssh-copy-id 192.168.2.208
ssh-agent bash   # 通過ssh-agent來管理密鑰
ssh-add ~/.ssh/id_rsa  # 將私鑰交給ssh-agent管理,避免每次連接都需要輸入密鑰密碼

三、配置Inventory文件

默認的Inventory文件是/etc/ansible/hosts,格式與windows的ini配置文件類似
1、按IP地址來配置
例如:我現在有2臺主機,IP地址分別為192.168.2.205和192.168.2.208,並且兩臺主機都是web服務器,那麽可以定義一個web_server組,如下:

[web_server]
192.168.2.205
192.168.2.208

如果修改了ssh端口號的話,可以按如下方式來定義:

[web_server]
192.168.2.205:5210
192.168.2.208:5210

如果我有一臺主機IP為192.168.2.203不屬於任何組,可以按如下方式來定義:

192.168.2.203

[web_server]
192.168.2.205
192.168.2.208

給主機設置一個別名,在這個例子中,通過“webserver1”別名,會連接192.168.2.205。

Webserver1 ansible_ssh_port=5210 ansible_ssh_host=192.168.2.205
Webserver2 ansible_ssh_port=5210 ansible_ssh_host=192.168.2.208

可以單獨設置連接用戶名和連接類型:

[web_server]
192.168.2.203       ansible_connection=local
192.168.2.205:5210   ansible_connection=ssh   ansible_ssh_user=xuad
192.168.2.208:5210   ansible_connection=ssh   ansible_ssh_user=andyxu

2、按主機名配置
按主機名配置和按IP地址配置一樣,只需把IP改成主機名即可,例如:

[web_server]
web1.com
web2.com

[db_server]
db1.com:5210
db2.com:5210

[targets]
ansible.com       ansible_connection=local
other1:5210   ansible_connection=ssh   ansible_ssh_user=xuad
Other2:5210   ansible_connection=ssh   ansible_ssh_user=andyxu

例如有一組db服務器,分別為db1.xuad.com到db50.xuad.com,共50臺db服務器

[db_server]
db[1:50].xuad.com:5210

如果是dba.xuad.com到dbf.xuad.com,共6臺db服務器

[db_server]
db[a:f].xuad.com:5210

3、給主機設置變量
分配變量給主機很簡單,這些變量定義後可在playbooks中使用。

[web_server]
web1.com  http_port=80  pathname=/etc/httpd/
web2.com  http_port=8081  pathname=/etc/nginx/

4、給組分配變量
下面例子是給web_server組定義兩個變量,http_port和pathname。

[web_server]
web1.com
web2.com

[web_server:vars]
http_port=80
pathname=/etc/httpd/

5、把一個組作為另一個組的子成員
下面例子是把web_server和db_server兩個組分配給some_server組,作為some_server組的子組,並分配變量給some_server組使用,再把some_server組分配給user_server組,作為user_server組的子組。

[web_server]
192.168.2.205
192.168.2.208

[db_server]
db1.com:5210
db2.com:5210

[some_server:children]
web_server
db_server

[some_server:vars]
http_port=80
nginx_port=8080
pathname=/etc/ansible/
xuad=foo.xuad.com

[user_server:children]
some_server
other_server
Northserver

6、分文件定義主機和組變量
假設有一臺主機為192.168.2.205,屬於web_server組,現在分別給web_server組和192.168.2.205主機定義變量,那麽hosts文件增加如下內容:

/etc/ansible/group_vars/web_server
/etc/ansible/host_vars/192.168.2.205

創建group_vars和host_vars目錄

mkdir /etc/ansible/group_vars
mkdir /etc/ansible/host_vars

然後編輯web_server文件,可按如下內容定義變量,註意:號後面有個空格。
vim /etc/ansible/group_vars/web_server

http_port: 80
http_path: /data/httpd/
ntp_server: ntp.xuad.com
db_server: db1.com

再編輯192.168.2.205文件,可按如下內容定義變量
vim /etc/ansible/host_vars/192.168.2.205

nginx_port: 8081
nginx_path: /data/nginx/
db_server: db2.com

還有更進一步的運用,可以為一個主機或者一個組創建一個目錄,目錄名就是主機名或組名,目錄中可以創建多個文件,文件中的變量都會被讀取為主機或組的變量,host文件內容如下:

/etc/ansible/group_vars/web_server/192.168.2.205
/etc/ansible/group_vars/db_server/db1.com

Inventory文件的參數可以查看ansible官方文檔,下面我們來看官方文檔的一個主機文件的例子,並說明每行都是什麽意思。

#給some_host主機定義了ssh連接的端口號和用戶名
some_host         ansible_ssh_port=2222     ansible_ssh_user=manager
#連接aws_host主機時將通過以下定義的私鑰文件進行驗證
aws_host          ansible_ssh_private_key_file=/home/example/.ssh/aws.pem
#給freebasd_host主機指定了python的路徑
freebsd_host      ansible_python_interpreter=/usr/local/bin/python
#給ruby_module_host主機指定了ruby運行的路徑
ruby_module_host  ansible_ruby_interpreter=/usr/bin/ruby.1.9.3

ansible還可以從外部獲取Inventory配置信息,獲取途徑有以下幾種:
1、從雲端拉取inventory
2、從LDAP獲取配置
3、從cobbler獲取配置
4、從CMDB獲取配置
從外部獲取inventory配置的方法我這裏就不講了,有興趣的可以查看官方文檔。

四、ansible批量執行命令

首先在inventory的配置文件/etc/ansible/hosts裏定義一個主機組,內容如下:
vim /etc/ansible/hosts
技術分享圖片
(1)我們先來ping一下,看下兩臺主機的連通情況
ansible web_server -m ping
技術分享圖片
(2)查看web_server組下有哪些主機
ansible web_server --list
技術分享圖片
(3)查看一臺主機的內存使用情況
命令格式:ansible <主機或主機組> -a “shell命令”
註:執行一條命令使用-a參數,後面跟shell命令
ansible 192.168.2.205 -a "free -h"
(4)在web_server組批量創建一個普通用戶
ansible web_server -a "useradd andy"
(5)重啟所有主機的httpd服務
命令格式:ansible <主機組> -m <模塊名稱> -a <指定執行參數>
註:使用all參數就是對hosts文件裏配置的所有主機執行命令
ansible all -m service -a "name=httpd state=restarted"
也可以使用ansible all -a "systemctl restart httpd"語句,結果是一樣的,但輸出信息不同,可自行測試看看。
(6)查看多個組下各主機指定用戶的UID和GID
命令格式:ansible <主機組1>:<主機組2>:<主機組3> -a "shell命令"
ansible http1:http2 -a "id andy"
技術分享圖片
(7)排除一個特定組,在web_server組下的不屬於http1組的主機的/tmp目錄下新建一個文件
命令格式:ansible ‘<主機組1>:!<主機組2>‘ -a "shell命令"
註:執行命令的主機屬於webserver組,但不屬於http1組
ansible ‘web_server:!http1‘ -a "touch /tmp/test.txt"
技術分享圖片
此時ansible會給出一個警告信息,意思是說ansible已經內置有file模塊,建議使用file模塊創建文件,如果想取消警告信息,可以修改配置文件ansible.cfg,把command_warnings參數改成False,就不會再給出警告信息了。其實創建文件可以使用下面這條命令,結果是一樣的,關於模塊的使用後面會講到。
ansible ‘web_server:!http1‘ -m file -a "dest=/tmp/test.txt state=touch"
(8)指定兩個組的交集,查看屬於web_server組又屬於http1組的主機的負載情況
註:!表示屬於前面的組但不屬於後面的組;&表示即屬於前面的組也屬於後面的組。
ansible ‘web_server:&http1‘ -a "uptime"
技術分享圖片
(9)在即屬於web_server組又屬於http2組但不屬於http1組的主機刪除/tmp/test.txt文件內容
ansible ‘web_server:!http1:&http2‘ -a "rm -f /tmp/test.txt"
(10)通配符使用,查看以http開頭的所有組的主機的字符編碼
ansible http* -a "cat /etc/locale.conf"
(11)查看以http開頭的所有組和web_server組的所有主機的磁盤使用情況
ansible http*:web_server -a "df -h"
(12)查看web_server組的第一臺主機的hostname
ansible web_server[0] -a "hostname"
(13)查看web_server組的前5臺主機的當前日期和時間
ansible web_server[0:4] -a "date ‘+%Y-%m-%d %H:%M:%S‘"
(14)正則表達式使用,查看以web或者http開頭的組的主機的httpd服務的進程PID
ansible ‘~(web|http)*‘ -a "pidof httpd"
(15)其它正則表達式例子

ansible ‘~(web|http)2‘ -a "pidof sshd"  # web2或者http2主機或者組
ansible ‘~(^web)*‘ -a "pidof sshd"  # 以web開頭的主機或者組
ansible ‘~(web|db).*\.example\.com‘ -a "pidof sshd"  # web.*.example.com或者db.*.example.com主機或者組

(16)如果不想使用ssh-agent,想通過密碼驗證的方式使用ssh,可以在執行ansible命令時使用--ask-pass或-k參數。

ansible web_server -a "shell命令" --ask-pass
ansible web_server -a "shell命令" -k

(17)批量重啟服務器,加-f 10選項可以fork出10個子進程(bash),以並行的方式執行reboot命令,即每次重啟10個
ansible web_server -a "/sbin/reboot" -f 10
(18)在執行ansible命令時,默認是以當前用戶的身份去執行,如果想以指定的用戶執行命令,需添加-u username選項

ansible web_server -a "shell命令" -u username  # ssh安全密鑰驗證方式
ansible web_server -a "shell命令" -u username -k  # ssh賬號密碼驗證方式

(19)以sudo去執行命令
如果設置了sudo不需要輸入密碼的話,可不加--ask-sudo-pass;如果sudo需要輸入密碼的話,必須加--ask-sudo-pass參數。建議設置成sudo不需要輸入密碼,這樣更容易實現自動化。

ansible web_server -a "shell命令" -u username --sudo
ansible web_server -a "shell命令" -u username --sudo --ask-sudo-pass

(20)也可以通過-sudo-user或-U選項,使用sudo切換到其它用戶,而不是root用戶
ansible web_server -a "shell命令" -u username -U otheruser [--ask-sudo-pass]
ansible有許多模塊,默認是“command”,也就是命令模塊,我們前面執行的那些語句都是以command模塊執行的,下面來看一個例子。
(21)統計無法登陸系統的用戶數量,即nologin用戶數
ansible web_server -a "grep ‘/sbin/nologin‘ /etc/passwd | wc -l"
發現執行後會報錯,無法得到我們想要的結果
技術分享圖片
這是因為command模塊不支持shell命令的變量、管道符等,如果你想使用shell相關的這些東西,可以使用shell模塊,用-m參數指定要運行的模塊即可。
ansible web_server -m shell -a "grep ‘/sbin/nologin‘ /etc/passwd | wc -l"
技術分享圖片
(22)查看模塊的幫助信息
ansible-doc shell
(23)查看web_server組各主機的ip地址
ansible web_server -m shell -a "/sbin/ifconfig | grep ‘inet ‘ | awk ‘{print \$2}‘ | sed -e ‘/127\.0\.0\.1/d‘"
註:shell模塊使用awk命令時需要使用轉義符*
(24)查看web_server組各主機的PATH變量內容
ansible web_server -m shell -a ‘echo $PATH‘
註意:如果使用雙引號"echo $PATH",會求出PATH變量在當前系統的值,這就牽扯到shell引號的規則了。*
在下圖中我們明顯看到雙引號和單引號執行的結果是不一樣的,單引號是遠程機器的結果,而雙引號實際是ansible本地機器的結果。
技術分享圖片
(25)Ansible能夠以並行的方式同時scp大量的文件到多臺機器,將本地hosts文件copy到web_server組的所有主機的/tmp目錄下
命令格式:ansible <主機或主機組> -m copy -a "src=<本地目錄或文件> dest=<遠程目錄或文件>"
ansible web_server -m copy -a "src=/etc/hosts dest=/tmp/"
技術分享圖片
(26)使用file模塊修改文件的屬主和權限,這裏可以替換為copy模塊,是等效的
命令格式:ansible <主機或主機組> -m file -a "dest=<遠程目錄或文件> mode=<權限> owner=<所屬用戶> group=<所屬用戶組>"

ansible web_server -m file -a "dest=/tmp/hosts mode=600"
ansible web_server -m file -a "dest=/tmp/hosts mode=600 owner=xuad group=xuad"
ansible web_server -a "ls -lh /tmp/hosts"

技術分享圖片
(27)使用file模塊創建目錄,與執行mkdir -p效果類似
ansible web_server -m file -a "dest=/tmp/test mode=755 owner=xuad group=xuad state=directory"
(28)使用file模塊創建文件,與執行touch效果類似
ansible web_server -m file -a "dest=/tmp/test.txt mode=755 owner=xuad group=xuad state=touch"
(29)使用file模塊創建一個軟鏈接文件
ansible web_server -m file -a "src=/root/test.txt dest=/tmp/test.txt state=link"
(30)刪除目錄(遞歸刪除)和刪除文件,absent表示刪除

ansible web_server -m file -a "dest=/tmp/test state=absent"
ansible web_server -m file -a "dest=/tmp/test.txt state=absent"

Ansible提供對yum和apt的支持,下面是關於yum的示例
(31)確認一個軟件包已經安裝,但不去升級它
ansible web_server -m yum -a "name=wget state=present"
技術分享圖片
(32)將一個軟件包升級到最新版本
ansible web_server -m yum -a "name=wget state=latest"
技術分享圖片
(33)卸載一個軟件包,將wget卸載
ansible web_server -m yum -a "name=wget state=removed"
技術分享圖片
(34)確認一個軟件包沒有安裝,確認wget已經不在了
ansible web_server -m yum -a "name=wget state=absent"
技術分享圖片
(35)安裝一個軟件包,通過yum方式安裝wget
ansible web_server -m yum -a "name=wget state=installed"
技術分享圖片
(36)刪除一個用戶,刪除andy用戶
ansible web_server -m user -a "name=andy state=absent"
(37)確認一個用戶是否存在,不存在則創建此用戶
ansible web_server -m user -a "name=andy state=present"
(38)創建一個新用戶,並指定用戶組和家目錄
ansible web_server -m user -a "name=andy groups=xuad home=/home/andy1"
(39)創建一個新用戶,並設置密碼
ansible web_server -m user -a ‘name=andy password="&lt;crypted password here&gt;"‘
註:<crypted password here>是經過sha-512加密算法加密後的值,需要安裝passlib,密碼值要用雙引號括起來,外面用單引號
通過以下方式生成sha-512算法密碼

pip install passlib
python -c "from passlib.hash import sha512_crypt; import getpass; print sha512_crypt.encrypt(getpass.getpass())"

(40)我們有時需要用git下載一個軟件項目,可以使用git模塊
ansible web_server -m git -a "repo=foo.example.org/repo.git dest=/srv/myapp version=HEAD"
(41)服務的啟動、重啟、停止,enabled=yes表示加入開機啟動

ansible web_server -m service -a "name=httpd state=started"
ansible web_server -m service -a "name=httpd enabled=yes state=started"
ansible web_server -m service -a "name=httpd state=restarted"
ansible web_server -m service -a "name=httpd state=stopped"

長時間運行的操作可以放到後臺執行,需要加--do-stuff參數,ansible會檢查任務的狀態,在主機上執行的同一個任務會分配同一個job id。
(42)後臺執行命令,最多運行3600秒,-B 表示後臺執行的最長時間
ansible all -B 3600 -a "/usr/bin/long_running_operation --do-stuff"
(43)檢查任務運行的狀態,使用async_status模塊,上面執行後臺命令後會返回一個job id,將這個id傳給async_status模塊
ansible all -m async_status -a "jid=488359623657.1326"
(44)後臺執行命令,最多運行1800秒,即30分鐘,-P表示每60秒檢查一次狀態,默認15秒
ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
(45)查看一臺主機的系統信息
ansible 192.168.2.205 -m setup
註:這些系統信息變量可以直接在playbook裏面調用
(46)查看一臺主機的日期和時間信息
ansible 192.168.2.205 -m setup -a ‘filter=ansible_date_time‘
(47)查看一臺主機的內存相關信息
ansible 192.168.2.205 -m setup -a ‘filter=ansible_*_mb‘
(48)查看一臺主機的網卡信息
ansible 192.168.2.205 -m setup -a ‘filter=ansible_ens3[0-5]‘
(49)計劃任務模塊cron,每6個小時同步一次時間
ansible web_server -m cron -a ‘name="modify ntp server" minute=0 hour="*/6" job="/usr/sbin/ntpdate ntp.xuadup.net"‘
技術分享圖片
ansible的cron模塊實際上就是在遠程主機上創建了一條crontab(自動計劃任務),我們到遠程主機上執行crontab -e看一下
技術分享圖片
(50)系統重啟後自動執行一個腳本
ansible web_server -m cron -a ‘name="a job for reboot" special_time=reboot job="/root/xuad.sh"‘
(51)刪除一個計劃任務
ansible web_server -m cron -a ‘name="a job for reboot" state=absent‘
(52)掛載分區
ansible web_server -m mount -a ‘name=/data src=/dev/sdb1 fstype=ext4 opts=rw state=mounted‘
(53)卸載分區
ansible web_server -m mount -a ‘name=/data state=unmounted‘
(54)確保一個分區是掛載狀態,如果不是則掛載
ansible web_server -m mount -a ‘name=/data src=/dev/sdb1 fstype=ext4 state=present‘
關於playbook的內容請繼續關註我的後續博文,謝謝!

通過ansible批量管理Linux服務器:配置Inventory和批量執行命令