怎麼用Jenkins配置分散式環境的安全釋出?

小兵張健發表於2019-04-18

我本是Java高階開發,去年換了家公司,當時沒有運維,讓我來搞搞著試試。結果在運維的道路上越走越遠。。。從此兼職了公司的運維,老闆可高興壞了。這次分享一篇當時寫釋出指令碼的經歷,希望能你有所幫助。

前言

  • 此配置充分考慮了釋出中的各種細節,適用於分散式釋出。
  • 此配置中流程模仿自去哪兒網,在此表示感謝。
  • 配置的時候身邊沒有運維大佬交流(畢竟我是Java開發),如有不足的地方歡迎評論指正。

大致流程

點選檢視Jenkins配置截圖

擦。。。掘金的Markdown按照cmdMarkdown中教程畫不出流程圖,知道怎麼畫圖的大佬救救孩子吧。

gitclone程式碼-->檢測程式碼-->構建jar包-->上傳jar包-->閘道器下線-->執行jar包-->閘道器上線-->檢測服務

流程細節和Jenkins配置

Jenkins配置部分建議對照截圖看

gitclone程式碼

Jenkins的plugin中安裝Git相關外掛用於clone程式碼,下圖中${group}等為parameterized的引數,許可權沒有設定的那麼細(其實是偷懶),所以沒有按專案配置不同的job。不建議學我。

怎麼用Jenkins配置分散式環境的安全釋出?

怎麼用Jenkins配置分散式環境的安全釋出?

檢測程式碼

通常可以用sonar檢測,配置sonar程式碼檢測規則,程式碼質量不合格直接打回,避免無效釋出。

構建jar包

我用maven構建的jar包;war包配個tomcat還方便控制埠,一樣的原理。Jenkins中也要下載maven相關plugins。

怎麼用Jenkins配置分散式環境的安全釋出?

這裡多了Pre Steps,每次構建前刪除部分jar包。因為開發沒有規範使用SNAPSHOT,所有依賴都用RELEASE,導致每次改動底層jar包後都讓我手動去伺服器刪除老jar包。所以我機智的在每次構建前把所有的老jar包都刪除了。這個操作也不規範,不要學習。

mvn命令是 clean package -Dmaven.test.skip=true -P test

上傳jar包

用的外掛是Publish over SSH,這裡的關鍵是連線上遠端伺服器。

怎麼用Jenkins配置分散式環境的安全釋出?

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,指令碼內容類似。

自我感覺這一套還可以,不知道各路大佬怎麼看,還請多多指教,畢竟第一次搞運維。。。我感覺在開發的路上越走越遠了。。。。

相關文章