通過ansible批量管理Linux服務器:配置Inventory和批量執行命令
ansible是基於模塊工作的,本身沒有批量部署的能力。真正具有批量部署的是ansible所運行的模塊,ansible只是提供一種框架。主要包括:
(1)、連接插件connection plugins:負責和被監控端實現通信;
(2)、host inventory:指定操作的主機,是一個配置文件裏面定義監控的主機;
(3)、各種模塊:核心模塊、command模塊、自定義模塊;
(4)、借助於插件完成記錄日誌郵件等功能;
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 <模塊名>
實際應用中也可以指定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組的第一臺主機的hostnameansible 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服務的進程PIDansible ‘~(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方式安裝wgetansible 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="<crypted password here>"‘
註:<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和批量執行命令