怎麼用Jenkins配置分佈式環境的安全發佈?

我本是Java高級開發,去年換了家公司,當時沒有運維,讓我來搞搞着試試。結果在運維的道路上越走越遠。。。今後兼職了公司的運維,老闆可高興壞了。此次分享一篇當時寫發佈腳本的經歷,但願能你有所幫助。html

前言

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

大體流程

點擊查看Jenkins配置截圖java

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

gitclone代碼-->檢測代碼-->構建jar包-->上傳jar包-->網關下線-->運行jar包-->網關上線-->檢測服務git

流程細節和Jenkins配置

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

gitclone代碼

Jenkins的plugin中安裝Git相關插件用於clone代碼,下圖中${group}等爲parameterized的參數,權限沒有設置的那麼細(實際上是偷懶),因此沒有按項目配置不一樣的job。不建議學我。 shell

檢測代碼

一般能夠用sonar檢測,配置sonar代碼檢測規則,代碼質量不合格直接打回,避免無效發佈。tomcat

構建jar包

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

這裏多了Pre Steps,每次構建前刪除部分jar包。由於開發沒有規範使用SNAPSHOT,全部依賴都用RELEASE,致使每次改動底層jar包後都讓我手動去服務器刪除老jar包。因此我機智的在每次構建前把全部的老jar包都刪除了。這個操做也不規範,不要學習。springboot

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

上傳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,腳本內容相似。

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


歡迎關注微信公衆號,提供思想和技術類原創文章。微信搜索小兵張健或掃描如下二維碼。

相關文章
相關標籤/搜索