《构建高可用Linux服务器 第3版》—— 3.6 生产环境下的Shell脚本分类

3.6 生产环境下的Shell脚本分类

生产环境下的Shell脚本作用还是挺多的,这里根据3.1节所介绍的日常工作中Shell脚本的作用,将生产环境下的Shell脚本分为备份类、监控类、统计类、开发类和自动化类。前面3类从字面意义上看比较容易理解,后面的我稍微解释一下:开发类脚本是用Shell来配合PHP做一些非系统类的管理工作,比如SVN的发布程序等;而自动化类脚本则利用Shell自动来替我们做一些繁琐的工作,比如自动生成及分配密码给开发组的用户或自动安装LNMP环境等。下面我会就这些分类举一些具体实例,便于大家理解。另外值得说明的一点是,这些实例都源自于我的线上环境,大家拿过来稍微改动一下IP或备份目录基本上就可以使用了。

3.6.1 生产环境下的Shell脚本备份类

俗话说得好,备份是救命的稻草。特别是重要的数据和代码,这些都是公司的重要资产,所以备份是必需的。备份能在我们执行了一些毁灭性的工作(比如不小心删除了数据)之后,进行恢复工作。我在实施项目时,发现有些有实力的公司在国内几个地方都有灾备机房,而且用的都是价格不菲的EMC高端存储。有朋友可能会问:如果我们没有存储怎么办?这可以参考一下我们公司的备份策略,即在执行本地备份的同时,让Shell脚本自动上传数据到另一台FTP备份服务器中。这种备份策略成本比较小,无需存储。此双备策略的具体步骤如下所示。

首先,做好准备工作。我们先要安装一台CentOS 5.8备份服务器,并安装vsftpd服务,稍微改动一下配置后启动。另外,关于vsftpd的备份目录,我们可以选择做RAID1或RAID5的分区或存储。没条件的朋友也可以像我们一样,用硬盘底座(HARD DRIVE DOCK)挂接一块2TB的SATA3硬盘(如果追求速度的话大家可以选择e-SATA插口),然后直接将其挂载到这台服务器的/mnt分区上。经过长时间测试发现这也非常稳定,备份工作进行得很顺利。

vsftpd服务的安装如下,CentOS 5.8下自带的yum极为方便。

yum -y install vsftpd

service vsftpd start && chkconfig vsftpd on
关于vsftpd配置前面已经讲过,这里给出配置文件,我们可以通过组合使用如下命令直接得出vsftpd.conf中有效的文件内容:

grep -v "^#" /etc/vsftpd/vsftpd.conf | grep -v '^$'

local_enable=YES

write_enable=YES

local_umask=022

dirmessage_enable=YES

xferlog_enable=YES

connect_from_port_20=YES

xferlog_std_format=YES

listen=YES

chroot_local_user=YES

pam_service_name=vsftpd

userlist_enable=YES

tcp_wrappers=YES
chroot_local_user=YES这句话的作用我要重点强调一下。它的作用是限制所有本地用户在登录vsftpd服务器时只能在自己的家目录下,这是基于安全的考虑。在编写脚本的过程中也考虑到了这点,如果大家要移植此脚本到自己的工作环境中,不要忘了这句语法,否则异地备份极有可能失效。

另外,下例中的CVS目录备份脚本说明一种情况,我们在备份服务器(即IP为192.168.4.45的机器)上应该建立备份用户CVS,并分配其密码,还应该将其家目录更改为备份目录,即/data/backup/cvs-backup,这样的话更方便备份工作,以下备份脚本以此类推。FreeBSD 8.1的用户密码配置文件为/etc/master.passwd,CentOS 5.8为/etc/passwd,两者是不一样的。由于这里用的FTP服务器是CentOS 5.8,所以我们只需要修改/etc/passwd文件即可。

注意 下面的脚本源自于我的生产环境,并没有做任何变动,我对每个脚本运行的环境都进行了说明,大家也可以尝试将在FreeBSD 8.1下运行的Shell脚本移植到CentOS 5.8下面。注意FreeBSD 8.1和CentOS 5.8下的data用法是不一样的,改编脚本时请注意!

1.CVS目录的备份脚本

由于CVS服务器仅保留以前网站的代码和CVS日志,我们现不提交任何内容,只是以读为准,所以仅仅做目录级的备份即可。考虑到目录的备份不是太大,我就没有做轮询处理(即只备份某一周期的文件,例如前30天),准备等备份文件过多时再考虑手动删除。应该在vsftpd服务器上建立相应的备份用户cvs_user,脚本内容如下所示(此脚本在FreeBSD 8.1 x86_64下已通过):

#!/bin/sh

# CVS backup for FreeBSD 8.1

# 2010-04-23

CVSDIR=/home/cvsroot/project

DATE='date +%Y-%m-%d'

OLDDATE='date -v -10d +%Y-%m-%d'

BACKDIR=/data/backup/cvs-backup

FILENAME=cvsbackup_'date +%Y-%m-%d'

if[! -d ${BACKDIR}/${DATE} ]; then

  mkdir ${BACKDIR}/${DATE}

 fi

 if [-d ${BACKDIR}/${OLDDATE} ]; then

     rm -rf ${BACKDIR}/${OLDDATE}

 fi

HOST=192.168.4.45

FTP_USERNAME=cvs_user

FTP_PASSWORD=cvs101

cd $CVSDIR

tar zcvf $FILENAME.tar.gz $CVSDIR

ftp -i -n -v << !

open ${HOST}

user ${FTP_USERNAME} ${FTP_PASSWORD}

bin

rmdir ${OLDDATE}

mkdir ${DATE}

cd ${DATE}

mput *

bye

!

2.版本控制软件SVN的代码库的备份脚本

版本控制软件SVN的重要性这里就不多说了,现在很多公司基本还是利用SVN作为提交代码集中管理的工具,所以做好其备份工作的重要性不言而喻。这里的轮询周期为30天一次,Shell会自动删除30天前的文件。应该在vsftpd服务器上建立相应的备份用户svn_user,脚本内容如下(此脚本在FreeBSD 8.1 x86_64下已通过):

#!/bin/sh

# subversion backup for FreeBSD 8.1

# Created by ritto.zhao

# 2010-04-23

SVNDIR=/data/svn

SVNADMIN=/usr/local/bin/svnadmin

DATE='date +%Y-%m-%d'

OLDDATE='date -v -30d +%Y-%m-%d'

BACKDIR=/data/backup/svn-backup

[ -d ${BACKDIR} ] || mkdir -p ${BACKDIR}

LogFile=${BACKDIR}/svnbak.log

[ -f ${LogFile} ] || touch ${LogFile}

  mkdir ${BACKDIR}/${DATE}

if [-d ${BACKDIR}/${OLDDATE} ]; then

rm -rf ${BACKDIR}/${OLDDATE}

echo " " >> ${LogFile}

echo " " >> ${LogFile}

echo "-----------------------------" >> ${LogFile}

echo 'date +"%Y-%m-%d %H:%M:%S"' >> ${LogFile}

echo "-----------------------------" >> ${LogFile}

echo "Subversion Backup Notification" >> ${LogFile}

/usr/bin/printf "Host:  'hostname'\ nAddress: ${IP}\ nDate:${DATE}\ n"

>> ${LogFile}

fi

for PROJECT in superbiiz ewizweb rest report ewiz

do

 cd ${SVNDIR}

 ${SVNADMIN} hotcopy ${PROJECT} ${BACKDIR}/${DATE}/${PROJECT} --clean-logs

 cd ${BACKDIR}/${DATE}

 tar zcvf ${PROJECT}_svn_${DATE}.tar.gz ${PROJECT} > /dev/null

 rm -rf ${PROJECT}

echo "Repository: ${PROJECT} backup done into ${BACKDIR}/${DATE}/ Successful!" >> ${LogFile}

echo "-----------------------------" >> ${LogFile}

echo "Subversion Backup Notification" >> ${LogFile}

/usr/bin/printf "Host:  'hostname'\ nAddress: ${IP}\ nDate:  ${DATE}\ n"

>> ${LogFile}

done

for PROJECT in httpd web rest report test

do

 cd ${SVNDIR}

 ${SVNADMIN} hotcopy ${PROJECT} ${BACKDIR}/${DATE}/${PROJECT} --clean-logs

 cd ${BACKDIR}/${DATE}

 tar zcvf ${PROJECT}_svn_${DATE}.tar.gz ${PROJECT} > /dev/null

 rm -rf ${PROJECT}

 echo "Repository: ${PROJECT} backup done into ${BACKDIR}/${DATE}/ Successful!" >> ${LogFile}

 /bin/sleep 2

done

HOST=192.168.4.45

FTP_USERNAME=svn_user

FTP_PASSWORD=svn101

cd ${BACKDIR}/${DATE}

ftp -i -n -v << !

open ${HOST}

user ${FTP_USERNAME} ${FTP_PASSWORD}

bin

cd ${OLDDATE}

mdelete *

cd ..

rmdir ${OLDDATE}

mkdir ${DATE}

cd ${DATE}

mput *

bye

!

另附上CentOS下SVN代码库备份脚本(此脚本在CentOS 5.6|5.8 x86_64下通过):

#!/bin/bash

SVNDIR=/data/svn

SVNADMIN=/usr/bin/svnadmin

DATE='date +%Y-%m-%d'

OLDDATE='date +%Y-%m-%d -d '30 days''

BACKDIR=/data/svnbackup

[ -d ${BACKDIR} ] || mkdir -p ${BACKDIR}

LogFile=${BACKDIR}/svnbak.log

[ -f ${LogFile} ] || touch ${LogFile}

mkdir $BACKDIR/$DATE

for PROJECT in myproject official analysis mypharma  

do  

 cd $SVNDIR 

 $SVNADMIN hotcopy $PROJECT  $BACKDIR/$DATE/$PROJECT  --clean-logs

 cd $BACKDIR/$DATE

 tar zcvf $PROJECT-svn-$DATE.tar.gz $PROJECT  > /dev/null

 rm -rf $PROJECT

 sleep 2 

done 

HOST=192.168.11.29

FTP_USERNAME=svn

FTP_PASSWORD=svn101

cd ${BACKDIR}/${DATE}

ftp -i -n -v << !

open ${HOST}

user ${FTP_USERNAME} ${FTP_PASSWORD}

bin

cd ${OLDDATE}

mdelete *

cd ..

rmdir ${OLDDATE}

mkdir ${DATE}

cd ${DATE}

mput *

bye

!

3.MySQL从数据库备份脚本

本着简单高效,不影响网站正常运营的原则,我们采用暂停从MySQL数据库的方式备份。这里要说明的是,本地的轮询周期为20天,vsftpd的轮询周期为60天,备份后就算是用gzip压缩,MySQL的数据库还是很大,大家可以根据实际需求来更改这个时间,注意不要让数据库撑爆你的备份服务器。由于是内部开发环境,密码设置得比较简单,如果要将其移植到自己的公网服务器上,还要在安全方面注意一下。另外附带说明一下,--opt只是一个快捷选项,等同于同时添加--add-drop-tables--add-locking --create-option --disable-keys --extended-insert --lock-tables --quick --set-charset选项。本选项能让mysqldump很快地导出数据,并且导出的数据可以很快导回。该选项默认是开启的,但可以用--skip-opt禁用。注意,如果运行mysqldump没有指定--quick或--opt选项,则会将整个结果集放在内存中。如果导出的是大数据库则可能会出现问题。脚本内容如下(此脚本在CentOS 5.6|5.8 x86_64下已通过):

#!/bin/bash

USERNAME=mysqlbackup

PASSWORD=mysqlbackup

DATE='date +%Y-%m-%d'

OLDDATE='date +%Y-%m-%d -d '-20 days''

FTPOLDDATE='date +%Y-%m-%d -d '-60 days''

MYSQL=/usr/local/mysql/bin/mysql

MYSQLDUMP=/usr/local/mysql/bin/mysqldump

MYSQLADMIN=/usr/local/mysql/bin/mysqladmin

SOCKET=/tmp/mysql.sock

BACKDIR=/data/backup/db

[-d ${BACKDIR} ] || mkdir -p ${BACKDIR}

[-d ${BACKDIR}/${DATE} ] || mkdir ${BACKDIR}/${DATE}

[! -d ${BACKDIR}/${OLDDATE} ] || rm -rf ${BACKDIR}/${OLDDATE}

for DBNAME in mysql test report

do

  ${MYSQLDUMP} --opt -u${USERNAME} -p${PASSWORD} -S${SOCKET} ${DBNAME} | gzip > ${BACKDIR}/${DATE}/${DBNAME}-backup-${DATE}.sql.gz

  echo "${DBNAME} has been backup successful"

  /bin/sleep 5

done

HOST=192.168.4.45

FTP_USERNAME=dbmysql

FTP_PASSWORD=dbmysql

cd ${BACKDIR}/${DATE}

ftp -i -n -v << !

open ${HOST}

user ${FTP_USERNAME} ${FTP_PASSWORD}

bin

cd ${FTPOLDDATE}

mdelete *

cd ..

rmdir ${FTPOLDDATE}

mkdir ${DATE}

cd ${DATE}

mput *

bye

!

4.mysqlhotcopy热备份数据库脚本

mysqlhotcopy是一个Perl脚本,最初由Tim Bunce编写并提供。它的主要实现原理是先锁住(LOCK)表,然后执行FLUSH TABLES动作,该正常关闭的表正常关闭,该进行flush同步的数据也进行同步,然后通过执行系统级别的复制(cp等)命令,将需要备份的表或数据库的所有物理文件都复制到指定的备份集位置上。它主要用于备份MyISAM存储引擎的数据库。脚本内容如下(此脚本在CentOS 5.6|5.8 x86_64下已通过):

#!/usr/bin/env bash

#author:coralzd powered by www.freebsdsystem.org

#description: mysqlhotcopy backup script

DATE='date+%y%m%d.%H'

DATADIR="/data0/mysql/data" #MySQL数据库目录

BACKDIR_DAILY="/data0/local/mysqld/daily" #每天备份数据库的目录

BACKDIR_HOURLY="/data0/local/mysqld/hourly"#每小时备份数据库的目录

INTERVAL="$1"

TMPDIR="/var/tmp/" #临时目录

TMPDIRH="$TMPDIR"hourly #临时每小时数据库目录

TMPDIRD="$TMPDIR"daily #临时每小时备份数据库的目录

LOGDIR="/data0/log/dbbackup/" #备份数据输出日志路径

KEEPH_LOCAL=1

USER=hotcopy #mysqlhotcopy用到的用户,必须要有select、reload、lock_tables 权限

PASSWD=hotcopy # 密码

HOST='hostname -s'

MYVERSION="5.1" 

mkdir -p $LOGDIR

case $INTERVAL in

hourly | HOURLY | Hourly | 1 )

echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

echo "Performing HOURLY level backup -- 'date +$m-$d.%H:%M:%S'" && echo 

""

echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 

>>"$LOGDIR"hourly.log

echo "Performing HOURLY level backup -- 'date +$m-$d.%H:%M:%S'" 

>>"$LOGDIR"hourly.log

mkdir -p $TMPDIRH # 创建临时目录

mkdir -p $BACKDIR_HOURLY #创建每小时备份目录

/usr/local/mysql/bin/mysqlhotcopy --allowold test -u $USER -p $PASSWD 

$TMPDIRH > /dev/null

echo "" && echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

echo "Compressing -- 'date +$m-$d.%H:%M:%S'"

echo "Compressing -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"hourly.log

cd $TMPDIRH #进入临时目录

find . -maxdepth 1 -type d -user mysql -exec tar czf {}-"$DATE".tar.gz '{}' \ ;

# 查找是mysql用户的数据库,然后进行打包

find . -maxdepth 1 -type d -user mysql -exec rm -rf {} \ ; # 查找并删除用户名为mysql的文件

echo ""

echo "Copying Local... -- 'date +$m-$d.%H:%M:%S'"

echo "Copying Local... -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"hourly.log

chattr -i $BACKDIR_HOURLY # 移除备份目录的保护属性

find $BACKDIR_HOURLY -type f -mtime +7 -exec rm {} \ ;#查找并删除在7天以外的备份数据库

mv * $BACKDIR_HOURLY #将打包好的文件移到每小时备份目录

chattr +i $BACKDIR_HOURLY # 对备份目录加保护

echo ""

echo "Ending -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"hourly.log

exit 0

;;

daily | DAILY | Daily | 2)

echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

echo "Performing DAILY level backup -- 'date +$m-$d.%H:%M:%S'" && echo 

""

echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" 

>>"$LOGDIR"daily.log

echo "Performing DAILY level backup -- 'date +$m-$d.%H:%M:%S'" 

>>"$LOGDIR"daily.log

mkdir -p $TMPDIRD #进入临时目录

mkdir -p $BACKDIR_DAILY #创建每天备份目录

/usr/local/mysql/bin/mysqlhotcopy --allowold test -u $USER -p $PASSWD 

$TMPDIRD > /dev/null

echo "" && echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

echo "Compressing -- 'date +$m-$d.%H:%M:%S'"

echo "Compressing -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"daily.log

cd $TMPDIRD #进入临时目录

find . -maxdepth 1 -type d -user mysql -exec tar czf {}-"$DATE".tar.gz '{}' \ ; 

#查找是mysql用户的数据库,然后进行打包

find . -maxdepth 1 -type d -user mysql -exec rm -rf {} \ ; #查找备份数据库,并将在1天以外的备份删除

echo "Copying Local... -- 'date +$m-$d.%H:%M:%S'"

echo "Copying Local... -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"daily.log

chattr -i $BACKDIR_DAILY #移除备份目录的保护属性

find $BACKDIR_DAILY -type f -mtime +$KEEPD_LOCAL -exec rm -rf '{}' \ ; #查找备份数据库,并将在1天以外的备份删除

mv * $BACKDIR_DAILY #将打包好的文件移到每小时备份目录

chattr +i $BACKDIR_DAILY #对备份目录加保护

echo "Ending -- 'date +$m-$d.%H:%M:%S'" >>"$LOGDIR"daily.log

exit 0

;;

* )

echo ""

echo 

"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

echo "Invalid Selection" 1>&2

exit 1

esac

3.6.2 生产环境下的开发类Shell脚本

Shell作为系统管理脚本,在开发功能上一直有所欠缺,但我们可以将其作为PHP或Python开发语言的辅助语言,配合作开发工具,提高我们的工作效率。

1.配合PHP作为SVN的发布程序

公司的SVN发布程序是这样的工作流程:把将要发布的程序打上publish please:,后面接上SVN日志(开发人员提交的代码日志,这比较重要,是后来更改代码的条件依据),然后PHP程序会检索出这些打上标的代码,并发布到线上环境中。这样一来就带来了一个问题:在按照原先的程序发布到线上后,会将publish please后面的开发人员写的SVN log清除,给开发造成了不便。我在接手此工作后将此Shell脚本重写,解决了这个Bug。由于此脚本牵涉的内容比较多,功能也比较繁琐,所以这里只给大家演示一下,并不要求掌握。实现功能的代码如下所示(此脚本在FreeBSD 8.1 x86_64下已通过):

#!/bin/sh

# SVN PUBLISH TOOL

# 2010-07-23

SVN=/usr/local/bin/svn

cd /var/www/html/svn_log/files/svn/

svn up --username web --password web101

cat /var/www/html/svn_log/files/svntest/file.log | svn log $2 | head -n5 | sed -n "/publish/p" > svnlog

svnlog_change='sed -i "s@publish please@already published@" svnlog'

cat /var/www/html/svn_log/files/svntest/file.log | awk -F ',' '{ print "/usr/local/bin/svn propset --username web --password web101 -r"$1" --revprop svn:log "$svnlog_change" " $2 }' | /bin/sh

[! -d /var/www/html/svn_log/files/svntest ] || mv /var/www/html/svn_log/files/svntest /var/www/html

/old-svntest/html-${COMMIT}

mkdir /var/www/html/svn_log/files/svntest

chmod -R 777 /var/www/html/svn_log/files/svntest

chown -R www:www /var/www/html/svn_log/files/svntest

cd /var/www/html/svn_log/files/svn/

svn up --username web --password web101

此脚本在线上已稳定运行半年,基本能实现我们的要求。美中不足的是,我们发现还存在着一个Bug,即如果有大量脚本要同时提交,此脚本会失效,这个Bug目前也只能在后续版本中改进了。

2.利用Shell安全方便地删除指定的zone

我维护的DNS服务器主要有3个,即一主一从一备。由于公司的架构采用了CDN方案,所以namd.conf针对“okspace.com”的出现位置就有3处,即电信、网通及其他,加上3个服务器,每次手动用Vim删除okspace.com时就必须修改9处,维护起来很麻烦。更棘手的是,有些zone经常需要删除,特别麻烦。所以我写了个Shell脚本以减轻自己的工作量,且达到安全删除的目的。

此脚本中变量domain中的文件内容可以自己定义,鉴于生产环境下bind都是源码安装的,所以就以named.conf文件为主了。代码虽然短小,但操作起来确实很方便,后期我想跟Python或PHP结合起来使用,做成图形化界面,并加入了更多功能,使其更完善。代码如下(此脚本在CentOS 5.6|5.8 x86_64下已通过):

#!/bin/bash

domain='zone\ "okspace.cn"' 

if [-e /var/named/chroot/etc/named.conf ];then

sed -i "/$domain/,/};/d" /var/named/chroot/etc/named.conf

else 

sed -i "/$domain/,/};/d" /var/named/chroot/var/named/named.rfc1912.zones

fi```
在实际工作中我们了解了Shell脚本强大的系统管理功能,也意识到了它在开发上的先天不足,这里我建议大家有时间可以关注和学习一门开发语言,PHP或Python均可。大家可以根据自己的兴趣和职业规划,有重点地选择学习。

####3.6.3 生产环境下的统计类Shell脚本

统计工作一直是Shell脚本的强项,我们完全可以利用Sed、Awk再加上正则表达式,写出强大的统计脚本来分析系统日志、安全日志及服务器应用日志等。

1.Nginx负载均衡器日志汇总脚本 此脚本同样适用于分析Nginx或Apache Web日志。

以下脚本是用来分析Nginx负载均衡器的日志,作为Awstats的补充,它可以快速得出排名最前的网站和IP等。脚本内容如下所示(此脚本在CentOS 5.8 x86_64下已测试通过):

!/bin/bash

if [$# -eq 0 ]; then

  echo "Error: please specify logfile."

  exit 0

else

  LOG=$1

fi

if [! -f $1 ]; then

  echo "Sorry, sir, I can't find this nginx log file, pls try again!"

exit 0

fi

echo "Most of the ip:"

echo "-------------------------------------------"

awk '{ print $1 }' $LOG | sort | uniq -c | sort -nr | head -10

echo

echo

echo "Most of the time:"

echo "--------------------------------------------"

awk '{ print $4 }' $LOG | cut -c 14-18 | sort | uniq -c | sort -nr | head -10

echo

echo

echo "Most of the page:"

echo "--------------------------------------------"

awk '{print $11}' $LOG | sed 's/^.\ (.cn\ )\"/\ 1/g' | sort | uniq -c | sort -rn | head -10

echo

echo

echo "Most of the time / Most of the ip:"

echo "--------------------------------------------"

awk '{ print $4 }' $LOG | cut -c 14-18 | sort -n | uniq -c | sort -nr | head -10 > timelog

for i in 'awk '{ print $2 }' timelog'

do

  num='grep $i timelog | awk '{ print $1 }''

  echo " $i $num"

  ip='grep $i $LOG | awk '{ print $1}' | sort -n | uniq -c | sort -nr | head -10'

  echo "$ip"

  echo

done

rm -f timelog

2.Nginx Web服务器日志切割脚本

为什么我们要对日志进行切割呢?这是因为在生产环境下,我们的Web服务器是365×24小时不间断地提供服务的,它的日志也是不间断产生的。而我们分析它的日志时,可能需要以天为单位来查看,所以考虑以天为单位来切割,可以利用Crontab来完成这项工作,切割后的日志可以用Awstats来分析。脚本内容如下所示(此脚本在CentOS 5.5 x86_64下已通过):

!/bin/bash 

The Nginx logs path 

logs_path="/data0/logs"

logs_dir=${logs_path}/$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")

logs_file=$(date -d "yesterday" +"%Y%m%d")

mkdir -p /data0/backuplogs/$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")

tar -czf ${logs_path}/${logs_file}.tar.gz ${logs_path}/*.log

rm -rf ${logs_path}/*.log

mv ${logs_path}/${logs_file}.tar.gz /data0/backuplogs/$(date -d "yesterday" +"%Y")/$(date -d "yesterday" +"%m")

/usr/local/nginx/sbin/nginx -s reload

for oldfiles in 'find /data0/backuplogs/$(date -d "30 days ago" +"%Y")/$(date -d "30 days ago" +"%m")/ -type f -mtime +30'

do

   rm -f $oldfiles

done

for oldfiles in 'find/data0/backuplogs/$(date -d"30 days ago"+"%Y")/$(date -d"30 days ago"+"%m")/-type f -mtime+30'这句代码的作用是自动删除一个月前的打包日志文件。Nginx处理日志的脚本比较简单,大家没必要像我一样写得这么复杂,还可以简化一些。

3.测试局域网内主机依然存活的小脚本

我们在对局域网的网络情况进行维护时,经常有这样的情况,需要收集网络中存活的IP,这个时候可以写一个Shell脚本,自动收集某一网段的IP。现在的IT技术型公司一般都比较大,网络工程师一般会规划几个VLAN,即几个网段,我们可以多设几个变量参数来自动收集所有网段的IP。脚本如下所示(此脚本在CentOS 5.8 x86_64下已通过):

!/bin/bash

for n in {100..200}; do

   host=192.168.4.$n

   ping -c2 $host &>/dev/null

   if [$? = 0 ]; then

         echo "$host is UP"

         echo "$host" >> /root/alive.txt

   else

         echo "$host is DOWN"

   fi

done```
程序会自动记录存活的IP,我们用cat命令来查看/root/alive.txt文件,如下所示:

cat /root/alive.txt

192.168.4.100

192.168.4.101

192.168.4.102

192.168.4.108

192.168.4.109

192.168.4.111

192.168.4.113

192.168.4.121

192.168.4.123

192.168.4.125

192.168.4.133

192.168.4.138

192.168.4.142

192.168.4.143
脚本虽然短小,但却非常实用,免得又要到Windows XP下去下载局域网检测工具。我们平时在工作中也应该注意多收集多写一些这样的脚本,达到简化我们工作的目的。

3.6.4 生产环境下的监控类Shell脚本

在生产环境下,服务器的稳定情况会直接影响公司的生意和信誉,可见其有多重要。所以,我们需要即时掌握服务器的状态,一般我们会在机房部署Nagios作为监控程序,然后用Shell作为补充脚本,实时监控我们的服务器。
1.自动监控ADSL状态并重启的脚本
故障分析:公司的办公环境中以一台Ubuntu 8.04作NAT路由器,但它的ADSL总是掉线,一掉的话网关的Gateway就没有了,直接影响就是所有同事都上不了网。所以我针对这种情况写了一个监控脚本,测试了很长时间,效果不错。执行脚本方法如下所示:
nohup sh route.sh &
注意前面要用上nohup,这样可避免root用户logout时此脚本退出。脚本代码如下(此脚本在Ubuntu 8.04 i386下已通过):

#!/bin/bash
#Created By Andrew.Yu
while :
 do
  if route | tail -l | grep "0.0.0.0"
  then
  &>/dev/null
  else
   adsl-stop
   adsl-start
  fi
  sleep 10
 done```
2.Nginx负载均衡服务器上监控Nginx进程的脚本
由于我们的电子商务前端的负载均衡层用到了Nginx+Keepalived架构,而Keepalived无法进行Nginx服务的实时切换,所以这里用了一个监控脚本nginx_pid.sh,每隔5秒就监控一次Nginx的运行状态,如果发现有问题就关闭本机的Keepalived程序,让VIP切换到从Nginx负载均衡器上。在对线上环境进行操作的时候,我人为地重启了主Master的Nginx机器,从Nginx机器在很短的时间内就接管了VIP地址,即网站的实际内网地址(此内网地址能过防火墙映射为公网IP),进一步证实了此脚本的有效性。脚本内容如下(此脚本已在CentOS 5.8  x86_64下测试通过):

!/bin/bash

Created By Andrew.Yu

while :
do
nginxpid='ps -C nginx --no-header | wc -l'
if [$nginxpid -eq 0 ];then
  ulimit -SHn 65535
  /usr/local/nginx/sbin/nginx
sleep 5
 nginxpid='ps -C nginx --no-header | wc -l'
 if [$nginxpid -eq 0 ];then
 /etc/init.d/keepalived stop
 fi
fi
sleep 5
done```
3.系统文件打开数监测脚本
这个脚本比较方便,可用来查看Nginx进程下最大文件打开数。脚本代码如下(此脚本在CentOS 5.8 x86_64下已通过):

#!/bin/bash
for pid in 'ps aux | grep nginx | grep -v grep|awk '{print $2}''
do
cat /proc/${pid}/limits | grep 'Max open files'
done```
脚本的运行结果如下所示:

Max open files      1024         1024         files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files
Max open files      65535        65535        files  
4.Web网站即时监控与报警程序
虽然现在规模较大的公司可以购买AlertBot即时监控服务,并配合Nagios来监控网站,但很多时候客户的公司可能没这个需求,所以我们可以写一个Shell程序监控我们的脚本,网站出故障后就向我们的邮箱或手机发送信息报警。如果飞信接口不是太稳定的话,可以向139的邮箱发报警邮件,它会自动绑定到我们的移动手机上。脚本代码如下(此脚本在CentOS 5.6|5.8 x86_64下已通过):

!/bin/sh

Created by kerryhu

MAIL:king_819@163.com

BLOG:http://kerry.blog.51cto.com

LANG=C

被监控服务器、端口列表

server_all_list=(\
125.252.87.171:80 \
58.64.157.166:80 \
58.64.157.174:80 \

219.87.10.1:80 \

)

telnum=152XXXXXXXX
passwd=12345

date=$(date -d "today" +"%Y-%m-%d_%H:%M:%S")

采用HTTP POST方式发送检测信息给接口程序interface.php,接口程序负责分析信息,决定是否发送报警MSN消息、手机短信、电子邮件

send_msg_to_interface()
{
  if [[$2 = "0" ]] || [[$2 = "2" ]]; then
     #开始发送警报邮件,135XXXXXXXX@139.com既是发送方也是接收方
     sendEmail -f 135XXXXXXXX@139.com -t 135XXXXXXXX@139.com -s smtp.139.com -u "from http_monitor" -xu 135XXXXXXXX@139.com -xp james -o message-charset=utf-8 -m $1
     #发送MSN警报消息(如果不需要MSN警报可以注释这行)

     curl -m 600 -d menu=http -d date=$date -d ip=$server_ip -d port=$server_port -d status=$status http://127.0.0.1/monitor/interface.php

  fi;

}

server_all_len=${#server_all_list[*]}
i=0
while [$i -lt $server_all_len ]
do
  server_ip=$(echo ${server_all_list[$i]} | awk -F ':' '{print $1}')
  server_port=$(echo ${server_all_list[$i]} | awk -F ':' '{print $2}')
  server_message=" "
  if curl -m 10 -G http://${server_all_list[$i]}/ > /dev/null 2>&1
  then
   #status:  0,http down  1,http ok  2,http down but ping ok
   status=1
      echo "服务器${server_ip},端口${server_port}能够正常访问!";
        server_message="服务器${server_ip},端口${server_port}能够正常访问!";
  else
    if curl -m 30 -G http://${server_all_list[$i]}/ > /dev/null 2>&1
    then
      status=1
      echo "服务器${server_ip},端口${server_port}能够正常访问!"
        server_message="服务器${server_ip},端口${server_port}能够正常访问!";
    else
      if ping -c 1 $server_ip > /dev/null 2>&1
      then
        status=2
        echo "服务器${server_ip},端口${server_port}无法访问,但是能够Ping通!";
         server_message="服务器${server_ip},端口${server_port}无法访问,但是能够Ping通!";
      else
        status=0
        echo "服务器${server_ip},端口${server_port}无法访问,并且无法Ping通!";
         server_message="服务器${server_ip},端口${server_port}无法访问,并且无法Ping通!";
      fi
    fi
  fi
send_msg_to_interface "${server_message}" "${status}";
  let i++
don

5.MySQL主从监控邮件报警脚本
脚本设计思路:
1)此脚本应该能适应各种各样不同的内外网环境,即IP不同的环境。
2)让脚本也顺便监控下MySQL是否正常运行。
3)Slave机器的IO和SQL状态都必须为YES,缺一不可,这里用到了多重条件判断-a。
脚本产生的背景环境:
我有不少基于公网类型的网站(没有硬件防火墙,直接置于IDC机房)做的都是MySQL一主一从架构,从机主要起备份数据库和冷备份的作用,虽然从机宕机了问题不大,但也影响数据的备份工作;这样的网站有数十个,如果一个一个手动检查,每天都要浪费不少时间,所以用了脚本监控,设计了如下脚本(以下脚本在CentOS 5.8 x86_64下已通过):

!/bin/bash

check MySQL_Slave Status

crontab time 00:10

MYSQLPORT='netstat -na|grep "LISTEN"|grep "3306"|awk -F[:" "]+ '{print $4}''
MYSQLIP='ifconfig eth0|grep "inet addr" | awk -F[:" "]+ '{print $4}''
STATUS=$(/usr/local/webserver/mysql/bin/mysql -u yuhongchun -pyuhongchun101 -S /tmp/mysql.sock -e "show slave status\G" | grep -i "running")
IO_env='echo $STATUS | grep IO | awk ' {print $2}''
SQL_env='echo $STATUS | grep SQL | awk '{print $2}''

if [ "$MYSQLPORT" == "3306" ]
then
 echo "mysql is running"
else
 mail -s "warn!server: $MYSQLIP mysql is down" yuhongchun027@163.com
fi

if [ "$IO_env" = "Yes" -a "$SQL_env" = "Yes" ]
then
 echo "Slave is running!"
else
 echo "####### $date #########">> /data/data/check_mysql_slave.log
 echo "Slave is not running!" >> /data/data/check_mysql_slave.log
 mail -s "warn! $MySQLIP_replicate_error" yuhongchun027@163.com << /data/data/check_mysql_slave.log
fi
建议每10分钟运行一次:
/10 root /bin/sh /root/mysql_slave.sh
记得在每台MySQL从机上分配一个yuhongchun的用户,权限大些也没关系,只限定在本地运行,如下所示:
grant all privileges on *.
to "yuhongchun"@"127.0.0.1" identified by "yuhongchun101";
grant all privileges on . to "yuhongchun"@"localhost" identified by "yuhongchun101";```
脚本实践:
此脚本我已用于生产环境,大家可以放在从MySQL机器上,用来监控。
后期应用:
后期公司的MySQL数据库准备由一主一从架构升级成一主多从,读写分离的架构,LVS作从数据库的负载均衡器,此脚本自动监控从MySQL的replication状态,如果不能同步则自动关闭本机的MySQL服务,免得影响整个网站的正常业务访问。

3.6.5 生产环境下的自动化类Shell脚本

1.批量生成账户脚本
在内网开发环境中,有时需要为开发组的同事批量生成账户,如果手动添加会非常麻烦,这个时候我们可以写一段Shell脚本来自动完成这项工作。在首次登录时密码均是统一的,在移交给开发人使用时让他们自行更改。脚本代码如下(此脚本在CentOS 5.8 x86_64下已通过):

#!/bin/bash 
#此脚本应用于开发环境下生成批量用户账户
for name in tom jerry joe jane andrewy brain
do
  useradd $name
  echo redhat | passwd --stdin $name
don```
passwd --stdin的作用是将前面的输入通过管道命令作为自己的输出,从而避免脚本交互,达到自动化的目的。
2.系统初始化脚本
此脚本用于新装Linux的相关配置工作,比如禁掉iptable和SELinux及ipv6、优化系统内核、停掉一些没必要启动的系统服务等。此脚本尤其适合大批新安装的CentOS系列的服务器。脚本代码如下所示(此脚本在CentOS 5.5|5.6 x86_64下已通过):

!/bin/bash

Created by kerryhu

MAIL:king_819@163.com

BLOG:http://kerry.blog.51cto.com

cat << EOF
+--------------------------------------------------------------+
|     === Welcome to CentOS System init ===        |
+--------------------------------------------------------------+
+--------------------------by kerry----------------------------+
EOF

set ntp

yum -y install ntp
echo " 3 /usr/sbin/ntpdate 210.72.145.44 > /dev/null 2>&1" >> /etc/crontab
service crond restart

set ulimit

echo "ulimit -SHn 102400" >> /etc/rc.local

set locale

true > /etc/sysconfig/i18n

cat >>/etc/sysconfig/i18n<<EOF

LANG="zh_CN.GB18030"

SUPPORTED="zh_CN.GB18030:zh_CN:zh:en_US.UTF-8:en_US:en"

SYSFONT="latarcyrheb-sun16"

EOF

set sysctl

true > /etc/sysctl.conf
cat >> /etc/sysctl.conf << EOF
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 87380 4194304
net.ipv4.tcp_wmem = 4096 16384 4194304
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.netdev_max_backlog = 262144
net.core.somaxconn = 262144
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_fin_timeout = 1
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 1024 65535
EOF
/sbin/sysctl -p
echo "sysctl set OK!!"

close ctrl+alt+del

sed -i "s/ca::ctrlaltdel:\/sbin\/shutdown -t3 -r now/#ca::ctrlaltdel:\/sbin\/shutdown -t3 -r now/" /etc/inittab

set purview

chmod 600 /etc/passwd
chmod 600 /etc/shadow
chmod 600 /etc/group
chmod 600 /etc/gshadow

disable ipv6

cat << EOF
+--------------------------------------------------------------+
|     === Welcome to Disable IPV6 ===                  |
+--------------------------------------------------------------+
EOF
echo "alias net-pf-10 off" >> /etc/modprobe.conf
echo "alias ipv6 off" >> /etc/modprobe.conf
/sbin/chkconfig --level 35 ip6tables off
echo "ipv6 is disabled!"

disable selinux

sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config
echo "selinux is disabled,you must reboot!"

vim

sed -i "8 s/^/alias vi='vim'/" /root/.bashrc
echo 'syntax on' > /root/.vimrc

zh_cn

sed -i -e 's/^LANG=.*/LANG="en"/'  /etc/sysconfig/i18n

init_ssh

ssh_cf="/etc/ssh/sshd_config"
sed -i -e '74 s/^/#/' -i -e '76 s/^/#/' $ssh_cf

sed -i "s/#Port 22/Port 65535/" $ssh_cf

sed -i "s/#UseDNS yes/UseDNS no/" $ssh_cf

client

sed -i -e '44 s/^/#/' -i -e '48 s/^/#/' $ssh_cf
service sshd restart
echo "ssh is init is ok.............."

chkser

tunoff services

---------------------------------------------------------------------------

cat << EOF
+--------------------------------------------------------------+
|     === Welcome to Tunoff services ===                 |
+--------------------------------------------------------------+
EOF

---------------------------------------------------------------------------

for i in 'ls /etc/rc3.d/S*'
do
      CURSRV='echo $i|cut -c 15-'
echo $CURSRV
case $CURSRV in
     crond | irqbalance | microcode_ctl | network | random | sshd | syslog | local )
   echo "Base services, Skip!"
   ;;
   *)
     echo "change $CURSRV to off"
     chkconfig --level 235 $CURSRV off
     service $CURSRV stop
   ;;
esac
done
echo "service is init is ok.............."

时间: 2024-10-03 23:57:52

《构建高可用Linux服务器 第3版》—— 3.6 生产环境下的Shell脚本分类的相关文章

《构建高可用Linux服务器 第3版》—— 导读

前言 我的系统架构师之路 2004年我初识UNIX开源系统.那会儿我正在一家大型国有企业做系统管理员,负责值守公司的Windows Server 2000服务器.当时"震荡波"和"冲击波"这两种病毒很猖狂,虽然我们在防毒方面投入了大量的精力和金钱(当时购买的都是正版Windows 2000系统和正版瑞星杀毒软件),但新上线的机器,偶尔也有遗漏的时候,没有打补丁的机器无一幸免,所以对这个问题比较头疼.有一次去朋友的公司(某省太平洋寿险下面的一个分支机构)参观,我发现他

《构建高可用Linux服务器 第3版》—— 第3章 生产环境下的Shell脚本

第3章 生产环境下的Shell脚本 虽然Shell脚本只是一个简单的解释型语言,不会受到开发人员的重视,但对于我们系统管理员来说它有着举足轻重的作用,它可以帮助我们简化日常的工作并减少工作量,成为系统管理员的瑞士军刀.我们在系统维护工作中用Shell脚本常常能比用C语言编写的程序更快地解决相同的问题.此外,Shell脚本具有很好的可移植性,有时跨越UNIX与POSIX兼容的系统,仅需略作修改,甚至不必修改即可使用Shell脚本. 在日常工作中Shell脚本能帮助我们做什么呢? 1)配合Cront

《构建高可用Linux服务器 第3版》—— 1.6 用开源工具Nagios监控Linux服务器

1.6 用开源工具Nagios监控Linux服务器 1.6.1 CentOS 5.8下的监控工具 在开源系统CentOS 5.8下有许多监控工具,比如实时监控系统状态的Nagios,还有监控网络流量的Cacti和MRTG,以及我个人比较喜欢的NTOP和Iptraf:另外,在CentOS 5.8下也有许多强大的命令行可用于监控系统状态,大家可以在Google上搜索以了解其具体用法. 1.6.2 Nagios应该监控的服务器基础选项 经过工作实践,我们认为Nagios应该监控服务器的参数有如下几个方

《构建高可用Linux服务器 第3版》—— 第2章 生产环境下服务器的故障诊断与排除

第2章 生产环境下服务器的故障诊断与排除 服务器系统与我们平时用的办公系统和家庭用的基于Windows PC的系统不一样,它要求能365×24小时不间断运行,以便为我们提供服务.有些朋友喜欢在Windows PC端下用Ghost软件来重新恢复已经严重崩溃的系统,不过此举对于服务器系统而言却没有任何意义.我们在系统发生故障时会尝试修复它,而不是重装.请大家记住服务器系统与Windows PC系统的区别.

《构建高可用Linux服务器 第3版》—— 2.8 小结

2.8 小结 在处理生产环境下的服务器故障时,应该本着安全的原则,在尽可能短的时间内处理问题,恢复服务器的正常状态.平时的系统维护工作,在多备份的前提下,也应该本着谨慎小心的原则,减少失误,毕竟我们不可能将每一项重要应用服务都做成集群模式,有些重要业务应该准备备份服务器,这样在出现问题时可以手动将备份的服务器换上去,然后再来解决故障服务器上的问题.另外,我们在用Xmanager 3.0远程管理多台线上服务器时,应该养成的好习惯是操作完一台就退出这一台的窗口,以免将其当成了测试服务器,从而发生误操

《构建高可用Linux服务器 第3版》—— 第1章 Linux服务器的构建基础

第1章 Linux服务器的构建基础 在从事目前的系统架构师工作之前,很长一段时间我从事的是系统管理员/高级系统管理员工作.在企业日常运营中,我的工作涉及的内容主要有电子商务网站的运维.内网开发环境的部署.公司外包项目的实施等.在这些工作中,我用到的系统绝大多数是免费开源的CentOS 5.8 x86_64系统,它的稳定和高效令我印象深刻.本章将以CentOS 5.8 x86_64的生产服务器为平台,逐步介绍它的Kickstart无人值守安装.网络配置.日志分析.性能状态监控,以及它的最小化优化等

《构建高可用Linux服务器 第3版》—— 1.5 Linux服务器的优化

1.5 Linux服务器的优化 服务器的优化是我们最小化安装系统时应该做的事情.其实,在做这项工作之前,我们就应该根据实际应用需求来选购Linux服务器,然后有所偏重地选择硬件,比如我们应该根据服务器的应用来确定是需要RAID 5,还是单块硬盘等. 1.5.1 如何根据服务器应用来选购服务器 无论是租用还是托管都要面临一个问题,那就是选择服务器的硬件配置,前面也说了,选购硬件配置时要根据我们的服务器应用需求而定.因为你无法通过一台服务器来满足所有的需求,解决所有的问题.在项目实施或网站架构之前,

《构建高可用Linux服务器 第3版》—— 2.4 系统维护时应该注意的地方

2.4 系统维护时应该注意的地方 无论是自己的内网开发机器还是线上的生产机器,我们在操作时都应该谨慎,否则系统很容易发生Crash的情况.就算我们能用备份很快恢复,在恢复时间之内,我们也会损失大量的数据,而且如果万一恢复不了,那就是灾难性的了. 2.4.1 服务器硬件改动进入了Emergency模式 同事在处理一台CentOS 5.8服务器时,他在机器上移走了一块硬盘,然后就直接启动机器,忽然发现系统进了Emergency模式,于是他连忙跑过来找我.我第一句就是问他:你改动了硬件没?他说他移走硬

《构建高可用Linux服务器 第3版》—— 1.4 Linux服务器的日志管理

1.4 Linux服务器的日志管理 从安全的角度来说,Linux服务器的日志非常重要,它记录了系统每天所发生的各种各样的事情,如果服务器受到攻击,就可以根据它来进行分析.同时,它更是很重要的排障依据,可以通过它来检查错误发生的原因,所以我们必须了解和熟悉其运作机制. 1.4.1 系统日志syslog.conf的配置详解 目前,Linux依旧使用syslog作为日志监控进程,对其进行必要的配置能减少很多麻烦,并且可更有效地从系统日志监控到系统的状态.理解并完善一个syslog的配置,对于系统管理员