脚本实现功能,从本地上传war包到指定服务器的指定目录,停止对应tomcat进程,替换上个版本的war包并进行备份(以防线上问题出现意外可以进行回滚)。
第一个脚本主要是上传war包到指定服务器的指定目录,shell脚本参考如下,在本地或者发布机器上运行:
#/bin/bash set -e cur_date=`date +‘%Y%m%d %H:%M:%S‘` current_day=`date +"%Y%m%d"` read -p "1.部署生产环境 2.测试环境 " nu echo $nu if [ ${nu} -eq 1 ] then read -p "请选择部署服务器ip: 1. nginx-server 2. app-server 3. app-pay 4. pay-server 5. redis1 6. redis2 " nu1 case ${nu1} in 1) ip_addr=IP1 ;; 2) ip_addr=IP2 ;; 3) ip_addr=IP3 ;; 4) ip_addr=IP4 ;; 5) ip_addr=IP5 ;; 6) ip_addr=IP6 ;; *) echo -e "请输入1~4的数字\n" exit 1 ;; esac elif [ ${nu} -eq 2 ] then read -p "请选择部署服务器ip 1. IP7 2. IP8 " nu2 case ${nu2} in 1) ip_addr=IP7 ;; 2) ip_addr=IP8 ;; *) echo -e "请输入1~2的数字\n" exit 1 ;; esac else echo -e "请选择正确的部署环境\n" exit 1 fi read -p "请输入部署服务器上传目录:" dir read -p "请输入部署war包名称:" war_name S_PATH=`pwd` echo "********** "$cur_date" *******" sleep 1 echo "******** 开始上传war包 *******" ssh [email protected]${ip_addr} "mkdir -p /${dir}/${current_day}" read -p "是否已经上传过war包:1,是 2,否 " nu3 if [ $nu3 -eq 2 ] then scp ./${war_name}.war [email protected]${ip_addr}:/${dir}/${current_day} else echo -e "跳过上传,继续进行部署" fi scp ./deploy_finance.sh [email protected]${ip_addr}:/${dir}/${current_day} echo -e "********开始进行部署***********" ssh -t [email protected]${ip_addr} "sh ${dir}/${current_day}/deploy.sh $dir $war_name"
第二个脚本即上个脚本中提到的deploy.sh脚本,主要用来停止对应tomcat进程,替换上个版本的war包并进行备份,运行在tomcat应用服务器上
#/bin/bash set -e #*******设置系统临时环境变量******** read -p "是否需要设置环境变量,请根据部署环境选择 1.生产环境不需要 2.测试环境需要 " nu if [ ${nu} -eq 2 ] then echo -e "*****设置系统临时环境变量******" export JAVA_HOME=/usr/local/java/jdk1.7.0_79 export PATH=$PATH:$JAVA_HOME else echo -e "跳过变量设置,继续部署" fi #*******部署服务******* #********************* #*******停止服务******** function deploy_war { file_war=$1 echo -e "*****INFO: 停止服务*******" _PID=`ps -ef|grep -w "${deploy_dir}"|grep -v grep|awk ‘{print $2}‘` if [ 8${_PID} -eq 8 ] then echo -e "进程不在运行,直接部署\n" else echo -e "${_PID}" cd ${deploy_dir} kill -9 ${_PID} sleep 3 _PID=`ps -ef|grep -w "${deploy_dir}"|grep -v grep|awk ‘{print $2}‘` if [ 8${_PID} -ne 8 ];then echo -e "*********${file_war}进程停止失败,请检查日志,部署脚本退出********" exit 1 else echo -e "********${file_war}进程已停止*********" fi fi #*********删除文件目录,备份war包********* if [ -d "${deploy_dir}/webapps" ]; then cd ${deploy_dir}/webapps echo -e "*********INFO: 切换目录成功" rm -rf ./${file_war} if [ $? -ne 0 ];then echo -e "*********${file_war}目录删除失败,退出部署************" exit 1 else echo -e "**********${file_war}目录删除成功,继续部署***********" fi tar -zcvf ${file_war}${current_day}.war.tar.gz ${file_war}.war if [ $? -ne 0 ];then echo -e "************备份失败,退出部署************" exit 1 else echo -e "***********备份成功,继续部署*************" fi cp -a /$dir/${current_day}/${file_war}.war /${deploy_dir}/webapps if [ $? -eq 0 ];then echo -e "******************war包拷贝成功***********" else echo -e "******************war包拷贝失败,退出部署***************" exit 1 fi else echo -e "************webapps目录不存在,请创建tomcat目录,退出部署******\n" exit 1 fi #********** 重启应用 *********** echo -e "*********INFO:启动服务***********\n" cd ${deploy_dir} rm -rf work rm -rf temp/* cd ${deploy_dir}/bin setsid ./startup.sh _PID1=`ps -ef|grep -w "${deploy_dir}"|grep -v grep|awk ‘{print $2}‘` sleep 8 if [ 8$[_PID1] -eq 8 ];then echo -e "************** ERROR:${file_war}启动失败,请检查启动日志***********\n" exit 1 else echo "**********${file_war}启动完毕" fi } dir=$1 war_name=$2 current_day=`date +"%Y%m%d"` if [ -d "${dir}/${current_day}" ]; then echo -e "**********INFO: ${current_day}目录已经存在,请忽略。\n" else mkdir -p ${dir}/${current_day} fi if [ $# -ne 2 ];then echo -e "******执行部署脚本时需要传入安装包存放目录********\n" echo -e "******即将退出部署\n" echo -e "******脚本执行方式,例如: ./deploy_finance.sh /mnt app " exit 1 fi read -p "*********请选择部署目录: 1. dir1 2. dir2 3. dir3 4. dir4 5. dir5 6. dir6 7. dir7 8. dir8 " nu_dir case ${nu_dir} in 1) deploy_dir=dir1 ;; 2) deploy_dir=dir2 ;; 3) deploy_dir=dir3 ;; 4) deploy_dir=dir4 ;; 5) deploy_dir=dir5 ;; 6) deploy_dir=dir6 ;; 7) deploy_dir=dir7 ;; 8) deploy_dir=dir8 ;; *) echo -e "请选择正确的部署目录,即将退出部署/n" exit 1 esac deploy_war ${war_name}
这里记录踩下的两个坑:
1.最初脚本写完之后是在测试环境下运行的,测试环境的JAVA目录并没有做软连接到/usr/bin下,只要运行部署脚本,tomcat都会因为找不到java_home的路径而报错,但是ssh到服务器上是能够正常启动的,看了一下/etc/profile文件的内容,之前的兄弟是把java环境变量放在这个文件做导入的,那么为什么ssh到服务器上去到tomcat/bin目录下执行./startup.sh能正常启动呢,./startup.sh是继承当前shell环境变量的,当你ssh 到服务器的时候,属于login shell,会去读取/etc/profile中的文件内容,自然会加载java的环境变量,而在远程脚本中执行./startup.sh,此时启动的shell子进程会继承父进程deploy.sh的环境变量,而这对父子进程都是属于no login shell,不会去读取/etc/profile的内容,但是它会去读取~/.bashrc中的内容,后来我去这个文件中设置java环境变量之后确实启动正常了。
2.第二个坑是最初在deploy.sh脚本中启动tomcat的时候,直接用的是./startup.sh,导致的结果就是每次发布的时候,本地从服务器上分配的伪终端显示tomcat进程启动成功,但是登录服务器进行检查的时候发现对应的tomcat根本没有启动成功。后来想了半天,原来是因为这种方式启动的tomcat进程是属于对应的sshd的子进程,当脚本运行完毕之后,对应的sshd进程结束之后,服务器收到singalhup,也会把其进程树下的子进程停掉。解决的方式就是用nohup或者setsid去启动tomcat,相应的命令解释有需求的同学可以谷歌一哈。
后续展望:
1.看能否用jenkins缩短发布时间,但是因为用的是阿里金融云且svn服务器是在公司本地的一台物理机上,且金融云环境和公司网络无法进行通讯(安全第一),用jenkins做持续集成和发布难以做到
2.总觉得shell语法不人性化,后面加强一下python学习,看能否用python完全代替掉shell
3.不知道大家有没有相关工具推荐一下,主要解决的痛点是要去特定的服务器上替换特定的文件
*******************************************
做为一个运维新手且木有人带,真是压力山大,记得之前有个前辈说过写出来的东西才是自己的,特此感谢博客园批准俺开通了微博来记录自己的学习经历和成长过程,上述文章如果有错误的地方或者童鞋们有更好的想法欢迎大家指出,也可以加我微信大家一起交流