1. 背景
由于實際項目需要,需要在 Linux 下發(fā)部署 Java Web 應(yīng)用摧阅。因為此前都是通過 Weblogic來部署的,乍換一種方式绷蹲,有點不使用棒卷。
主要遇到問題有三個:
- 啟動過程有點繁瑣,不夠簡單易用祝钢,對維護(hù)人員有一定要求比规,去理解每個參數(shù)的設(shè)置
- 而且啟動參數(shù),每次重啟都要輸入一堆參數(shù)拦英,不夠便捷
- 再者蜒什,重啟過程需要找到進(jìn)程 然后 kill 掉,再重啟疤估,耗時多
2. 解決思路
通過網(wǎng)上材料灾常,無非通過 K8S 去管理部署應(yīng)用 以及 原生 Java 方式管理,但是我們的 K8S 環(huán)境還沒提供铃拇,只能暫時采用 Java 原生钞瀑。
Java 原生,參數(shù)太多慷荔,那考慮將這些參數(shù)封裝成為一個 shell 腳本雕什,以后服務(wù)的啟動、停显晶、重啟或者查看狀態(tài)贷岸,都是通過 一個 shell 腳本來完成。
Shell 腳本功能就是提供應(yīng)用的 啟動磷雇、停偿警、重啟或者查看狀態(tài)。那就是寫四個方法唯笙,分別讓用戶選擇户敬。
3. 實現(xiàn)舉措
四個核心方法,完成應(yīng)用的 啟動睁本、停尿庐、重啟或者查看狀態(tài)。
3.1. 核心方法
function start()
{
}
function stop()
{
}
function restart()
{
}
function status()
{
}
3.2. 啟動
啟動過程中指定 JVM
參數(shù)呢堰,這里提供參考 JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
設(shè)置 虛擬機(jī)內(nèi)容娜汁、和 內(nèi)容異常過程中Dump操作饰抒、以及設(shè)置 GC日志路徑第步。
3.3. 停止
應(yīng)用停止過程中需要判斷應(yīng)用當(dāng)前的狀態(tài)哎迄,通過
ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}'
檢查出來應(yīng)用的 PID 。通過
ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill
來停止應(yīng)用
3.4. 重啟
結(jié)合 啟動和停止搪泳,查詢應(yīng)用狀態(tài),服務(wù)存在的話,則 kill 應(yīng)用贺纲,然后再啟動應(yīng)用。
3.4.1. 查看狀態(tài)
應(yīng)用停止過程中需要判斷應(yīng)用當(dāng)前的狀態(tài)褪测,通過 ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}'
檢查出來應(yīng)用的 PID 猴誊。
3.5. 其他
3.5.1. 日志路徑
默認(rèn)在當(dāng)前應(yīng)用的目錄下構(gòu)建 logs
日志文件夾,并按照應(yīng)用名稱侮措,分目錄存儲懈叹。
如應(yīng)用 A
,則日志文件在 logs/A/
下
3.5.2. 格式化日志
利用 function log_*
方法分扎,定義日志的級別澄成。
LOG_LEVEL=1
function log_debug(){
content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 1 ] && echo -e "\033[32m" ${content} "\033[0m"
}
function log_info(){
content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 2 ] && echo -e "\033[32m" ${content} "\033[0m"
}
function log_warn(){
content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 3 ] && echo -e "\033[33m" ${content} "\033[0m"
}
function log_err(){
content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 4 ] && echo -e "\033[31m" ${content} "\033[0m"
}
function log_always(){
content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 5 ] && echo -e "\033[32m" ${content} "\033[0m"
}
4. 完整文件
#!/bin/bash
# 日志級別 debug-1, info-2, warn-3, error-4, always-5
LOG_LEVEL=1
# 調(diào)試日志
function log_debug(){
content="[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 1 ] && echo -e "\033[32m" ${content} "\033[0m"
}
# 信息日志
function log_info(){
content="[INFO] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 2 ] && echo -e "\033[32m" ${content} "\033[0m"
}
# 警告日志
function log_warn(){
content="[WARN] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 3 ] && echo -e "\033[33m" ${content} "\033[0m"
}
# 錯誤日志
function log_err(){
content="[ERROR] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 4 ] && echo -e "\033[31m" ${content} "\033[0m"
}
# 一直都會打印的日志
function log_always(){
content="[ALWAYS] $(date '+%Y-%m-%d %H:%M:%S') $@"
[ $LOG_LEVEL -le 5 ] && echo -e "\033[32m" ${content} "\033[0m"
}
SpringBoot=$1
if [ "$SpringBoot" = "" ];
then
log_err "Please enter the Jar application name"
lot=$(find ./ -maxdepth 1 -type f -and -name "*.jar")
# lot_pat=${lot#*/}
log_err "The Optional Jar applications are as follows: $lot"
exit 1
fi
ADATE=$(date +%Y%m%d%H%M%S)
# 啟動參數(shù)
START_OPTS=$3
# JVM參數(shù)
APP_HOME=$(pwd)
dirname $0|grep "^/" >/dev/null
# 獲取當(dāng)前執(zhí)行路徑
if [ $? -eq 0 ];then
APP_HOME=$(DIR_NAME $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
log_info "Current directory is $APP_HOME"
ENV_PORT=${START_OPTS#*=}
ENV_DIR="$APP_HOME/logs"
if [ "$ENV_PORT" = "" ]; then
log_info "Application Port is Null"
log_info "$ENV_DIR"
if [ ! -d "$ENV_DIR" ];then
mkdir -p $ENV_DIR
fi
else
log_info "Application Port is $ENV_PORT"
ENV_DIR="$ENV_DIR/$ENV_PORT"
log_info "$ENV_DIR"
if [ ! -d "$ENV_DIR" ];then
mkdir -p $ENV_DIR
fi
fi
log_warn " Construct log folder $ENV_DIR"
pid=0
Purpose=$2
# 當(dāng)沒有輸入具體,操作畏吓,默認(rèn)為 START 墨状,此時需要用戶二次確認(rèn),輸入 Y|y|YES|Yes 同意操作
# 或者 n|N|NO|no 菲饼,不同意重啟歉胶,直接退出
if [ "$Purpose" = "" ];
then
log_err "Operation Name Not Entered : The Default Action Is START !"
read -p "Are You Sure?[y/n]:" sure
case $sure in
y|Y|Yes|YES)
log_warn "You Enter $a"
log_warn "Prepare to restart the app: $SpringBoot"
Purpose="start"
;;
n|N|NO|no)
echo "you enter $a"
log_warn "Ready To Exit Startup: $SpringBoot"
exit 1
;;
*)
echo "error";;
esac
fi
log_debug "##############################"
log_debug "Java environment variable information"
LOG_PATH=$ENV_DIR/$SpringBoot-$ADATE.log
GC_LOG_PATH=$ENV_DIR/gc-$SpringBoot-$ADATE.log
VSpringBoot=${SpringBoot%%.*}
LOG_DEBUG_PATH=$ENV_DIR/$VSpringBoot/debug.log
log_debug "LOG_DEBUG_PATH is $LOG_DEBUG_PATH"
log_debug "$(java -version)"
log_debug "Startup log $LOG_PATH"
log_debug "Startup gc log $GC_LOG_PATH"
JVM_OPTS="-Dname=$SpringBoot -Duser.timezone=Asia/Shanghai -Xms1024M -Xmx1024M -XX:PermSize=256M -XX:MaxPermSize=768M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -Xloggc:$GC_LOG_PATH -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
log_debug "$JVM_OPTS $GC_LOG_PATH"
# 啟動項目,如果項目已經(jīng)啟動過巴粪,則先 kill 掉原先項目通今,再啟動
function start()
{
# 檢查項目的進(jìn)程是否存在
checkPid
#
if [ $pid -ne "0" ]; then
log_info "Application $SpringBoot Running... PID:$pid ,Please Stop It"
# echo -e "\033[31m Application $SpringBoot Running... PID:$pid ,Please Stop It \033[0m"
# Kill the current Process
killPid
log_info ".............."
startFun
else
log_info ".............."
startFun
log_info ".............."
fi
}
checkPid()
{
pid=$(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}')
# `ps -aux | grep $SpringBoot | grep 'java -jar'|grep -v grep | awk '{print $2}' | xargs kill`
}
killPid()
{
log_err "Application PID:$pid is being stopped, Please wait for a while, or fish"
# echo -e "\033[31m Application PID:$pid is being stopped, Please wait for a while, or fish \033[0m"
$(ps -ef |grep $SpringBoot |grep 'java -jar'|grep -v grep|awk '{print $2}' | xargs kill)
tail -n 10 $LOG_DEBUG_PATH
sleep 10s
}
startFun()
{
log_debug "Begin Start $SpringBoot ..."
# echo -e "\033[32m Begin Start $SpringBoot ... \033[0m"
$(java -jar $JVM_OPTS $SpringBoot $START_OPTS > $LOG_PATH 2>&1 &)
# nohup java -jar $JVM_OPTS $SpringBoot --spring.config.location=file:./application.yml $START_OPTS > $LOG_PATH 2>&1 &
log_debug "$SpringBoot SUCCESS..."
#echo -e "\033[32m $SpringBoot SUCCESS... \033[0m"
sleep 10s
tail -n 300 $LOG_PATH
}
function stop()
{
checkPid
log_info "Begin Stop Application $SpringBoot"
# echo "Begin Stop Application $SpringBoot"
if [ "$pid" -ne "0" ]; then
log_err "$SpringBoot stop..."
# echo "$SpringBoot stop..."
killPid
else
log_info "$SpringBoot not running!"
# echo "$SpringBoot not running!"
fi
}
function restart()
{
# stop
sleep 3s
start
}
function status()
{
checkPid
if [ "$pid" -ne "0" ]; then
log_info "$SpringBoot not running!"
#echo "$SpringBoot not running!"
else
log_info "$SpringBoot is running... PID:$pid"
# echo "$SpringBoot is running... PID:$pid"
fi
}
case $Purpose in
start) start;;
stop) stop;;
restart) restart;;
status) status;;
*) log_info "require start|stop|restart|status" ;;
esac
5. 使用
sh restart.sh $1 $2 $3
- $1 : SpringBoot 應(yīng)用名.jar 必選
- $2 :操作內(nèi)容,可空肛根,為空默認(rèn)為 restart
- $3 : 其他參數(shù)辫塌,可空
樣例如下:
sh restart.sh cia-codegen.jar