我本是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,腳本內容相似。
自我感受這一套還能夠,不知道各路大佬怎麼看,還請多多指教,畢竟第一次搞運維。。。我感受在開發的路上越走越遠了。。。。
歡迎關注微信公衆號,提供思想和技術類原創文章。微信搜索小兵張健或掃描如下二維碼。