第六章·shell编程-企业级实战练习

书写脚本常用监控命令

监控目标/命令

  • 本地端口监控
    • netstat-lntup
    • ss -lntup
    • lsof
  • 远端端口监控
    • telnet
    • nc
    • nmap
  • 进程监控
    • ps -ef
    • ps aux
  • web监控
    • curl
    • wget
  • 数据库
    • mysql -uroot -p123 'select ping()'
  • 内存
    • free -m
  • 磁盘
    • df -h
  • 文件内容
    • md5

端口检查

本地检查端口是否开启

## 查看所有端口
[root@zabbix01 ~]# netstat -lntup
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      37809/beam.smp
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      544/rpcbind
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      38249/nginx: master
tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      4122/epmd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      770/sshd
tcp        0      0 0.0.0.0:15672           0.0.0.0:*               LISTEN      37809/beam.smp
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      37783/postmaster
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      928/master
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      38249/nginx: master
tcp6       0      0 :::5672                 :::*                    LISTEN      37809/beam.smp
tcp6       0      0 :::111                  :::*                    LISTEN      544/rpcbind
tcp6       0      0 :::80                   :::*                    LISTEN      38249/nginx: master
tcp6       0      0 :::4369                 :::*                    LISTEN      4122/epmd
tcp6       0      0 :::22                   :::*                    LISTEN      770/sshd
tcp6       0      0 :::5432                 :::*                    LISTEN      37783/postmaster
tcp6       0      0 ::1:25                  :::*                    LISTEN      928/master
tcp6       0      0 :::443                  :::*                    LISTEN      38249/nginx: master
udp        0      0 0.0.0.0:698             0.0.0.0:*                           544/rpcbind
udp        0      0 0.0.0.0:111             0.0.0.0:*                           544/rpcbind
udp6       0      0 :::698                  :::*                                544/rpcbind
udp6       0      0 :::111                  :::*                                544/rpcbind

## 查看指定端口
##错误方式;会过滤包含22所有的端口
[root@zabbix01 ~]# netstat -lntup|grep 22
tcp        0      0 0.0.0.0:4369            0.0.0.0:*               LISTEN      4122/epmd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      770/sshd
tcp6       0      0 :::4369                 :::*                    LISTEN      4122/epmd
tcp6       0      0 :::22                   :::*                    LISTEN      770/sshd

## 精确查找端口
##正确方式
[root@zabbix01 ~]# netstat -lntup|grep [s]shd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      770/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      770/sshd

[root@zabbix01 ~]# netstat -lntup|grep -w '22'
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      770/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      770/sshd

[root@zabbix01 ~]# ss -lntup|grep -w 22
tcp    LISTEN     0      128       *:22                    *:*                   users:(("sshd",pid=770,fd=3))
tcp    LISTEN     0      128      :::22                   :::*                   users:(("sshd",pid=770,fd=4))

##查看命令返回值判断端口是否开启
[root@m01 ~]# netstat -lntup|grep -w '22' &>/dev/null
[root@m01 ~]# echo $?
0
[root@m01 ~]# netstat -lntup|grep -w '10050' &>/dev/null
[root@m01 ~]# echo $?
1

## 转化成数字
[root@zabbix01 ~]# netstat -lntup|grep -w '22'|wc -l
2

## 个人推荐还是使用netstat这个命令,后续我们需要监控TCP的11种状态,也用该命令
#lsof
[root@zabbix01 ~]# lsof -i:22
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd      770 root    3u  IPv4  19637      0t0  TCP *:ssh (LISTEN)
sshd      770 root    4u  IPv6  19646      0t0  TCP *:ssh (LISTEN)
sshd    25088 root    3u  IPv4 491299      0t0  TCP zabbix01:ssh->gateway:61954 (ESTABLISHED)
sshd    80641 root    3u  IPv4 291875      0t0  TCP zabbix01:ssh->gateway:54130 (ESTABLISHED)

#ss
[root@zabbix01 ~]#  ss -lntup|grep 22
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd      770 root    3u  IPv4  19637      0t0  TCP *:ssh (LISTEN)
sshd      770 root    4u  IPv6  19646      0t0  TCP *:ssh (LISTEN)
sshd    25088 root    3u  IPv4 491299      0t0  TCP zabbix01:ssh->gateway:61954 (ESTABLISHED)
sshd    80641 root    3u  IPv4 291875      0t0  TCP zabbix01:ssh->gateway:54130 (ESTABLISHED)

远端检查端口是否开启

#1.telnet
[root@zabbix01 ~]# telnet 127.0.0.1 22
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
SSH-2.0-OpenSSH_7.4
## 这是一个交互式的,需要我们手动退出,所以适合在命令行使用,不适合脚本中使用
## 当然也有方法能让他不交互。随便ehco一个数交给管道符。
[root@zabbix01 ~]# echo | telnet 127.0.0.1 22
[root@zabbix01 ~]# echo | telnet 127.0.0.1 22 2>/dev/null|grep 'Connected'|wc -l

##使用telnet端口扫描
#!/bin/bash

. /etc/init.d/functions

IP=$1
for port in `seq 65535`;do
    {
    port_count=`echo ''|telnet $IP $port 2>/dev/null |grep 'Connected'|wc -l`

    if [ $port_count -ne 0 ];then
        action "$port 端口" /bin/true
    fi
    } &
done 

# 2.nc   netcat 网络中的瑞士军刀,功能很牛
[root@zabbix01 ~]# echo |nc 127.0.0.1 22
SSH-2.0-OpenSSH_7.4
Protocol mismatch.
[root@zabbix01 ~]# echo $?
0

-l:创建端口
[root@zabbix01 ~]# nc -l 8888

-k:保持连接
[root@zabbix01 ~]# nc -lk 8888

## 可以跟端口建立连接,传输数据

-u:指定nc使用udp协议(默认tcp)
-s:指定发送数据的源IP地址,适用于多网卡机器
-w:设置超时时间
-z:扫描时不发送任何数据

# 3.nmap也是一个很牛逼的网络扫描工具,一个命令能写一本书
## 扫描IP
nmap 10.0.0.61

## 扫描一个主机的一个端口
nmap -p 22 10.0.0.61

## 扫描一个主机的多个端口
nmap -p 22-1024 10.0.0.61

## 扫描多个主机的多个端口
nmap -p 22-1024 10.0.0.61 baidu.com

进程判断

ps和top命令

[root@web01 ~]# ps -ef|grep [n]ginx
root    12209   1     0 10:42 ?     00:00:00 nginx: master process
/usr/sbin/nginx -c /etc/nginx/nginx.conf
www     12210   12209 0 10:42 ?     00:00:00 nginx: worker process
[root@web01 ~]# ps -ef|grep [n]ginx|wc -l
2
[root@web01 ~]# ps -ef|grep [n]ginx1111|wc -l
0

## 远程进程检测
vim check_process.sh
#!/bin/bash

proc_count=`ssh 172.16.1.7 'ps -ef|grep [n]ginx|wc -l'`

if [ $proc_count -eq 0 ];then
    echo 'nginx不存活'
else
    echo 'nginx存活'
fi

网络检测

curl命令

# 1.curl命令
-I:只显示响应头信息
-H:修改请求头信息
-v:显示详细的请求过程
-L --location:跟随跳转
-s:不显示头部的统计信息
-X:指定请求方式
-w:取出指定内容,例如:%{http_code}取出状态码
-o:指定输出位置
-A:指定User-Agent
-u:指定用户名密码

##  举例:
## 访问百度
[root@zabbix01 ~]# curl www.baidu.com

## 只显示响应头部信息
[root@zabbix01 ~]# curl -I www.baidu.com
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 277
Content-Type: text/html
Date: Wed, 01 Sep 2021 01:24:34 GMT
Etag: "575e1f60-115"
Last-Modified: Mon, 13 Jun 2016 02:50:08 GMT
Pragma: no-cache
Server: bfe/1.0.8.18

## 只要状态码
[root@zabbix01 ~]# curl -s -w "%{http_code}" -o /dev/null https://roweyy.com
200
[root@zabbix01 ~]# curl -s -w "%{http_code}\n" -o /dev/null https://roweyy.com
200

## 追踪跳转
[root@zabbix01 ~]#   curl www.360buy.com
[root@zabbix01 ~]#   curl -v www.360buy.com
[root@zabbix01 ~]#   curl -v www.360buy.com -L

## -s取消头部信息,一般配合管道符使用
[root@zabbix01 ~]# curl -I https://roweyy.com|awk 'NR==1{print $2}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
200

[root@zabbix01 ~]# curl -I -s https://roweyy.com|awk 'NR==1{print $2}'
200

## 指定用户名密码
[root@zabbix01 ~]# yum install -y nginx httpd-tools
[root@zabbix01 ~]# htpasswd -b -c /etc/nginx/auth_conf lw lw
[root@zabbix01 ~]# vim /etc/nginx/conf.d/lw.conf
server {
    listen 80;
    server_name _;
    access_log off;

    location /nginx_status {
        stub_status;
        auth_basic "Auth access Blog Input your Passwd!";
        auth_basic_user_file auth_conf;
    }
}

## 直接访问会报错401没有认证
[root@zabbix01 ~]# curl 10.0.0.61/nginx_status
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>

## 加上用户名密码就可以了
[root@zabbix01 ~]# curl -ulw:lw 10.0.0.61/nginx_status
Active connections: 1
server accepts handled requests
 5 5 3
Reading: 0 Writing: 1 Waiting: 0

## 但是我推荐这么访问
[root@zabbix01 ~]# curl http://zls:zls@10.0.0.61/nginx_status
Active connections: 1
server accepts handled requests
 6 6 4
Reading: 0 Writing: 1 Waiting: 0

## 访问的时候,可以修改我们自己的User-Agent,偷偷的,不让别人发现
[root@zabbix01 ~]# curl -A zls_chrome https://roweyy.com

wget命令

-O:指定输出位置
-r:递归下载
--debug:类似于curl的-v显示过程
-q:静默输出
--spider:不下载,就访问(爬虫模式)

[root@zabbix01 ~]# wget -r https://nginx.org/en/docs/

[root@zabbix01 ~]# wget -q --spider www.baidu.com
[root@zabbix01 ~]# echo $?
0
[root@zabbix01 ~]# wget -q --spider www.baidu.com/asdasda
[root@zabbix01 ~]# echo $?
8

文件检测

md5

# 获取文件md5值
[root@zabbix01 ~]# md5sum /etc/passwd
38b06c70e862085e22f23838dc873ade  /etc/passwd

# 将md5值保存到文件中
[root@zabbix01 ~]# md5sum /etc/passwd > passwd.md5

# 检测md5
[root@zabbix01 ~]# md5sum -c passwd.md5
/etc/passwd: OK

# 如果内容有改动则md5会发生变化
[root@zabbix01 ~]# useradd test_md5
[root@zabbix01 ~]# md5sum -c passwd.md5
/etc/passwd: FAILED
md5sum: WARNING: 1 computed checksum did NOT match

if判断实战

1.监控系统内存,如果不足30%就发送邮件告警通知运维人员

#下载 mailx
[root@m01 ~]# yum install -y mailx

#修改配置文件
[root@m01 ~]# vim /etc/mail.rc
set from=1627556442@qq.com
set smtp=smtps://smtp.qq.com:465
set smtp-auth-user=1627556442@qq.com
set smtp-auth-password=#客户端授权码
set smtp-auth=login
set ssl-verify=ignore
set nss-config-dir=/etc/pki/nssdb/

## 系统内存
# 可用内存
[root@m01 ~]# free -m|awk 'NR==2{print $NF}'
692
# 所有内存
[root@m01 ~]# free -m|awk 'NR==2{print $2}'
972

#编写脚本
[root@m01 ~]# vim check_mem.sh
#!/bin/bash
IP=`ifconfig eth0|awk 'NR==2{print $2}'`
mem_ava=`free -m|awk 'NR==2{print int($NF/$2*100)}'`
mem_info=`free -m|awk 'NR==2{print $NF}'`

if [ $mem_ava -lt 30 ];then
    echo -e "IP地址:$IP\n主机名:$HOSTNAME\n内存可用率:低于30%\n当前可用内存:
${mem_info}M" \
    |mail -s "${IP}内存检测结果" 133411023@qq.com
fi

使用sendEmail

使用mailx我们会发现无法发送表格邮件,mailx不支持html格式

# 1.下载sendEmail
wget http://test.driverzeng.com/other/sendEmail-v1.56.tar.gz

# 2.安装依赖
yum install perl-Net-SSLeay perl-IO-Socket-SSL -y

# 3.解压
tar xf sendEmail-v1.56.tar.gz

# 4.创建安装目录
[root@m01 ~]# mkdir /app

# 5.移动软件到安装目录中
[root@m01 ~]# mv sendEmail-v1.56 /app/

# 6.添加环境变量
[root@m01 ~]# vim /etc/profile.d/sendEmail.sh
PATH="/app/sendEmail-v1.56:$PATH"

# 7.加载环境变量
[root@m01 ~]# source /etc/profile
## sendEmail选项
-f 112233@qq.com# 发件人邮箱地址
-t 445566@qq.com# 收件人邮箱地址
-s smtp.qq.com# 发件人邮箱的smtp服务器地址
-u 'lw test email'# 邮件标题
-m 'test mail content'# 邮件内容
-a /tmp/data.txt /tmp/1.jpg#发送附件
-xu 112233# 发件人邮箱登录用户名
-xp fdnzuslqhshgkslxj# 发件人邮箱登录密码(QQ邮箱的授权码)
-cc 222222@qq.com# 抄送指定用户
-bcc 333333@qq.com# 加密抄送
-o message-content-type=html# 邮件内容格式为html
-o message-file=FILE# 指定某个文件内容作为邮件内容
-o message-charset=utf8# 邮件内容编码为utf8
-o tls=no#关闭tls握手

## 发送html格式邮件
[root@m01 ~]# cat check_mem.sh
#!/bin/bash

IP=`ifconfig eth0|awk 'NR==2{print $2}'`
mem_ava=`free -m|awk 'NR==2{print int($NF/$2*100)}'`
mem_info=`free -m|awk 'NR==2{print $NF}'`

if [ $mem_ava -gt 30 ];then
cat > mem_info.txt <<EOF
<table border=1px color=red>
    <tbody>
     <tr bgcolor="#fff000">
      <td colspan=7 align=center>内存监控信息</td>
     </tr>
     <tr>
      <td align=center>IP地址</td>
      <td align=center>主机名</td>
      <td align=center>内存可用率</td>
      <td align=center>当前可用内存</td>
     </tr>
     <tr>
      <td align=center>$IP</td>
      <td align=center>$HOSTNAME</td>
      <td align=center>小于30%</td>
      <td align=center>${mem_info}M</td>
     </tr>
    </tbody>
</table>
EOF

sendEmail -f 1627556442@qq.com \
-t 1627556442@qq.com \
-s smtp.qq.com \
-u "${IP}主机内存检测结果" \
-xu 1627556442 \
-xp tcrvcdgkxxgybiab \
-o message-content-type=html \
-o message-file=mem_info.txt \
-o message-charset=utf8 \
-o tls=no
fi

2.检查nginx服务是否正常,业务是否正常

[root@m01 ~]# cat check_web.sh
#!/bin/bash

. /etc/init.d/functions
domain_name_list=(www.zls.com blog.zls.com php.zls.com)
IP_list=(10.0.0.61 10.0.0.7)
proc_count=`ps -ef|grep [n]ginx|wc -l`
port_80_count=`netstat -lntup|grep -w '80'|wc -l`
port_443_count=`netstat -lntup|grep -w '443'|wc -l`

# 本地
for domain_name in ${domain_name_list[*]};do
    http_code=`curl -s -w "%{http_code}" -o /dev/null $domain_name`
    if [ $http_code -eq 401 ];then
        action "${domain_name}网站正常,但是身份验证不通过" /bin/false
    elif [[ $http_code =~ ^[4-5] ]];then
        action "${domain_name}网站无法访问" /bin/false
    elif [ $proc_count -le 0 ];then
        action "nginx进程" /bin/false
    elif [ $port_80_count -le 0 ];then
        action "nginx的80端口检测" /bin/false
    #elif [ $port_443_count -le 0 ];then
        # echo 'nginx的443端口不存在'
    else
        action "${domain_name}网站" /bin/true
    fi
done

# 远程
for IP in ${IP_list[*]};do
proc_count=`ssh $IP "ps -ef|grep [n]ginx|wc -l"`
port_80_count=`ssh $IP "netstat -lntup|grep -w '80'|wc -l"`
port_443_count=`ssh $IP "netstat -lntup|grep -w '443'|wc -l"`

    for domain_name in ${domain_name_list[*]};do
        http_code=`curl -s -w "%{http_code}" -o /dev/null $domain_name`
        if [ $http_code -eq 401 ];then
            action "${domain_name}网站正常,但是身份验证不通过" /bin/false
        elif [[ $http_code =~ ^[4-5] ]];then
            action "${domain_name}网站无法访问" /bin/false
        elif [ $proc_count -le 0 ];then
            action "$IP nginx进程" /bin/false
        elif [ $port_80_count -le 0 ];then
            action "$IP nginx的80端口检测" /bin/false
        #elif [ $port_443_count -le 0 ];then
            # echo 'nginx的443端口不存在'
        else
            action "${domain_name}网站" /bin/true
        fi
    done
done

山林不向四季起誓 荣枯随缘