微服务发布启动方式很多,大概有以下方式,使用脚本启动方便运维维护,更方便各种CI,CD等Devops操作,希望能帮助到目前正在开发微服务的同学们。
**
**
java -jar package(服务包名,如abc.jar),这种方式比较简单直接,如果需要参数需要携带参数启动如:
java -Xms500m -Xmx500m -server -XX:+HeapDumpOnOutOfMemoryError -jar $JAR_PATH/abc.jar --spring.profiles.active=test
以上方式在命令行执行容易写错,另外每次手动执行也不合适。
**
**
根据服务的参数配置以及使用的具体环境,正常每个项目都有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
**
编写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
**
**
chmod a+x bootstrap.sh
./bootstrap.sh start
**
**
./bootstrap.sh stop
./bootstrap.sh status(当前微服务状态检查)
以上脚本可以结合Jenkins做持续集成发布,也可以通过自己内部监控系统灵活执行脚本。