Spring Boot 主机部署方案

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. boot.conf

#java程序路径(必需)
JAVA_EXE=~/apps/java/jdk1.8.0_181/bin/java

#注册中心地址(如果未启用注册中心,可注释)
#DISCOVERY_URI="http://user:password@127.0.0.1:8761/eureka/"

#配置文件选择
PROFILES_ACTIVE=dev

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

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

#命令行参数
CMD_LINE_ARGS=""

2.4.2 run.sh

#!/bin/bash
# -------------------------------------------------------------------------------
# version:     2.0
# Date:        2018-08-25 10:00
# Author:      Ma Yonglong
# Email:       yonglong.ma@hpe.com
# Description: Spring Boot应用运行脚本,支持Mac,Linux
# -------------------------------------------------------------------------------

#应用主目录
cd "$(dirname "$0")" || exit 1
APP_HOME=$(pwd)

LOG_DIR="${APP_HOME}/logs"

PID_FILE="${APP_HOME}/app.pid"

BOOT_CONF="${APP_HOME}/boot.conf"

#应用JAR
APP_JAR="$(find "${APP_HOME}" -name "*.jar" 2>/dev/null | head -n 1)"

#应用名称
APP_NAME=${APP_JAR##*/}
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|cleanup}"
    echo $'\n\n\n'
    exit 1
}

psCheck() {
    echo "--------------All instances on this machine--------------"
    echo "USER       PID   %CPU %MEM VSZ    RSS    TTY   STAT  START   TIME COMMAND" && echo ""
    ps aux | grep "$APP_NAME" | grep -E -v "grep"
}

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

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

#2.引入启动配置
if [ -r "$BOOT_CONF" ]; then
    . "$BOOT_CONF"
else
    echoRed "Missing or unreadable $BOOT_CONF"
    echo $'\n\n\n'
    exit 1
fi

#基础配置
BASE_ARGS="--spring.profiles.active=$PROFILES_ACTIVE --server.port=$SERVER_PORT"

if [ ! "$DISCOVERY_URI" = "" ]; then
    BASE_ARGS="$BASE_ARGS --eureka.client.serviceUrl.defaultZone=$DISCOVERY_URI"
fi

RUN_EXE="$JAVA_EXE $JVM_ARGS -jar $APP_JAR $BASE_ARGS $CMD_LINE_ARGS"

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 boot.conf"
        echo $'\n\n\n'
        exit 1
    fi

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

    #打印启动命令
    echo "-------Boot Command: "
    echo "nohup $RUN_EXE >/dev/null 2>${LOG_DIR}/error.log &"
    echo $'\n\n\n'

    #创建错误日志文件
    mkdir -p "$LOG_DIR" && touch "${LOG_DIR}/error.log"

    #启动
    nohup $RUN_EXE >/dev/null 2>>"${LOG_DIR}/error.log" &

    #记录pid到pid文件
    echo $! >"$PID_FILE"

    #命令执行异常,快速失败
    sleep 0.5
    if (! isRunning); then
        echoRed "Result: Start failed" && rm -f "$PID_FILE"
        echo $'\n\n\n'
        exit 1
    fi

    #启动几秒钟中后失败的情况,6秒内失败
    sleep 6
    if (! isRunning); then
        echoRed "Result: Start failed" && rm -f "$PID_FILE"
        echo $'\n\n\n'
        exit 1
    fi

    #启动几秒钟中后失败的情况,10秒内失败
    sleep 4
    if (! isRunning); then
        echoRed "Result: Start failed" && rm -f "$PID_FILE"
        echo $'\n\n\n'
        exit 1
    fi

    #启动几秒钟中后失败的情况,启动在10秒外失败的比例比较低,而且也不可能一直等,这种情况交给监控告警来解决

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

    #检查本机存在的实例
    psCheck
}

stop() {
    echo "--------------Stopping $APP_NAME:"
    echo $'\n\n\n'

    if (! isRunning); then
        echoYellow "Result: Not running" && rm -f "$PID_FILE"
        echo $'\n\n\n'
        return 0
    fi

    kill "$(<"$PID_FILE")" 2>/dev/null

    #30秒后强制退出
    TIMEOUT=30
    while isRunning; do
        if ((TIMEOUT-- == 0)); then
            kill -KILL "$(<"$PID_FILE")" 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'

    if isRunning; then
        echoGreen "Result: Running (PID: $(<"$PID_FILE"))"
    else
        echoYellow "Result: Not running"
    fi

    echo $'\n\n\n'
    psCheck
}

cleanup() {
    echo "--------------Cleanup $APP_NAME:"
    echo $'\n\n\n'
    if ! isRunning; then
        [[ -d "$LOG_DIR" ]] || {
            echoGreen "Result: Log does not exist, there is no need to clean up" && echo $'\n\n\n'
            return 0
        }
        rm -rf "$LOG_DIR"
        echoGreen "Result: Log cleared"
    else
        echoYellow "Result: Please stop the application first and then clean up the log"
    fi
    echo $'\n\n\n'
}

case "$ACTION" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    stop
    start
    ;;
status)
    status
    ;;
cleanup)
    cleanup
    ;;
*)
    usage
    ;;
esac

#成功退出
exit 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容