我本是Java高階開發,去年換了家公司,當時沒有運維,讓我來搞搞著試試。結果在運維的道路上越走越遠。。。從此兼職了公司的運維,老闆可高興壞了。這次分享一篇當時寫釋出指令碼的經歷,希望能你有所幫助。
前言
- 此配置充分考慮了釋出中的各種細節,適用於分散式釋出。
- 此配置中流程模仿自去哪兒網,在此表示感謝。
- 配置的時候身邊沒有運維大佬交流(畢竟我是Java開發),如有不足的地方歡迎評論指正。
大致流程
擦。。。掘金的Markdown按照cmdMarkdown中教程畫不出流程圖,知道怎麼畫圖的大佬救救孩子吧。
gitclone程式碼-->檢測程式碼-->構建jar包-->上傳jar包-->閘道器下線-->執行jar包-->閘道器上線-->檢測服務
流程細節和Jenkins配置
Jenkins配置部分建議對照截圖看
gitclone程式碼
Jenkins的plugin中安裝Git相關外掛用於clone程式碼,下圖中${group}等為parameterized的引數,許可權沒有設定的那麼細(其實是偷懶),所以沒有按專案配置不同的job。不建議學我。
檢測程式碼
通常可以用sonar檢測,配置sonar程式碼檢測規則,程式碼質量不合格直接打回,避免無效釋出。
構建jar包
我用maven構建的jar包;war包配個tomcat還方便控制埠,一樣的原理。Jenkins中也要下載maven相關plugins。
這裡多了Pre Steps,每次構建前刪除部分jar包。因為開發沒有規範使用SNAPSHOT,所有依賴都用RELEASE,導致每次改動底層jar包後都讓我手動去伺服器刪除老jar包。所以我機智的在每次構建前把所有的老jar包都刪除了。這個操作也不規範,不要學習。
mvn命令是
clean package -Dmaven.test.skip=true -P test
上傳jar包
用的外掛是Publish over SSH,這裡的關鍵是連線上遠端伺服器。
shell 指令碼
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包
這裡我做了回滾,所以如果釋出的話會把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,指令碼內容類似。
自我感覺這一套還可以,不知道各路大佬怎麼看,還請多多指教,畢竟第一次搞運維。。。我感覺在開發的路上越走越遠了。。。。