微服務發佈啓動方式很多,大概有以下方式,使用腳本啓動方便運維維護,更方便各種CI,CD等Devops操作,希望能幫助到目前正在開發微服務的同學們。
**
1,命令行方式啓動微服務
**
java -jar package(服務包名,如abc.jar),這種方式比較簡單直接,如果需要參數需要攜帶參數啓動如:
java -Xms500m -Xmx500m -server -XX:+HeapDumpOnOutOfMemoryError -jar $JAR_PATH/abc.jar --spring.profiles.active=test
以上方式在命令行執行容易寫錯,另外每次手動執行也不合適。
**
2,通過腳本方式啓動服務
**
根據服務的參數配置以及使用的具體環境,正常每個項目都有dev,test,prod三個環境,腳本執行需要幾個關鍵參數,
port:服務啓動的端口號,這個確保當前服務未必佔用;
mainclass:入口類,也就是我們main方法所在的class類;
classpath:服務資源路徑,包括配置文件,依賴的其他jar文件的lib庫
下邊是我針對微服務編寫一套基於bashshell腳本,目前已經在各個環境(dev,test,prod)運行,由於是微服務需要依賴不同環境的配置文件,yml配置文件命名規則如下,也是按照springboot環境要求,具體配置內容開發者都雷同,不在贅述。
application-dev.yml(開發環境配置)
application-test.yml(測試環境配置)
application-prod.yml(商用環境配置)
當然最基礎的配置文件必須得有,以SpringCloud Edgware.SR4版本爲例
bootstrap.yml(spring.cloud.config相關配置,eureka相關配置,系統啓動優先加載的參數必須配置在這裏)
spring:
cloud:
bus:
trace:
enabled: true
config:
name: ${spring.application.name} #application
profile: ${spring.profiles.active} #profile
label: ${branch}
fail-fast: true
override-system-properties: true
discovery:
enabled: true # [new]開啓config服務發現的支持
service-id: micro-config-server #[new] config-server-application-name
stream:
bindings:
springCloudBusInput:
destination: springCloudBus
kafka:
binder:
brokers: ${kafka-brokers}
zk-nodes: ${zk-nodes}
configuration:
auto:
offset: #可以設置原生kafka屬性,比如設置新的消費組從最新的offset開始消費
reset: latest
security:
user:
name: admin
password: admin123
eureka:
instance:
instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${server.port}
prefer-ip-address: true
lease-renewal-interval-in-seconds: 15
lease-expiration-duration-in-seconds: 45
client:
serviceUrl:
defaultZone: ${eureka-url}
registry-fetch-interval-seconds: 10 #eureka client刷新本地緩存時間 # [new]註冊中erueka-server
application.yml(各個環境的通用配置,spring.application.name,spring.profiles.active)
server:
port: 8202
context-path: /acbs
management:
port: 9202
security:
enabled: false
spring:
devtools:
livereload:
port: 35728
application:
name: micro-acbs
mainclass: com.zhht.BootstrapApplication
#profile config
profiles:
active: ${environment}
#acbs-service.properties
com:
zhht:
acbs:
charge.feeId.expire: 3600
charge.feeId.useCache: false
charge.feeId.cron: 0 0 0/1 * * ?
charge.noplate.fee: true
feign:
hystrix:
enabled: true
client:
config:
default:
loggerLevel: BASIC
hystrix:
threadpool:
default:
coreSize: 20
maximumSize: 500
allowMaximumSizeToDivergeFromCoreSize: true
command:
default:
execution:
timeout:
enabled: false
ribbon:
ReadTimeout: 8000
ConnectTimeout: 3000
MaxAutoRetries: 0 #對當前服務的重試次數
MaxAutoRetriesNextServer: 1 #切換相同Server的次數
retryableStatusCodes: 500
ServerListRefreshInterval: 10000 #eureka客戶端ribbon刷新時間,默認30s
#數據源配置
#https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter
#mybatis
mybatis:
#entity掃描的包名
type-aliases-package: com.zhht.busiconf
#Mapper.xml所在的位置
mapper-locations: classpath:/mapper/*Mapper.xml
#開啓MyBatis的二級緩存
configuration:
cache-enabled: false
#分頁插件
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: true
params: count=countSql
**
3,微服務啓動腳本
編寫bootstrap.sh微服務啓動腳本
**
#!/bin/bash
# This bootstap script support minimum of JDK 1.8 ,with inner webserver of Tomcat8.
# please regarding copyright ownership.
# author:ningquan
# writted:2018-06-26
# -----------------------------------------------------------------------------
# Start Script for the Springboot Server
# -----------------------------------------------------------------------------
#set -x
#set JAVA_OPTS
JAVA_OPTS="-server -Xms${ProgramMemory} -Xmx${ProgramMemory} -Xss512k -XX:MetaspaceSize=60m -XX:MaxMetaspaceSize=256m"
ONS_VAR="-Dons.client.logRoot=/data/ons -Dons.client.logLevel=INFO -Dons.client.logFileMaxIndex=10"
BOOT_LOGDIR='/data/logs'
source /etc/profile
#JAVACMD=$JAVA_HOME/bin/java,search jre.
echofont(){
echo -e "\033[37;"$1"m $2 \033[0m"
}
if [ -z $JAVACMD ] ; then
if [ -n $JAVA_HOME ] ; then
JAVACMD=$JAVA_HOME/bin/java
else
JAVACMD=`which java`
fi
fi
if [ -z $JAVACMD ] ;then
echo "please check JAVA_HOME,not found JAVA runtime environment......"
exit 1
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly."
echo " We cannot execute $JAVACMD"
exit 1
fi
echofont 32 "JAVACMD="$JAVACMD
#setting perform path
BASEDIR=`dirname $0`/..
BASEDIR=`(cd $BASEDIR; pwd)`
echofont 32 "BASEDIR="$BASEDIR
#grep -w 'port:' application.yml |sed s/[[:space:]]//g |cut -d: -f 2
APPLICATION_CONFIG_FILE="$BASEDIR/conf/application.yml"
if [ -f $APPLICATION_CONFIG_FILE ] ;then
if [ ! -r $APPLICATION_CONFIG_FILE ] ; then
echofont 31 "Error: current user can't read file application.yml,suggest use root user"
exit 1
fi
else
echofont 31 "Error: not found application.yml in your config path /conf"
exit 1
fi
SERVER_PORT=`grep -E '^[^#]*+port:' $APPLICATION_CONFIG_FILE |sed s/[[:space:]]//g |awk -F':' '/70|71|72|73|74|80|81|82|83|84/{print $2}'`
#echo "server.port="$SERVER_PORT
#profiles active
PROFILE_ACTIVE=`grep -E '^[^#max_]*+active:' $BASEDIR/conf/application.yml | sed s/[[:space:]]//g | awk -F':' '{print $2}'`
echofont 32 "spring.profiles.active="$PROFILE_ACTIVE
SERVER_PROFILE_ACTIVE_FILE=""
#if [ -n $PROFILE_ACTIVE ] ; then
# eval SERVER_PROFILE_ACTIVE_FILE='$BASEDIR/conf/application-"$PROFILE_ACTIVE".yml'
# echofont 32 "spring.profiles.active.file="$SERVER_PROFILE_ACTIVE_FILE
# if [ -f $SERVER_PROFILE_ACTIVE_FILE ] ;then
# if [ ! -r $SERVER_PROFILE_ACTIVE_FILE ] ; then
# echofont 31 "Error: current user can't read file:application-"$PROFILE_ACTIVE".yml,suggest use root user"
# exit 1
# fi
# fi
#else
# echofont 33 "Warning: not found profile active file:application-"$PROFILE_ACTIVE".yml"
#fi
#according to profile active of environment that get ralative config
if [ ! -z $SERVER_PROFILE_ACTIVE_FILE ] ;then
SERVER_PORT=`grep -E '^[^#]*+port:' $SERVER_PROFILE_ACTIVE_FILE |sed s/[[:space:]]//g |awk -F':' '/70|71|72|73|74|80|81|82|83|84/{print $2}'`
echofont 32 "final server.port="$SERVER_PORT
fi
#get spring boot application main class,through springboot param 'spring.application.mainclass' property obtain.
MAIN_CLASS=`grep -w 'mainclass:' $APPLICATION_CONFIG_FILE | sed s/[[:space:]]//g | awk -F':' '{print $2}'`
APPLICATION_NAME=`grep -w 'name:' $APPLICATION_CONFIG_FILE | sed s/[[:space:]]//g | awk -F':' '/micro|api/{print $2}'`
echofont 32 "application-name="$APPLICATION_NAME
if [ -z $MAIN_CLASS ] ;then
echofont 31 "Error: springboot application not set main class,please check config file of application.yml and set property: spring.application.mainclass"
exit 1
fi
echofont 32 "main-class:"$MAIN_CLASS
CLASSPATH="$BASEDIR"/conf:"$BASEDIR"/boot/*:"$BASEDIR"/lib/*:$CLASSPATH
#echo "CLASSPATH=$CLASSPATH"
#according to diffrent case run someone scripts
#CHECK APPLICATION PROCESS STATUS
APPLICATION_PID="" #`netstat -anp |grep $SERVER_PORT |grep LISTEN |awk '{print $7}' | awk -F'/' '{print $1}'`
check_exist(){
APPLICATION_PID=`netstat -anutp |grep $SERVER_PORT |grep LISTEN |awk '{print $7}' | awk -F'/' '{print $1}'`
if [ -z $APPLICATION_PID ] ; then
return 1
fi
return 0
}
status(){
echofont 32 "start check current server status:"
check_exist
if [ $? -eq 0 ] ; then
echofont 32 "application:"$APPLICATION_NAME" is running. The process pid:"$APPLICATION_PID
else
echofont 33 "application:"$APPLICATION_NAME" is not running"
fi
}
start(){
echofont 32 "=================start application server====================="
if [ ! -d "$BOOT_LOGDIR/$APPLICATION_NAME/" ] ; then
`mkdir -p "$BOOT_LOGDIR/$APPLICATION_NAME/"`
fi
check_exist
if [ $? -eq 0 ] ; then
echofont 31 "Error:application:"$APPLICATION_NAME" is already running. The process pid="$APPLICATION_PID
exit 1
fi
nohup $JAVACMD $JAVA_OPTS \
-classpath "$CLASSPATH" \
-Dbasedir="$BASEDIR" \
-Dfile.encoding="UTF-8" \
-Djava.awt.headless="true" \
-Dsun.net.client.defaultConnectTimeout="60000" \
-Dsun.net.client.defaultReadTimeout="60000" \
-Djmagick.systemclassloader="no" \
-Dnetworkaddress.cache.ttl="300" \
-Dsun.net.inetaddr.ttl=300 \
-XX:+UseG1GC \
-XX:+DisableExplicitGC \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:-OmitStackTraceInFastThrow \
-XX:HeapDumpPath="$BOOT_LOGDIR/" \
-XX:ErrorFile="$BOOT_LOGDIR/$APPLICATION_NAME/javadump_error_%p.log" \
$ONS_VAR \
$MAIN_CLASS \
"$@" >$BOOT_LOGDIR/$APPLICATION_NAME/catalina-out.log 2>&1 &
#APPLICATION_PID=$$
#echo "checking process......"
sleep 5
#status
runpid=`ps aux |grep java |grep $APPLICATION_NAME |awk '{print $2}'`
if [ ! -z $runpid ] ; then
echo $runpid > $BASEDIR/bin/server.pid
echofont 32 "===================server start success!======================"
echofont 32 "===========Ning Quan wish you have a good job!================"
else
echofont 31 "Error:server start fail,please cat /data/logs/cataout.log"
fi
}
restart(){
echofont 32 "==============restart application server================="
stop
start
}
stop(){
echofont 32 "===========stop application server start================="
check_exist
if [ $? -eq 0 ] ; then
`kill $APPLICATION_PID`
sleep 5
check_exist
if [ $? -eq 0 ] ; then
stop
fi
#exit 1
fi
echofont 32 "=========stop application server finish!================="
}
usage(){
echofont 33 "Usage: sh bootstrap.sh [start|stop|restart|status]"
echofont 33 "eg: ./bootstrap.sh start"
exit 1
}
#CHECK APPLICATION PROCESS STATUS
APPLICATION_PID="" #`netstat -anp |grep $SERVER_PORT |grep LISTEN |awk '{print $7}' | awk -F'/' '{print $1}'`
check_exist(){
APPLICATION_PID=`netstat -anutp |grep $SERVER_PORT |grep LISTEN |awk '{print $7}' | awk -F'/' '{print $1}'`
if [ -z $APPLICATION_PID ] ; then
return 1
fi
return 0
}
echofont(){
echo -e "\033[37;"$1"m $2 \033[0m"
}
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac
exit 0
**
4,啓動微服務
**
chmod a+x bootstrap.sh
./bootstrap.sh start
**
5,關閉微服務
**
./bootstrap.sh stop
./bootstrap.sh status(當前微服務狀態檢查)
以上腳本可以結合Jenkins做持續集成發佈,也可以通過自己內部監控系統靈活執行腳本。