我本是Java高级开发,去年换了家公司,当时没有运维,让我来搞搞着试试。结果在运维的道路上越走越远。。。从此兼职了公司的运维,老板可高兴坏了。这次分享一篇当时写发布脚本的经历,希望能你有所帮助。
点击查看Jenkins配置截图
擦。。。掘金的Markdown按照cmdMarkdown中教程画不出流程图,知道怎么画图的大佬救救孩子吧。
gitclone代码-->检测代码-->构建jar包-->上传jar包-->网关下线-->运行jar包-->网关上线-->检测服务
Jenkins配置部分建议对照截图看
Jenkins的plugin中安装Git相关插件用于clone代码,下图中${group}等为parameterized的参数,权限没有设置的那么细(其实是偷懒),所以没有按项目配置不同的job。不建议学我。
通常可以用sonar检测,配置sonar代码检测规则,代码质量不合格直接打回,避免无效发布。
我用maven构建的jar包;war包配个tomcat还方便控制端口,一样的原理。Jenkins中也要下载maven相关plugins。
这里多了Pre Steps,每次构建前删除部分jar包。因为开发没有规范使用SNAPSHOT,所有依赖都用RELEASE,导致每次改动底层jar包后都让我手动去服务器删除老jar包。所以我机智的在每次构建前把所有的老jar包都删除了。这个操作也不规范,不要学习。
mvn命令是 clean package -Dmaven.test.skip=true -P test
用的插件是Publish over SSH,这里的关键是连接上远程服务器。
shell脚本实现了网关下线、运行jar包、网关上线、检测服务。先来个总览,再细说。
#!/bin/bash source /etc/profile source /home/java/.bash_profile cd /home/java/jar #发送eureka下线指令 offline=`curl -X -o /dev/null DELETE "http://192.168.30.230:4011/$project/health/offline/018ee962eab6431393540d5eb33s43hs2" -H "accept: */*" ` echo "请求完成,响应内容是$offline" #sleep 3s 保证已经打到的请求完整返回 sleep 3s #下线后停止服务 ./springboot.sh stop $project-test # 构建 or 回滚 echo $action if [ "$action" == "build" ] then #备份之前构建 mkdir -p backup/$BUILD_NUMBER mv $project-test.jar backup/$BUILD_NUMBER cp target/$project-test.jar . elif [ "$action" == "rollback" ] then cp backup/$buildId/$project-test.jar . else exit 1 fi #保留Jenkins衍生进程 BUILD_ID=DONTKILLME ./springboot.sh start $project-test #启动后等待上线时间 sleep 10s #判断服务是否上线成功 for i in {1..10} do code=`curl -I -m 10 -o /dev/null -s -w %{http_code} -X GET "http://192.168.30.230:4011/$project/health/check" -H "accept: */*"` sleep 3s if [ "$code" == "200" ];then echo "第$i次尝试,上线成功,响应码是$code" exit 0 else echo "第$i次尝试,上线失败,响应码是$code" fi done exit 复制代码
我在代码中写了让服务器下线gateway的接口,为了安全性,做了key的拦截。
public static final String KEY = "018ee962eab6431393540d5eb337131230a12"; @GetMapping("/check") public String healthCheck() { return "service is running health"; } @DeleteMapping("/offline/{key}") public String offLine(@PathVariable String key) { if (ObjectUtils.equals(KEY, key)) { DiscoveryManager.getInstance().shutdownComponent(); return "下线成功"; } else { return "下线失败,秘钥错误"; } } 复制代码
需要注意的是,服务器下线后不能立马重启,因为下线后新请求不会打过来,但可能有已经打进来的请求还没返回出去,所以要等3s把所有进来请求都安全返回。
#发送eureka下线指令 offline=`curl -X -o /dev/null DELETE "http://192.168.30.230:4011/$project/health/offline/018ee962eab6431393540d5eb33s43hs2" -H "accept: */*" ` echo "请求完成,响应内容是$offline" #sleep 3s 保证已经打到的请求完整返回 sleep 3s 复制代码
这里我做了回滚,所以如果发布的话会把jar包保存到backup,是回滚就从构建开始拦截,直接cp backup里指定的jar包,我用$BUILD_NUMBER区分备份。springboot.sh是项目运行脚本。
# 构建 or 回滚 echo $action if [ "$action" == "build" ] then #备份之前构建 mkdir -p backup/$BUILD_NUMBER mv $project-test.jar backup/$BUILD_NUMBER cp target/$project-test.jar . elif [ "$action" == "rollback" ] then cp backup/$buildId/$project-test.jar . else exit 1 fi #保留Jenkins衍生进程 BUILD_ID=DONTKILLME ./springboot.sh start $project-test 复制代码
以下是springboot脚本内容
#!/bin/bash # RUNNING_USER=jianzhangg ADATE=`date +%Y%m%d%H%M%S` APP_NAME=$2 echo $APP_NAME APP_HOME=`pwd` dirname $0|grep "^/" >/dev/null if [ $? -eq 0 ];then APP_HOME=`dirname $0` else dirname $0|grep "^/." >/dev/null retval=$? if [ $retval -eq 0 ];then APP_HOME=`dirname $0|sed "s#^.#$APP_HOME#"` else APP_HOME=`dirname $0|sed "s#^#$APP_HOME/#"` fi fi if [ ! -d "$APP_HOME/logs" ];then mkdir $APP_HOME/logs fi LOG_PATH=$APP_HOME/logs/$APP_NAME.log GC_LOG_PATH=$APP_HOME/logs/gc-$APP_NAME-$ADATE.log if [ ! -f "$LOG_PATH" ]; then touch "$LOG_PATH" fi if [ ! -f "$GC_LOG_PATH" ]; then touch "$GC_LOG_PATH" fi #JMX监控需用到 JMX="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false" #JVM参数 JVM_OPTS="-Dname=$APP_NAME -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" JAR_FILE=$APP_NAME.jar pid=0 start(){ checkpid if [ ! -n "$pid" ]; then nohup java -jar $JVM_OPTS $JAR_FILE > $LOG_PATH 2>&1 & # JAVA_CMD="nohup java -jar $JVM_OPTS $JAR_FILE > $LOG_PATH 2>&1 &" # su - $RUNNING_USER -c "$JAVA_CMD" echo "---------------------------------" echo "启动完成,按CTRL+C退出日志界面即可>>>>>" echo "---------------------------------" sleep 20s tail -n 500 $LOG_PATH # sleep 20s # exit else echo "$APP_NAME is runing PID: $pid" fi } status(){ checkpid if [ ! -n "$pid" ]; then echo "$APP_NAME not runing" else echo "$APP_NAME runing PID: $pid" fi } checkpid(){ pid=`ps -ef |grep "Dname=$APP_NAME" |grep -v grep |awk '{print $2}'` } stop(){ checkpid if [ ! -n "$pid" ]; then echo "$APP_NAME not runing" else echo "$APP_NAME stop..." kill -9 $pid fi } restart(){ stop sleep 1s start } case $1 in start) start;; stop) stop;; restart) restart;; status) status;; *) echo "require start|stop|restart|status" ;; esac 复制代码
springGateway服务重启后会自动上线;以前在去哪儿里面用的nginx,有个healthcheck.html做上下线,通过ping html判断tomcat是否启动。我这里也是在项目里面写了接口,通过请求接口判断。
#判断服务是否上线成功 for i in {1..10} do code=`curl -I -m 10 -o /dev/null -s -w %{http_code} -X GET "http://192.168.30.230:4011/$project/health/check" -H "accept: */*"` sleep 3s if [ "$code" == "200" ];then echo "第$i次尝试,上线成功,响应码是$code" exit 0 else echo "第$i次尝试,上线失败,响应码是$code" fi done 复制代码
以上是完整的发布流程,如果分布式环境需要在Jenkins配置post step,脚本内容类似。
自我感觉这一套还可以,不知道各路大佬怎么看,还请多多指教,毕竟第一次搞运维。。。我感觉在开发的路上越走越远了。。。。