我本是Java高级开发,去年换了家公司,当时没有运维,让我来搞搞着试试。结果在运维的道路上越走越远。。。今后兼职了公司的运维,老板可高兴坏了。此次分享一篇当时写发布脚本的经历,但愿能你有所帮助。html
点击查看Jenkins配置截图java
擦。。。掘金的Markdown按照cmdMarkdown中教程画不出流程图,知道怎么画图的大佬救救孩子吧。nginx
gitclone代码-->检测代码-->构建jar包-->上传jar包-->网关下线-->运行jar包-->网关上线-->检测服务git
Jenkins配置部分建议对照截图看spring
Jenkins的plugin中安装Git相关插件用于clone代码,下图中${group}等为parameterized的参数,权限没有设置的那么细(实际上是偷懒),因此没有按项目配置不一样的job。不建议学我。 shell
一般能够用sonar检测,配置sonar代码检测规则,代码质量不合格直接打回,避免无效发布。tomcat
我用maven构建的jar包;war包配个tomcat还方便控制端口,同样的原理。Jenkins中也要下载maven相关plugins。安全
这里多了Pre Steps,每次构建前删除部分jar包。由于开发没有规范使用SNAPSHOT,全部依赖都用RELEASE,致使每次改动底层jar包后都让我手动去服务器删除老jar包。因此我机智的在每次构建前把全部的老jar包都删除了。这个操做也不规范,不要学习。springboot
mvn命令是 clean package -Dmaven.test.skip=true -P test
bash
用的插件是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,脚本内容相似。
自我感受这一套还能够,不知道各路大佬怎么看,还请多多指教,毕竟第一次搞运维。。。我感受在开发的路上越走越远了。。。。
欢迎关注微信公众号,提供思想和技术类原创文章。微信搜索小兵张健或扫描如下二维码。