Spring Boot 主机部署方案

作者: tianwen01 | 来源:发表于2018-05-28 11:40 被阅读138次

1.关于主机部署

1.1. 趋势

部署环境一直在演变,从物理机,虚拟机,到容器化平台,这个趋势是明显的,是不可否认的,这个我们不做过多讨论,
本文所提的方案是在需要主机(物理机、虚拟机)部署的前提下进行的。

1.2.优点

  • 简单,没有过多的依赖与封装,简单意味着可靠
  • 故障定位快,部署环境越复杂,因环境引起的故障定位越困难,当然此话有点绝对,但统计学上看,是这样的

1.3.缺点

  • 资源限制欠缺
    比如限制CPU占用,内存占用,虽然java有内存限制的方法,但此方法只适用java,其他开发语言的项目,可能也有,但限制方式不统一,同时很多语言没有限制的方法

  • 控制能力不足
    比如动态缩容,扩容,这些高级特性,需要自己写服务去实现,容器化平台很多是带这个功能

2. 部署设计

2.1.运维分工

  • 运维人员

    1. 数据库、缓存、存储、操作系统等基础中间件
    2. 系统监控
    3. 告警处理进度的跟踪及汇总
    4. 服务简单的起停操作,日志查看
  • 开发人员(自己负责的服务)

    1. 服务的上线
    2. 服务线上告警及故障的处理

2.2.用户隔离

  1. 不同项目有共用机器(这个不常见)
  2. 同一个项目,不同环境有共用机器(比如预发布环境与生产环境有部分主机重叠)
  3. 同一个项目,中间件和业务服务共用机器
#以开放平台项目为例(osp),应用运行在普通用户
useradd osp && echo Osp_2018 | passwd --stdin osp

2.3.目录设计

  1. 为了用户隔离,应用部署目录放在用户目录下
  2. 为了避免JRE的相互干扰,在~/apps/java目录存放自己的Server JRE(比如server-jre-8u172-linux-x64.tar.gz解压缩到java目录),并在app_env.conf明确指定JAVA_EXE,这样大家升级jdk相互不干扰
    /home/osp/apps
  • apps
    应用部署根目录
    • java
      JRE目录
    • {app_code}
      具体的应用目录
      • {server_port}
        应用端口号,以支持单机部署多个实例
        • app_env.conf
          应用启动脚本参数文件
        • run.sh
          应用启动脚本
        • logs
          应用日志目录,日志文件一定要限制大小,比如springboot 默认的一个文件10M,最多存7个文件
        • {app_code}-{app_version}.jar
          应用部署包
dir.png

2.4 应用启动脚本

脚本已经开源,欢迎大家完善这个脚本,开源项目地址:https://github.com/Hanson1330/spring-boot-run

2.4.1. app_env.conf

#java程序路径(必需)
JAVA_EXE=/home/msp/apps/java/jdk1.8.0_172/bin/java

#注册中心地址(如果未启用注册中心,可注释)
MSP_DISCOVERY_URI=http://ms:ms_1234@10.34.110.160:8761/eureka/

#配置文件选择
PROFILES_ACTIVE=default

#服务端口(必需)
SERVER_PORT=12330

#JVM配置(必需)
JAVA_OPTIONS=("-Xms256m -Xmx1024m" "-XX:PermSize128m" "-Djava.io.tmpdir=/var/tmp" "-Duser.timezone=Asia/Shanghai")

#Spring Boot属性配置(有特殊配置在双引号里添加)
SPRING_BOOT_OPTIONS=""

2.4.2 run.sh

#!/bin/bash
<<!
 **********************************************************
 * Author        : 马永龙
 * Email         : yonglong.ma@hpe.com
 * Last modified : 2015-05-16 14:00
 * Filename      : run.sh
 * Description   : 服务运行脚本,支持Mac,Linux
 * *******************************************************
!

#切换至根目录
cd "$(dirname "$0")" || exit 1

#根目录
WORKING_DIR="$(pwd)"

#应用启动配置
APP_ENV_CONF="${WORKING_DIR}"/app_env.conf

#日志目录
LOGS_DIR="${WORKING_DIR}"/logs

#进程ID
PID_FILE="${WORKING_DIR}"/app.pid

#应用名称
APP_NAME="$(ls *.jar 2>/dev/null | head -n 1)"
APP_NAME=${APP_NAME%.jar}

#操作
ACTION=$1

echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }

usage() {
    echo $'\n\n\n'
    echoRed "Usage: ${0} support command {start|stop|restart|status}"
    echo $'\n\n\n'
    exit 1
}

psCheck() {
    echo "-----------------All instances in this machine--------------------"
    echo "$(ps -ef | grep ${APP_NAME} | grep -E -v "grep|start|stop|status|restart")"
}

await() {
    end=$(date +%s)
    let "end+=10"
    while
        [[ $now -le $end ]]
    do
        now=$(date +%s)
        sleep 1
    done
}

#1.检查操作参数
[ $# -gt 0 ] || usage

#2.引入启动变量
if [ -r ${APP_ENV_CONF} ]; then
    . "${APP_ENV_CONF}"
else
    echoRed "Missing or unreadable ${APP_ENV_CONF}"
    echo $'\n\n\n'
    exit 1
fi

#根据PID检查是否在运行
isRunningPid() {
    ps -p "$1" &>/dev/null
}

#根据PID_FILE检查是否在运行
isRunning() {
    [[ -f "$PID_FILE" ]] || return 1
    local pid=$(cat "$PID_FILE")
    ps -p "$pid" &>/dev/null
    return
}

#基础配置
if [ "$MSP_DISCOVERY_URI" = "" ]; then
    BASE_OPTIONS=("--spring.profiles.active=$PROFILES_ACTIVE" "--server.port=$SERVER_PORT")
else
    BASE_OPTIONS=("--spring.profiles.active=$PROFILES_ACTIVE" "--server.port=$SERVER_PORT" "--eureka.client.serviceUrl.defaultZone=$MSP_DISCOVERY_URI")
fi

if [ "$SPRING_BOOT_OPTIONS" = "" ]; then
    RUN_EXE="$JAVA_EXE ${JAVA_OPTIONS[*]} -jar ${APP_NAME}.jar ${BASE_OPTIONS[*]}"
else
    RUN_EXE="$JAVA_EXE ${JAVA_OPTIONS[*]} -jar ${APP_NAME}.jar ${BASE_OPTIONS[*]} ${SPRING_BOOT_OPTIONS[*]}"
fi

start() {
    echo "--------------Starting $APP_NAME:"
    echo $'\n\n\n'

    #检查jdk
    if [ -z "$JAVA_EXE" ]; then
        echoRed "Result: Start failed,Cannot find a Java JDK. Please check JAVA_EXE in app_env.conf"
        echo $'\n\n\n'
        exit 1
    fi

    #检查已经运行
    if isRunning "$PID_FILE"; then
        echoYellow "Result: Running, no need to start"
        echo $'\n\n\n'
        exit 0
    fi

    echo "Boot Command: nohup $RUN_EXE"
    echo $'\n\n\n'

    nohup $RUN_EXE >/dev/null 2>&1 &

    disown $!
    echo $! >"$PID_FILE"

    #等5秒
    await

    TIMEOUT=100
    while (! isRunning "$APP_PID"); do
        if ((TIMEOUT-- == 0)); then
            echoRed "Result: Start timeout"
            echo $'\n\n\n'
            exit 1
        fi
        sleep 1
    done

    echoGreen "Result: Start success,Running (PID: $(<$PID_FILE))"
    echo $'\n\n\n'

    psCheck
}

stop() {
    echo "--------------Stopping $APP_NAME:"
    echo $'\n\n\n'
    if [ ! -f "$PID_FILE" ]; then
        echoYellow "Result: Not running"
        echo $'\n\n\n'
        psCheck
        return 0
    fi

    local pid=$(<${PID_FILE})

    if [ -z $pid ]; then
        #pid文件存在,但进程却不存在
        echoRed "Result: Not running (PID: $pid not found)"
        echo $'\n\n\n'
        psCheck
        rm -f "$PID_FILE"
        return 0
    fi

    kill "$pid" 2>/dev/null

    TIMEOUT=30
    while isRunning $PID_FILE; do
        if ((TIMEOUT-- == 0)); then
            kill -KILL "$PID" 2>/dev/null
        fi
        sleep 1
    done
    rm -f "$PID_FILE"
    echoGreen "Result: Stop success"
    echo $'\n\n\n'
}

status() {
    echo "--------------Status $APP_NAME:"
    echo $'\n\n\n'
    [[ -f "$PID_FILE" ]] || {
        echoYellow "Result: Not running"
        echo $'\n\n\n'
        psCheck
        return 1
    }
    local pid=$(<$PID_FILE)

    if isRunningPid $pid; then
        echoGreen "Result: Running (PID: $pid )"
        echo $'\n\n\n'
        psCheck
        return 0
    else
        echoRed "Result: Not running (PID: $pid not found)"
        echo $'\n\n\n'
        psCheck
        return 1
    fi
}

case "$ACTION" in
start)
    start
    ;;

stop)
    stop
    ;;

restart)
    stop
    start
    ;;

status)
    status
    ;;
*)
    usage
    ;;
esac

#成功退出
exit 0

2.4.3 日志配置文件(logback-spring.xml)示例

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <jmxConfigurator/>
    <appender name="ERROR_FILE"
              class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <File>${LOG_PATH}/error.log</File>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
            <fileNamePattern>${LOG_PATH}/error.log.%i</fileNamePattern>
        </rollingPolicy>
        <triggeringPolicy
                class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
            <MaxFileSize>10MB</MaxFileSize>
        </triggeringPolicy>
    </appender>

    <root level="INFO">
        <appender-ref ref="ERROR_FILE"/>
    </root>
</configuration>

相关文章

网友评论

    本文标题:Spring Boot 主机部署方案

    本文链接:https://www.haomeiwen.com/subject/mnswjftx.html