【11.22】nginx监控、代码上线

案例:监控Nginx服务器(文档+直播)

监控Nginx服务器状态码是否有502

相信运维过Nginx+php-fpm+MySQL网站的朋友一定遇到过502问题,发生502问题的原因有很多种,而最常见的是由于php-fpm资源耗完导致。
而本案例要监控的这台服务器就是这种情况,平时一直都很好,但若网站访问量很高,就会有502的状态码出现。发生502的问题时,需要及时分析造成php-fpm资源耗尽的原因,所以要做一个监控脚本,当有502状态码第一时间告警通知我们。

具体要求如下:
1)脚本一分钟执行一次
2)监控502状态可以通过分析网站的访问日志,也可以通过用curl工具发起http请求,获得状态
码,建议通过分析访问日志,假如访问日志路径为/data/logs/access.log
3)一分钟内出现502的次数超过50次则需要告警
4)告警需要发邮件通知

知识点一:计划任务cron

本案例要求我们一分钟执行一次脚本,所以要用到 cron。
执行命令:
crontab -e
这样就进入到了编辑页面,计划任务的格式是这样的:

# Example of job definition:
# .---------------- 分钟 (范围0 - 59)
# | .------------- 小时 (范围0 - 23)
# | | .---------- 日期 (范围1 - 31)
# | | | .------- 月 (范围1 - 12) 也可以用英文的简写形式: jan,feb,mar,apr ...
# | | | | .---- 周 (范围0 - 6) (周日可以用0或者7表示) 也可以写成英文简写形式:
sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * 用户名(可以省略) 要执行的命令

示例1:
每周1,3,5凌晨4点20分执行脚本 /usr/local/sbin/123.sh

20 4 * * 1,3,5 /bin/bash /usr/local/sbin/123.sh

示例2:
每隔3天清空文件/data/log/tmp.log

0 0 */3 * * true>/data/log/tmp.log

示例3:
每天9点到12点,14点到16点执行脚本/usr/local/sbin/xxx.sh

0 9-12,14-16 * * * /bin/bash /usr/local/sbin/xxx.sh

本案例每分钟执行一次,则写成这样:

* * * * * /bin/bash /usr/local/sbin/mon_502.sh

知识点二:过滤关键词

shell 脚本中,过滤某个关键词使用 grep 命令,比如在本例中需要把日志中包含 502 的日志过滤出来,命令为:
grep ‘502’ /data/log/access.log

这个是最基本的用法,平时脚本中使用 grep 的机会很多,且用法也比较复杂,通常会和正则表达式配合在一起使用。下面为几个常见的用法,(以下全部示例文件为1.txt)。

过滤出所有包含数字的行:

grep '[0-9]' 1.txt

过滤出以英文字母开头的行:

grep '^[a-zA-Z]' 1.txt

去除所有空行:

grep -v '^$' 1.txt

过滤出包含以abc开头且以123结尾的字符串的行

grep 'abc.*123' 1.txt

过滤出至少有两个连续数字的行

grep -E '[0-9][0-9]+' 1.txt

或者

grep -E '[0-9]{2,}' 1.txt

过滤出含有alexis或linux的行有几行

grep -En 'alexis|linux' 1.txt

再回过头来看本案例的需求,因为是一分钟检测一次,所以过滤的关键词是上一分钟的时间,通过分析日志,可以发现上一分钟可以用 date -d “-1 min” +"%Y:%H:%M:[0-5][0-9]"这个关键词
来表示。

知识点三:shell 中的大小比较

shell 脚本的语法比较特殊,其中数字比较大小并不能直接使用>,<,>=,<=等字符,而是使用如下方式:

含义选项
大于-gt
小于-lt
大于等于-ge
小于等于-le
等于-eq
不等于-ne

结合if语句,写法如下:

if [ $a -gt 10 ] //当变量a的值大于10的时候
if [ $x -le 100 ] //当变量x的值小于等于100的时候

如果要比较的对象并不是数字,而是一个字符串的时候,可以这样用:

if [ $str == "alexis" ] //当变量str的值是alexis的时候

知识点四:shell中的逻辑判断

在所有的编程语言中,逻辑判断和循环遍历可以说是必不可少的组成部分,shell中的逻辑判断以if
为主,其格式主要有三种。

1)if … then … fi
示例代码:

if [ $a -gt 5 ]
then
	command1
	command2
fi

2)if … then … else … fi
示例代码:

if command 
then
	command1
else
	command2
fi

说明:if后面的条件可以是一条命令,命令执行成功则条件成立,执行command1,否则条件不成立,执行command2

3)if … then … elif … then … else … fi
示例代码:

if [ $b -ge 10] || [ $b -lt 6 ]
then
	command1
elif [ $b -eq 8 ]
then
	command2
else
	command3
fi

说明:if后面的判断条件可以有多个,用||表示或者,用&&表示并且

知识点五:在命令行下发邮件

python发邮件的脚本,调用第三方邮件,不过不用QQ的了,而是使用163的邮箱。因为可以在手机上安装邮件客户端,所以不用担心提醒的问题了,收到邮件直接在app上提醒,比短信还方便。同时,接收邮件人也可以是自己,也就是说自己给自己发邮件,这样也不会有垃圾邮件的烦恼。
下面是发邮件的python代码:

#!/usr/bin/python
#coding:utf-8
import smtplib
from email.mime.text import MIMEText
import sys
mail_host = 'smtp.163.com'
mail_user = 'test@163.com'
mail_pass = 'your_mail_password'
mail_postfix = '163.com'
def send_mail(to_list,subject,content):
	me = "zabbix 监控告警平台"+"<"+mail_user+"@"+mail_postfix+">"
	msg = MIMEText(content, 'plain', 'utf-8')
	msg['Subject'] = subject
	msg['From'] = me
	msg['to'] = to_list
	try:
		s = smtplib.SMTP()
		s.connect(mail_host)
		s.login(mail_user,mail_pass)
		s.sendmail(me,to_list,msg.as_string())
		s.close()
		return True
	except Exception,e:
		print str(e)
		return False
if __name__ == "__main__":
	send_mail(sys.argv[1], sys.argv[2], sys.argv[3])

说明:该脚本会调用第三方的邮箱账户,需要你填写正确的mail_host, mail_user以及mail_pass。假如脚本名字为mail.py,则发邮件的命令为:

python mail.py xxx@xxxxx.com "邮件主题" "邮件内容"

本案例参考脚本
有了以上四个储备知识,下面就该写本案例的脚本了,如下是我提供的一个参考脚本:
vim /usr/local/sbin/mon_502.sh //内容如下

#!/bin/bash
##该脚本用来监控网站的502问题
t=`date -d "-1 min" +"%Y:%H:%M:[0-5][0-9]"`
log="/data/logs/access.log"
#假设mail.py已经写好,并放在/usr/local/sbin/下
mail_script="/usr/local/sbin/mail.py"
mail_user=xxx@xxxx.com
n=`grep $t $log|grep -c " 502 "`
if [ $n -gt 50 ]
then
 python $mail_script $mail_user "网站有502" "1分钟内出现了$n次"
fi

增加任务计划:

* * * * * /bin/bash /usr/local/sbin/mon_502.sh 2>/tmp/mon_502.err

说明:需要在该cron最后面定义一个错误日志输出,如果脚本执行过程中有报错,我们可以
到/tmp/mon_502.err文件中查看错误信息。

案例:自动化运维–代码上线(文档+直播)

生产环境中一个业务通常跑在多台服务器上,也就是所谓的负载均衡,那么这些机器上运行的代码必须要保持一致。如何实现一致呢?有两种方案。

1. 通过共享的方式
如果机器量不多,可以使用NFS实现,当然如果要求稳定性最好是使用专业的存储设备(NAS、SAN等),这种方式架构如下:
在这里插入图片描述
这种架构的优点是方便维护,比如有代码更新时,只需要更新一台机器上的代码,则其他机器上都会跟着更新。缺点是,机器量大了的话,共享存储会成为瓶颈,甚至由于对文件的争抢造成性能问题。还有一点,共享存储这里是一个很大的单点隐患,不出故障一切都OK,一旦出了故障,则整个业务都挂掉,影响非常大。

2. 分布式
既然通过共享的方式有不少缺点,那么就选择另外一种方式,即把代码存到每一台WEB服务器本地磁盘上,如下图所示:
在这里插入图片描述
这样做的好处是,没有存储性能问题,没有资源争抢冲突,也没有单点故障的隐患。缺点是,每次代码更新需要对所有web机器进行更新,比较繁琐。虽然步骤繁琐,但大多数企业都会选择该方式。本案例的背景就是第二种方式,具体要求如下:
1)提供一个所有 WEB 服务器的 IP 列表 ip.list
2)假设所有 WEB 服务器上有一个普通用户user01,密码为SGs2ox6uj,该用户为同步代码用户
3)每次代码上线会提供一个文件列表file.list(即要更改的文件列表)

知识点一:rsync同步文件通过文件列表
rsync 这个同步文件的工具虽然我们在前面几个案例中多次出现过,但通过一个文件列表来同步文件并不常见,先看示例:

# cat 1.txt
/tmp/123/1.sh
/root/test/a.txt
/etc/passwd
# rsync -av --files-from=./1.txt / root@192.168.1.180:/

说明: 1.txt为一个文件列表,即要同步的文件列表;rsync的–files-from选项指定要同步文件的列表文件(1.txt的路径,可以是绝对路径,也可以是相对路径),这个文件列表其实就是一堆文件路径,这个路径建议用绝对路径,否则会出错;如果文件列表中的文件路径为绝对路径,则rsync的源目录必须为/,当然目标目录也必须是/。

知识点二:expect 脚本同步文件
跟远程执行命令类似,expect 脚本要想同步命令,spawn 后面的shell命令不再是ssh,而是 rsync,示例如下:

#!/usr/bin/expect
set passwd "SGs2ox6uj"
set host "192.168.1.180"
spawn rsync -a user01@$host:/tmp/test.txt /tmp/
expect {
	"yes/no" {send "yes\r"}
	"password:" {send "$passwd\r"}
}
expect eof

也可以传递参数给expect脚本,示例如下:

#!/usr/bin/expect
set passwd "SGs2ox6uj"
set host [lindex $argv 0]
set file [lindex $argv 1]
spawn rsync -a --files-from=$file / user01@$host:/
expect {
	"yes/no" {send "yes\r"}
	"password:" {send "$passwd\r"}
}
expect eof

本案例参考脚本

#/bin/bash
##代码上线
#提醒用户,是否更新了要上线的代码列表文件
read -p "你是否已经更新了文件列表./file.list?确认请输入y或者Y,否则按其他任意键退出脚本。" c
#如果直接按回车,也会退出脚本
if [ -z "$c" ]
then
	exit 1
fi
if [ $c == "y" -o $c == "Y" ]
then
	echo "脚本将在2秒后,继续执行。"
	#每秒输出一个.共输出两个.
	for i in 1 2
	do
		echo -n "."
		sleep 1
	done
	echo
else
	exit 1
fi

#判断有无./rsync.exp文件
[ -f ./rsync.exp ] && rm -f ./rsync.exp

#定义rsync.exp
cat >./rsync.exp <<EOF
#!/usr/bin/expect
set passwd "SGs2ox6uj"
set host [lindex \$argv 0]
set file [lindex \$argv 1]

spawn rsync -avR --files-from=\$file / user01@\$host:/
expect {
	"yes/no" {send "yes\r"}
	"password:" {send \$passwd\r}
}
expect eof
EOF

chmod a+x ./rsync.exp

#定义检测文件是否存在的函数
if_file_exist()
{
	if [ ! -f $1 ]
	then
		echo "文件$1不存在,请检查。"
		exit 1
}

#ip.list为所有WEB机器的ip列表
#file.list为要同步的文件列表

if_file_exist ./ip.list
if_file_exist ./file.list

for ip in `cat ./ip.list`
do
	./rsync.exp $ip ./file.list
done

#善后处理
rm -f ./rsync.exp

说明:要想在生产环境里使用该脚本,需要先提前创建一个user01用户,并且保证user01用户对
WEB服务器上代码所在目录有写权限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值