自動化服務器巡檢的實現過程


由於上級的工作安排,今年的5月份開始每天都需要做一些服務器信息的巡檢;

對方交接時,完全是通過手敲指令、手動記錄來實現的;

熟悉了一段時間,把流程和記錄方式優化了一下(依舊是手動);

后來聽說Y哥那邊在部署總行提供的新的監控系統,基本可以替代巡檢;

就打算堅持一下,不研究自動化巡檢了,等監控上線;

等來等去就等了4個月。。。。。

新的監控一直不能正式上線,告警很多很雜,項目組一直在做優化和過濾;

還好這4個月一直不太忙,每天花點時間巡檢好像也沒什么;

進入三季度最后一個月突然忙了起來;

決定不等了,研究一下腳本;

這篇隨筆就用來記錄和整理自動化服務器巡檢的實現過程吧。


自動化巡檢系統大致分為幾個部分:

1. 常規服務器巡檢腳本;

2. 定制服務器巡檢腳本;

3. 腳本的下發;

4. 巡檢信息的統一收集;

5. 巡檢信息每日自動發送到郵箱。


 先上一張結構圖:

第一次做這種多服務器互相發送文件的系統真的是沒有經驗;

最一開始應該先考慮網絡結構,因為圖中的Windows管理機並不能和特殊網段服務器通信,導致后面加入特殊網段后,不得不用堡壘機下發腳本和收集結果,導致結構很混亂,不過還好,特殊網段服務器不算多;

如果一開始就用堡壘機作為下發和收集的核心,整體結構會清晰很多。


1. 常規服務器巡檢腳本

常規服務器巡檢腳本是在一台Linux服務器上編寫、測試,再上傳到Windows管理機的。需要巡檢的服務器每天定時去提供SFTP服務的Windows管理機上下載腳本,方便后續腳本更新,實現此功能的腳本(getshell.sh)如下:

#!/bin/bash
# ----- 從SFTP下載巡檢腳本 -----

sftpip=XX.XXX.XX.XXX
user=XXXXXXX
downDir=/patrol/shell

# ----- 隨機延時約0-30s后下載 -----

sleeptime=`expr $RANDOM / 1000`
sleep $sleeptime

sftp $user@$sftpip << EOF
cd $downDir
lcd /root/patrol
get patrol.sh
bye
EOF

SFTP腳本無法像FTP一樣直接在腳本中寫入密碼,需要先將訪問者的公鑰提供給SFTP服務端,生成公鑰的方法我參考的是http://bbs.chinaunix.net/thread-508290-1-1.html

在Windows管理機上我使用的是FreeSSHD提供的SFTP服務,把公鑰放在軟件配置中指定的位置就可以了。

因為涉及到的服務器比較多,好幾十條公鑰,所以合成公鑰是用bat腳本實現的:

@echo off
dir
copy *.pub result.pub
echo DONE
pause

腳本中添加了一個隨機延時功能,原因是一開始同步操作多個服務器進行SFTP訪問時,出現了超過SFTP最大連接數的現象。因為每個服務器訪問SFTP的時間很短,因此隨機延時0-30s就夠了。其中$RANDOM是系統自帶的隨機數變量。

寫好腳本后在服務器的crontab中添加了一行定時任務,每天7點執行getshell.sh:

0 7 * * * /bin/bash /root/patrol/getshell.sh > /dev/null 2>&1

后面的 > /dev/null 2>&1 是不寫定時任務日志的意思,因為功能比較簡單,感覺沒必要寫日志。crontab的寫法參考的是菜鳥教程:https://www.runoob.com/w3cnote/linux-crontab-tasks.html

下面就是巡檢腳本(patrol.sh)的主體了:

#!/bin/bash
PATH=/sbin:/usr/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
# ----- 巡檢腳本 V2.0 -----

# ----- 定義變量:上傳SFTP地址、用戶名、密碼、路徑 -----

cd /root/patrol
sftpip=XX.XXX.XX.XXX
user=XXXXXXX
remoteDir=/patrol/upload

# ----- 定義變量:本機信息、巡檢參數、時間參數 -----

localip=`ifconfig | grep 'XX.XXX.XX' | grep Bcast | awk '{print $2}' |awk -F: '{print $2}'`
loadavg=`top -b -n 1 | grep 'load average' | awk '{print $11 $12 $13 $14 $15}'`
cpuid=`top -b -n 1 | grep %Cpu | awk '{print $8 $9}'`
diskfree=`df -h | awk '{print $5}'`
memtotal=`free -l | grep Mem | awk '{print $2}'`
memocp=`free -l | grep buffers/cache | awk '{print $3}'`
memratio=`expr $memocp \* 100 / $memtotal`

if [ $memratio -ge 80 ]
then
    memwarn=內存過高!!!
else
    memwarn=內存正常
fi

date=$(date "+%Y%m%d")
filename=$date"_"$localip.txt

# ----- 主程序 -----

echo -e $date-----$localip-----$loadavg-----$cpuid-----$diskfree-----$memratio-----$memwarn >$filename

# ----- 隨機延時約0-30s后上傳SFTP -----

sleeptime=`expr $RANDOM / 1000`
sleep $sleeptime

sftp $user@$sftpip << EOF
cd $remoteDir
put $filename
bye
EOF

rm $filename

整個腳本中,比較難的就是各個巡檢項變量的定義,從上到下依次是本機IP、平均負載、CPU空閑、邏輯卷占用、內存總量、內存占用、內存占比,一共七項。shell中復雜變量的定義需要用··框起來,就是鍵盤上1左邊的點;

其中grep 'XXX'是為了抓取需要的行,awk '{print $X}'是為了抓取這一行內需要的位置,memratio這一項中的expr 'XXX'是為了用上面的memtotalmemocp兩個變量計算內存占比,然后加了一個內存是否過高的判斷;

主程序只有一行,就是把各個變量echo到一個文件中,文件以當天的日期_服務器IP.txt命名。echo -e的目的是激活轉義字符。

后面還是添加了延時和SFTP上傳,上傳后刪除掉了服務器上的文件,防止時間長了占用太多服務器磁盤。

寫完上述內容后,手動運行patrol.sh就可以實現功能了,但是添加了crontab定時任務后發現不生效:

30 7 * * * /bin/bash /root/patrol/patrol.sh > /dev/null 2>&1

一開始認為是crontab寫得有問題,后來發現是沒有在腳本中添加環境變量,即開頭的PATH這一行,參考的是:https://www.cnblogs.com/huskiesir/p/9970291.html

因為腳本中用到的變量比較多,所以干脆把系統提示的所有環境變量都扔進去了。。。

目前巡檢腳本的輸出結果是這樣的:

20211014-----XX.XXX.XX.XX-----average:0.18,0.11,0.09-----63.6id,-----Use% 1% 1% 10% 0% 17% 51% 59% 1% 9% 1% 33% 38% 27% 10% 5% 1% 0%-----24-----內存正常

只對內存的狀態進行了一個簡單的判斷,后續優化的過程中打算把每一項的狀態都判斷出來,這樣看巡檢結果就比較方便了,尤其是邏輯卷占用這塊,現在看着簡直頭疼,不過這也比之前每天點開一大堆服務器手動巡檢強太多了。


2. 定制服務器巡檢腳本

除了每台服務器都需要的常規項巡檢,某些服務器還需要針對某個服務或者某些定時生成的文件進行巡檢,實現起來其實就是一些特殊變量的定義,最后還是全部echo到一個txt中統一收集,下面一一進行列舉:

查看進程

custom_patrol=`ps -ef | grep XXX | grep XXX`

沒什么好說的,就是看一些進程在不在,輸出結果就是ps -ef的某一行。

② 查看文件

custom_patrol=`ls -l /某路徑 | grep 文件關鍵字`

也沒啥好說的,就是看一些文件在不在,grep后面可以跟一些日期變量啥的,可以抓取文件名中有日期的文件。一開始我還不知道腳本中不能用ll這個命令,查了一下才知道ll就是ls -l的縮寫。。。

③ 查看consul服務數

custom_patrol=`/某路徑/consul catalog services | wc -l`

查看consul微服務的個數,后面的 | wc -l 是計數的意思,不加的話會列出服務的列表。

④ telnet端口

telnet本來是一個很簡單的指令:

telnet XX.XXX.XX.XXX 某端口

但是用腳本實現起來就要稍微復雜一點了,因為telnet本身是類似於FTP、SSH、SFTP這類讓系統進入某個客戶端的指令。在腳本中,進去容易,出來就得靠EOF了,所以實現起來是這樣的:

custom_patrol=`telnet XX.XXX.XX.XXX 某端口 << EOF
exit
EOF`

沒錯EOF就是為了多加一個exit讓系統退出來。。。這樣的話就把telnet的情況定義成了變量,實現了端口檢測。

⑤ Redis數據庫狀態檢測

custom_patrol=`redis-cli -c -p 某端口 -h XX.XXX.XX.XXX -a '密碼'` << EOF
cluster nodes
ping
exit
EOF`

同樣用到了EOF格式,cluster nodes是為了檢查主從節點,ping是為了pong,exit是為了退出。

⑥ Oracle數據庫表空間占用查詢 

custom_patrol=`su - oracle -c "sqlplus 用戶名/密碼 << EOF
select round(sum(bytes)/1024/1024/1024,2)||'G' from user_segments where TABLESPACE_NAME = '表名';
exit
EOF
exit" | grep -E 'G|M' | grep -v Mining`

公司內的要求是Oracle數據庫只能用oracle用戶來啟動,因此這個變量的聲明首先要切換到oracle用戶,在su - oracle后加-c "指令"添加切換用戶后的指令,sqlplus的指令同樣用EOF格式。

因為進入sqlplus后會顯示一大堆東西,因此加了兩個grep來縮小一下范圍,一個是-E顯示含有G或者M的行,一個-v是不顯示含有Mining的行

⑦ 文件下載測試

這個功能一開始是想把下載信息定義成變量,然后echo這個變量來顯示下載是否成功,后來感覺這樣操作太麻煩了,直接下載這個文件,然后用ls -l檢測文件是否存在(或是否為當天下載)即可。

curl -o download_test.zip http://XX.XXX.XX.XXX:某端口/路徑/文件名\&name=n.zip
custom_patrol=`ls -lh | grep download_test.zip`

curl下載這行我一直沒跑出來,后來是讓開發小伙伴RCM幫忙改的,現在也沒太搞懂,有空再研究下。。。


目前用到的一些需要定制的巡檢基本就是這些。在echo某個多行變量到txt的時候,打開txt發現寫入的時候忽略了換行,參考https://blog.csdn.net/jxfgh/article/details/6757488在echo后加了一個while循環,實現了換行:

echo -e "$XXX" > result.txt | while read i
do
    echo $i
done

3. 腳本的下發4. 巡檢信息的統一收集都已經在1. 常規服務器巡檢腳本的腳本中實現了,不再贅述。


5. 巡檢信息每日自動發送到郵箱

每天每台服務器的巡檢信息上傳到Windows管理機后,需要進行匯總、上傳FTP、歸檔這幾個動作,通過bat腳本實現:

@echo off
copy nul all.tx
for %%a in (*.txt) do type %%a >>all.tx && echo. >> all.tx
ren all.tx *.txt
ren all.txt %date:~0,4%%date:~5,2%%date:~8,2%.tmp
del *.txt
ren %date:~0,4%%date:~5,2%%date:~8,2%.tmp %date:~0,4%%date:~5,2%%date:~8,2%.txt
ftp -i -s:"upload"
move %date:~0,4%%date:~5,2%%date:~8,2%.txt D:\FTPhome\patrol\history_data
del %date:~0,4%%date:~5,2%%date:~8,2%.txt

其中ftp命令文件upload:

open XX.XX.XX.XX
用戶名
密碼
lcd 本地路徑
cd FTP路徑
binary
put *.txt
bye

上傳到FTP后,下一步就是下載到辦公機然后通過郵件發送了,這個功能是通過Windows任務計划程序和Python實現的,首先通過定時任務啟動bat去調用兩個.py:

@echo off
cd 本地路徑
python ftp_download.py
python auto_email.py
move %date:~0,4%%date:~5,2%%date:~8,2%.txt 本地路徑\history_data

ftp_download.py(參考:https://www.cnblogs.com/Dahlia/p/10551929.html)

#coding=utf-8
import os
import time
from ftplib import FTP  # 引入ftp模塊

class MyFtp:

    ftp = FTP()

    def __init__(self,host,port=21):
        self.ftp.connect(host,port)

    def login(self,username,pwd):
        self.ftp.set_debuglevel(2)  # 打開調試級別2,顯示詳細信息
        self.ftp.login(username,pwd)
        print(self.ftp.welcome)

    def downloadFile(self,localpath,remotepath,filename):
        os.chdir(localpath)   # 切換工作路徑到下載目錄
        self.ftp.cwd(remotepath)   # 要登錄的ftp目錄
        self.ftp.nlst()  # 獲取目錄下的文件
        file_handle = open(filename,"wb").write   # 以寫模式在本地打開文件
        self.ftp.retrbinary('RETR %s' % os.path.basename(filename),file_handle,blocksize=1024)  # 下載ftp文件
        # ftp.delete(filename)  # 刪除ftp服務器上的文件

    def close(self):
        self.ftp.set_debuglevel(0)  # 關閉調試
        self.ftp.quit()

if __name__ == '__main__':
    ftp = MyFtp('FTP地址')
    ftp.login('用戶名','密碼')
    date = time.strftime("%Y%m%d", time.localtime())
    ftp.downloadFile('本地路徑','FTP路徑','%s.txt' % date)
    ftp.close()

auto_email.py(參考:https://www.cnblogs.com/yufeihlf/p/5726619.html)

#coding: utf-8
  
import time
import smtplib    
from email.mime.multipart import MIMEMultipart    
from email.mime.text import MIMEText    
from email.mime.image import MIMEImage 
from email.header import Header   
    
#設置smtplib所需的參數
#下面的發件人,收件人是用於郵件傳輸的。
smtpserver = 'SMTP服務器'
username = '用戶名'
password = '密碼'
#成功開啟IMAP/SMTP服務,在第三方客戶端登錄時,登錄密碼輸入以下授權密碼:
#HLSNDVBIOUQEUURU
sender = '發送者郵箱'
receiver = '接收者郵箱'
#若收件人為多個收件人
#receiver=['XXX@126.com','XXX@126.com']
date = time.strftime("%Y%m%d", time.localtime())

#subject = 'Automatic server patrol'
#通過Header對象編碼的文本,包含utf-8編碼信息和Base64編碼信息。以下中文名測試ok
subject = '服務器巡檢結果'
subject = Header(subject, 'utf-8').encode()
    
#構造郵件對象MIMEMultipart對象
#下面的主題,發件人,收件人,日期是顯示在郵件頁面上的。
msg = MIMEMultipart('mixed') 
msg['Subject'] = subject
msg['From'] = '發件人'
msg['To'] = receiver
#收件人為多個收件人,通過join將列表轉換為以;為間隔的字符串
#msg['To'] = ";".join(receiver) 
#若無時間,就默認一般為當前時間,該值一般不設置
#msg['Date']='2012-3-16'

#構造文字內容   
text = "今日巡檢結果"    
text_plain = MIMEText(text, 'plain', 'utf-8')    
msg.attach(text_plain)    

#構造圖片鏈接
# sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
# image = MIMEImage(sendimagefile)
# image.add_header('Content-ID','<image1>')
# image["Content-Disposition"] = 'attachment; filename="testimage.png"'
# msg.attach(image)

#構造html
#發送正文中的圖片:由於包含未被許可的信息,網易郵箱定義為垃圾郵件,報554 DT:SPM :<p><img src="cid:image1"></p>
# html = """
# <html>  
#   <head></head>  
#   <body>  
#     <p>Hi!<br>  
#        How are you?<br>  
#        Here is the <a href="http://www.baidu.com">link</a> you wanted.<br> 
#     </p> 
#   </body>  
# </html>  
# """    
# text_html = MIMEText(html,'html', 'utf-8')
# text_html["Content-Disposition"] = 'attachment; filename="texthtml.html"'   
# msg.attach(text_html)    


# 構造附件
sendfile=open('本地路徑\%s.txt' % date,'rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8') 
text_att["Content-Type"] = 'application/octet-stream'  
#以下附件可以重命名成aaa.txt(測試不成功) 
# text_att["Content-Disposition"] = 'attachment; filename="Python自動郵件附件測試.txt"'
#另一種實現方式
text_att.add_header('Content-Disposition', 'attachment', filename = "%s.txt" % date)
#以下中文測試不ok
#text_att["Content-Disposition"] = u'attachment; filename="中文附件.txt"'.decode('utf-8')
msg.attach(text_att)    
       
#發送郵件
smtp = smtplib.SMTP()    
smtp.connect(smtpserver)
#我們用set_debuglevel(1)就可以打印出和SMTP服務器交互的所有信息。
#smtp.set_debuglevel(1)  
smtp.login(username, password)    
smtp.sendmail(sender, receiver, msg.as_string())    
smtp.quit()

對兩個.py的理解比較少,基本上調試了一下能夠運行以后就沒有再改動了,其中還遇到了ftplib使用報錯計算機名為中文導致郵件發送報錯兩個問題,分別參考這兩篇解決的:

https://blog.csdn.net/BobYuan888/article/details/82980817

https://blog.csdn.net/weixin_41278305/article/details/110943401

內網環境安裝VSCode的離線插件參考了這兩篇:

https://blog.csdn.net/l508742729/article/details/103543755

https://blog.csdn.net/sinat_36188088/article/details/105203338


至此自動化服務器巡檢並且通過郵件發送巡檢結果就基本實現了,后續考慮繼續優化巡檢腳本,增加判斷語句,直接給出巡檢項是否正常的結果,減少人工查看的部分。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM