标签 bash 下的文章

故事背景:

  • 暂未启用 CI/CD 机制;
  • JVM 以 Jar 包方式启动;
  • 存在开发、测试、生产三套环境。

解决的痛点:

  • 解放劳动力,使 Jar 包从开发、测试到生产环境的部署自动化;
  • 友好且优雅地管理 JVM;
  • 我要看到更详细的日志。嗯,配合 ELK 简直真香。

实现前提:

  • Jar 包中配置文件(数据池、配置项等)剥离,每套环境独立,Jar 包重复利用;
  • 各环境中已配置了 FTP 服务,且可访问到 Jar 包所在目录。

好,开始表演:

#!/bin/sh
# author: xuchao_dot_org

DATE_TIME=$(date "+%Y-%m-%d %H:%M:%S");

BASE_DIR=/data/java/jar/myproject
TMP_DIR=/data/java/tmp/myproject
PROJECT_NAME=myproject_name # 同样也是 Jar 包的文件名
CONFIG_FILE=/data/java/conf/myproject/application.yml
LOG_FILE=/data/java/logs/myproject/$(date +%Y_%m_%d_%H_%M_%S).log

DEV_IP=
DEV_PORT=
DEV_USERNAME=
DEV_PASSWD=
DEV_DIR=/jar/myproject
TEST_IP=
TEST_PORT=
TEST_USERNAME=
TEST_PASSWD=
TEST_DIR=/jar/myproject

export JAVA_HOME=/data/java/jdk/jdk1.8.0_191
export PATH=$JAVA_HOME/bin:$PATH
export JAVA=$JAVA_HOME/bin/java
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

function running() {
    count=`ps aux | grep java | grep ${PROJECT_NAME}.jar | grep -v grep | wc -l`
    procedure=`ps -ef | grep -w "${PROJECT_NAME}.jar" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
    if [ ${count} -eq 1 -o "${procedure}" != "" ]; then
        return 0
    else
        return 1
    fi
}

function start() {
    if running; then
        echo "${PROJECT_NAME} is running."
        echo "${DATE_TIME} failed to start, ${PROJECT_NAME} is running." 2>&1 >> $LOG_FILE
        exit 1
    fi
    echo "starting ${PROJECT_NAME}..."
    echo "${DATE_TIME} starting ${PROJECT_NAME}..." >> $LOG_FILE
    echo ${CLASSPATH} >> $LOG_FILE
    exec nohup $JAVA -server -Xms128m -Xmx256m -Xss256k -Dspring.config.location=${CONFIG_FILE} -Djava.io.tmpdir=${TMP_DIR} -jar ${BASE_DIR}/${PROJECT_NAME}\.jar >> $LOG_FILE 2>&1 & # 需要调整 JVM 启动参数的选手请看这里
    sleep 15
    if running; then
                echo "${PROJECT_NAME} is successfully started."
        echo "${DATE_TIME} ${PROJECT_NAME} is successfully started." 2>&1 >> ${LOG_FILE}
        else
                echo "${PROJECT_NAME} is failed to start."
        echo "${DATE_TIME} ${PROJECT_NAME} is failed to start." 2>&1 >> ${LOG_FILE}
    fi
}

function stop() {
    if ! running; then
        echo "${PROJECT_NAME} is not running." | tee ${LOG_FILE}
        echo "${DATE_TIME} failed to stop, ${PROJECT_NAME} is not running." 2>&1 >> ${LOG_FILE}
        exit 1
    fi
    echo "stopping ${PROJECT_NAME}..."
    echo "${DATE_TIME} stopping ${PROJECT_NAME}..." >> $LOG_FILE
    pid=`ps -ef | grep -w "${PROJECT_NAME}.jar" | grep -w "java" | grep -v "grep" | awk '{print $2}'`
    kill -15 ${pid}
    sleep 5
    if ! running; then
        echo "${PROJECT_NAME} is successfully stoped."
        echo "${DATE_TIME} ${PROJECT_NAME} is successfully stoped." 2>&1 >> ${LOG_FILE}
    else
        echo "${PROJECT_NAME} is failed to stop. trying again..."
        echo "${DATE_TIME} ${PROJECT_NAME} is failed to stop. trying again..." 2>&1 >> ${LOG_FILE}
        kill -15 ${pid}
        sleep 5
        if ! running; then
            echo "${PROJECT_NAME} is successfully stoped. [2nd attempt]"
            echo "${DATE_TIME} ${PROJECT_NAME} is successfully stoped. [2nd attempt]" 2>&1 >> ${LOG_FILE}
        else
            echo "${PROJECT_NAME} is failed to stop. [2nd attempt]"
            echo "${DATE_TIME} ${PROJECT_NAME} is failed to stop. [2nd attempt]" 2>&1 >> ${LOG_FILE}
        fi
    fi
}

function status() {
    if running; then
        echo "${PROJECT_NAME} is running."
    else
        echo "${PROJECT_NAME} is stopped."
    fi
}

function help() {
    echo "script for jvm managerment. author: xuchao_dot_org"
    echo "usage: $0 [start|stop|restart|status|get|help]"
    echo "    start:        start the ${PROJECT_NAME} server"
    echo "    stop:        stop the ${PROJECT_NAME} server"
    echo "    restart:    restart the ${PROJECT_NAME} server"
    echo "    status:        get ${PROJECT_NAME} current status, running or stopped"
    echo "    get:        [dev|test] [version] get file from dev or test"
    echo "    help:        show this message"
}

function get_dev() {
    [ -z $1 ] && echo "params error. please see [ $0 help ] for more information." && exit 1
    echo "geting file [${PROJECT_NAME}-$1.jar] from dev..."
    echo "${DATE_TIME} geting file [${PROJECT_NAME}-$1.jar] from dev..." 2>&1 >> ${LOG_FILE}
    ftp -inp 2>&1 >> ${LOG_FILE} <<EOF
open ${DEV_IP} ${DEV_PORT}
user ${DEV_USERNAME} ${DEV_PASSWD}
cd ${DEV_DIR}
lcd ${BASE_DIR}
get ${PROJECT_NAME}-$1.jar
close
bye
EOF
    if [ -f "${BASE_DIR}/${PROJECT_NAME}-$1.jar" ]; then
        echo "get file [${PROJECT_NAME}-$1.jar] from dev successfully."
        echo "${DATE_TIME} get file [${PROJECT_NAME}-$1.jar] from dev successfully." 2>&1 >> ${LOG_FILE}
        \cp -rf ${BASE_DIR}/${PROJECT_NAME}-$1.jar ${BASE_DIR}/${PROJECT_NAME}.jar
        echo "copy file [${PROJECT_NAME}-$1.jar] into [${PROJECT_NAME}.jar] successfully."
        echo "${DATE_TIME} copy file [${PROJECT_NAME}-$1.jar] into [${PROJECT_NAME}.jar] successfully." 2>&1 >> ${LOG_FILE}
    else
        echo "failed to get file [${PROJECT_NAME}-$1.jar] from dev."
        echo "${DATE_TIME} failed to get file [${PROJECT_NAME}-$1.jar] from dev." 2>&1 >> ${LOG_FILE}
    fi
}

function get_test() {
    [ -z $1 ] && echo "params error. please see [ $0 help ] for more information." && exit 1
    echo "geting file [${PROJECT_NAME}-$1.jar] from test..."
    echo "${DATE_TIME} geting file [${PROJECT_NAME}-$1.jar] from test..." 2>&1 >> ${LOG_FILE}
    ftp -inp 2>&1 >> ${LOG_FILE} <<EOF
open ${TEST_IP} ${TEST_PORT}
user ${TEST_USERNAME} ${TEST_PASSWD}
cd ${TEST_DIR}
lcd ${BASE_DIR}
get ${PROJECT_NAME}-$1.jar
close
bye
EOF
    if [ -f "${BASE_DIR}/${PROJECT_NAME}-$1.jar" ]; then
        echo "get file [${PROJECT_NAME}-$1.jar] from test successfully."
        echo "${DATE_TIME} get file [${PROJECT_NAME}-$1.jar] from test successfully." 2>&1 >> ${LOG_FILE}
        \cp -rf ${BASE_DIR}/${PROJECT_NAME}-$1.jar ${BASE_DIR}/${PROJECT_NAME}.jar
        echo "copy file [${PROJECT_NAME}-$1.jar] into [${PROJECT_NAME}.jar] successfully."
        echo "${DATE_TIME} copy file [${PROJECT_NAME}-$1.jar] into [${PROJECT_NAME}.jar] successfully." 2>&1 >> ${LOG_FILE}
    else
        echo "failed to get file [${PROJECT_NAME}-$1.jar] from test."
        echo "${DATE_TIME} failed to get file [${PROJECT_NAME}-$1.jar] from test." 2>&1 >> ${LOG_FILE}
    fi
}

function get_file() {
    [[ -z $1 || -z $2 ]] && echo "params error. please see [ $0 help ] for more information." && exit 1
    case "$1" in
        dev)
            get_dev $2
            ;;
        test)
            get_test $2
            ;;
        *)
            help
            exit 1
            ;;
    esac
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart)
        $0 stop
        sleep 5
        $0 start
        ;;
    status)
        status
        ;;
    help)
        help
        ;;
    get)
        get_file $2 $3
        ;;
    *)
        help
        exit 1
        ;;
esac

演出结束,下期再见。