一、安装jenkins

注:这里不多说哈,百度遍地都是,安装方式不限,默认选择将推荐插件都安装,然后安装两个需要使用到的插件。

调用脚本插件:Conditional BuildStep
控制台时间戳插件:timestamper

二、jenkins创建项目

注:这里有个坑需要说一下,最开始我使用的是maven构建,但是如果按照我的这套方案会有一个编译死循环的问题,也就是说我本来是通过脚本来判断是编译构建新包或者是回滚旧包,但是问题来了,使用maven构建项目的话即使上边有脚本判断还是跳不出编译这一步,也就是说不管你是发布新版本还是旧版本都会重新编译一遍,那么坑的点是什么呢?发布的时候会编译两次,回滚的时候也是会编译两次,正常回滚就是不需要编译的直接将包传送过来启动即可,经过各种尝试后,终于找到问题点在哪?使用maven构建项目的话它自带的maven项无法关掉,所以就会造成上边脚本的编译和下边的maven编译重复,最终的解决方案:不使用maven构建项目,使用其他的比如我这里用的是自由风格,这样的话可以根据我们的需求来选择用不用maven编译,然后只需要在脚本里判断如果是发布新版本那么就调用maven编译并发布,如果是回滚操作那么将直接跳过编译即可。 重点:跳过编译你会发现回滚最多三五秒,这样的话对于我们运维来说缩短了回滚的时间,同时降低了用户访问失败的时长。

三、配置自动发布和回滚的脚本

1、丢弃旧的构建

WechatIMG12.jpg 注:以上配置根据自己需求调整就行。

2、参数化构建

WechatIMG13.jpg

3、字符参数

WechatIMG14.jpg

4、源码管理

WechatIMG15.jpg

5、构建环境

WechatIMG16.jpg 注:以上选项主要是为了统计编译构建和回滚的时长。

6、Build Steps

WechatIMG17.jpg WechatIMG18.jpg 注:上图中的maven版本我这里是自己安装的这个版本所以配置选择了这个,如果没有提前配置的话就是默认选项。

#!/bin/bash
if [ -z $version ];then 
  echo "need build" 
  exit 0
else
  echo "no need build"
  exit -1
fi
clean install -Pprod -U -Dmaven.test.skip=true
pom.xml

7、执行shell

WechatIMG19.jpg 注:这里截图为了清楚就大概截一下图,具体详细信息在下边单独输出。

###########################################
case $deploy_environment  in
  deploy)
    echo "deploy $deploy_env"
    #mvn install -Dmaven.test.skip=true -e
    #创建每次要备份的目录
    path="${WORKSPACE}/bak/${BUILD_NUMBER}"      
    echo "$path"
    echo "-d $path"
    if [ -d $path ];
    then
        echo "The files is already  exists "
    else
        mkdir -p  $path
    fi
    #因为代码有双层目录,而target目录是在第二层目录里,所以在第一层创建一个新target目录
    #\mkdir -p $WORKSPACE/target/
    #将打包好的jar包重新定义新目录
    #\cp -f $WORKSPACE/cjkj-account-server/target/*.jar $WORKSPACE/target/
    #将打包好的jar包备份到相应目录,覆盖已存在的目标
    \cp -f $WORKSPACE/target/*.jar $path
    echo "Completing!"
    ;;
  rollback)
    echo "rollback $deploy_env  version=$version"
    ############创建回滚的jar包数据目录##########################
    #注:为了防止出现不断发布新版本,再不断修改和发布后,不知道该回滚哪个版本是没问题的版本
    #创建每次要备份的目录
    path="${WORKSPACE}/bak/${BUILD_NUMBER}"      
    echo "$path"
    echo "-d $path"
    if [ -d $path ];
    then
        echo "The files is already  exists "
    else
        mkdir -p  $path
    fi
    ##############
    #进入备份目录
    cd ${WORKSPACE}/bak/$version
    #这里cjkj-sass-web是你打包的jar包的名字
    if [ -d ${WORKSPACE}target/ ];        
    then
      echo "The files is already  exists "
    else
       mkdir -p  ${WORKSPACE}/target/
    fi
    #将备份拷贝到程序打包目录中,并覆盖之前的jar包
    \cp -f *.jar ${WORKSPACE}/target/
    ######拷贝回滚jar包到最新备份目录保证最新备份永远是没问题的jar包########
    \cp -f *.jar $path
    echo "Completing!"
    ####################################
    ;;
  *)
  esac
#####################################################  
#保留文件数
ReservedNum=5
FileDir=${WORKSPACE}/bak/
date=$(date "+%Y%m%d-%H%M%S") 
#进入备份目录
cd $FileDir
#当前有几个文件夹,即几个备份
FileNum=$(ls -l | grep '^d' | wc -l) 
while(( $FileNum > $ReservedNum))
do
#获取最旧的那个备份文件夹
    OldFile=$(ls -rt | head -1)
    echo  $date "Delete File:"$OldFile
    rm -rf $FileDir/$OldFile
    let "FileNum--"
done

8、执行shell

WechatIMG20.jpg

#设置项目名的变量
project="cjkj-sassweb"
#创建应用服务器的所需目录
ssh  jenkins@IP地址 "mkdir -p /data/apps/$project/{temp,logs}"
ssh  jenkins@IP地 "mkdir -p /data/logs/$project"
#使用机器上脚本进行服务更新过程
ssh  jenkins@IP地 "bash /data/apps/deploy.sh $project"

四、配置java应用节点的shell脚本

#!/bin/bash

#将jenkins的第一个变量参数传递过来$1=cjkj-appweb
PROJECT="$1"

#判断Jenkins的变量参数是否传递过来
if [ -z "$PROJECT" ]; then
   echo "cannot be empty"
   exit 1
else
   echo "传递参数:$PROJECT"
fi

#将jar包路径和日志路径赋值
DEPLOY_DIR="/data/apps/$PROJECT"
APP_LOG="/data/logs/$PROJECT"

#将java应用的物理限制赋值
JAVA_OPTS="-Xms512m -Xmx512m -Xmn256m -Xss256K -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m"

#定义当前环境(测试环境或者线上环境)
springProf="test"
#springProf="prod"

#刷新环境变量
source /etc/profile
[ -f "${DEPLOY_DIR}/.env" ] && source $DEPLOY_DIR/.env

#停止old版本应用
pid=$(jps | grep $PROJECT | awk '{print $1}')
if [ -n "$pid" ]; then
    kill -15 $pid
    sleep 15
    ps aux | grep $pid
    if [ $? -eq 0 ]; then
        kill -9 $pid
        echo "强制killed进程"
    else
        echo "进程已结束"    
    fi
else
    echo "no pid"
fi

#拷贝新的jar包到指定服务器的指定目录
scp root@172.16.148.135:/var/lib/jenkins/workspace/$PROJECT/target/*.jar  /data/apps/$PROJECT/$PROJECT.jar
if [ $? -eq 0 ]; then
   echo "将新的jar包拷贝到指定目录"
else
   echo "jar包拷贝失败"
fi

#启动new版本应用
nohup  java  -Dbasedir=${DEPLOY_DIR} -DLOGS_FOLDER=${APP_LOG} ${JAVA_OPTS}  -Dfile.encoding=UTF-8 -Djava.io.tmpdir=${DEPLOY_DIR}/temp  \
-Dsecurerandom.source=file:/dev/urandom -Djava.security.egd=file:/dev/./urandom -Dnetworkaddress.cache.ttl=10 -Dsun.net.inetaddr.ttl=10 \
-verbose:gc -Xloggc:${APP_LOG}/gc_start_at_`date '+%Y%m%d%H%M%S'`.log \
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+DisableExplicitGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSParallelInitialMarkEnabled -XX:+PrintGCDetails -XX:+CMSScavengeBeforeRemark -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=${APP_LOG}/dump.hprof -DAPP_LOG_HOME=${APP_LOG}/ \
-XX:ErrorFile=${APP_LOG}/java_error.log  -server -jar ${DEPLOY_DIR}/*.jar --spring.profiles.active=$springProf  --server.tomcat.accesslog.enabled=true > $APP_LOG/start_`date '+%Y%m%d%H%M%S'`.log &

#检查新版本应用是否健康启动
ps aux | grep $PROJECT | grep -v grep
if [ $? -eq 0 ]; then
   echo "$PROJECT running"
else
   echo "$PROJECT Startup failed"
fi