美文网首页Jenkins & LinuxJenkins社区jenkins for App
Jenkins部署SpringBoot应用到远程服务器(含脚本)

Jenkins部署SpringBoot应用到远程服务器(含脚本)

作者: CptHiro | 来源:发表于2017-04-17 19:34 被阅读6076次

    使用SpringBoot+SpringCloud写了一套APP后台服务,也引入了当下比较流行的微服务的理念,模块也比较多。为了方便前期测试和后期线上部署更新,使用Jenkins作为持续集成工具。

    结构

    服务器结构

    服务器结构
    • 测试机器:若干台外网测试主机,这里假设其中某台的IP地址为114.114.111.111。
    • Jenkins服务器:搭建在内网的测试主机,Jenkins部署在这台机器上。
    • SVN代码库:公司内部的SVN代码托管服务器(少说都有7,8年了,稳定到出奇)

    测试环境目录结构

    测试环境目录结构
    • /chl: 项目总目录
    • /chl/exec:执行脚本目录
    • /chl/pid:记录各个程序运行时pid
    • /chl/work:项目应用程序存放目录

    代码结构

    这里以chl-tss(一个业务系统模块)模块为例

    思路

    • 使用maven构建项目
    • 构建后使用Publish Over SSH部署到远程服务器:
    • 关闭应用
    • 备份应用到lastDepoly目录
    • 上传新版本的Jar包(或者war包)
    • 启动应用
    • 其中,关闭、备份、删除和启动应用都是由脚本来完成,所以我写了一个部署脚本 chl-deploy.sh 放在 /chl/exec下(内容见 相关脚本 章节)。
    • Pushlish Over SSH的执行顺序是先上传文件再执行脚本,所以对于每个应用每个服务器我都设置了两个 Transfer Set :
    • 先执行清理脚本:关闭,备份和删除旧版应用jar包

    chl-deploy.sh chl-tss clean

    • 再执行启动脚本启动应用

    chl-deploy.sh chl-tss start

    安装Jenkins

    下载Jenkins

    可以在https://jenkins.io/download/下载Jenkins的最新版本。建议下载LTS(LongTermSuport)。我下载的是 jenkins.war

    选择下载war包

    部署到内网服务器

    1. 将下载的jenkins.war包上传到Jenkins服务器上,使用一下命令启动:

    nohup java -Xms256m -Xmx1024m -XX:MaxPermSize=512m -jar jenkins.war --ajp13Port=-1 --httpPort=7076 > jenkins.out 2>&1 &

    其中 --httpPort=7076指定jenkins启动监听的端口,这里更改为7076(默认是8080)。-Xms256m -Xmx1024m -XX:MaxPermSize=512m设置了JVM参数(需要因环境而异)。

    我安装到了/jenkins,目录结构为:

    | - /jenkins/
    |  + pid
    |  + conf
    |  + log
    |    jenkins.sh
    |    jenkins.war
    

    其中,conf为jenkins工作目录,pid目录记录jenkins运行pid。jenkins.sh是为了方便启动和停止jenkins服务器,内容见相关脚本章节。

    启动jenkins :

    ./jenkins.sh start

    关闭jenkins:

    ./jenkins.sh stop

    配置Jenkins

    1. 初始化
      1.1 启动Jenkins:
    cd /jenkins
    ./jenkins.sh start;tail -f log/jenkins.out
    

    1.2. 访问Jenkins:http://192.168.0.186:7076 (192.168.0.186是我部署jenkins的服务器)。页面出现:

    输入管理员初始化密码
    会提示 “Unlock Jenkins”,要求输入密码“Administrator password”,此时可以到控制台上找到这一段: 从控制台获取管理员密码

    图中划横线的部分就是管理员密码,辅助粘贴到输入框中即可。另外也可以从/jenkins/conf/secrets/initialAdminPassword文件中得到:

    cat /jenkins/conf/secrets/initialAdminPassword

    1.3. 选择插件,选择“Install suggest Plugins”

    选择默认插件

    然后等待吧,安静的等插件安装完成。
    此时需要一杯咖啡...

    或者去解决一波BUG...

    1.4 若干分钟之后,插件安装完成。之后设置管理员后就可以使用了。

    1. 增加 Publish Over SSH 插件
      系统设置->插件管理->可选插件 搜索 Publish Over SSH,选中点击立即安装即可安装。
    搜索安装Publish Over SSH
    1. 系统配置
      在新建任务之前,需要做一些配置。
      2.1 设置jenkins路径
    设置jenkins路径
    • Jenkins URL填写jenkins访问路径
    • 邮箱地址填写自己的邮箱地址

    2.2 邮件通知设置

    图片.png
    • 这是用QQ企业邮箱的配置

    2.3 设置SSH远程服务器

    SSH Servers
    • 这里点击“增加”即可新增多个远程服务器
    设置远程服务器SSH(1)
    • 点击“高级”即可设置Push Over SSH的端口和密码
    设置端口和密码
    • 勾选“Use password authentication, or use a different key”
    • Passphrase / Password 设置密码
    • Port 设置端口

    2.4 SVN版本指定
    如果使用SVN,则需要注意选择Subversion Workspace Version版本:

    Subversion Workspace Version
    • subversion 版本设置一定要正确

    2.6 保存后全局配置就已经设置完成了

    2.7 项目配置
    2.7.1 新建maven项目

    构建一个maven项目

    源码管理选择 Subversion

    使用SVN源码管理
    • Credentials:凭证,点击 Add 即可输入用户名和密码
    • Local module directory :默认即可(Jenkins工作空间下)。特别是在web

    构建环境中勾选 Send files or execute commands over SSH after the build runs,然后点击 Add Server,即可新增目标远程服务器:

    构建环境增加SSH远程部署(1)
    • Name:选择 2.3 步骤中新增的远程服务器
    • Source files:需要上传的文件,可以使用通配符和Jenkins变量。这一步留空。
    • Exec command:在远程服务器上执行的脚本,这里我的想法是,先清理一下远程服务器,关闭服务并备份程序。
    cd /chl/exec
    sh ./chl-deploy.sh chl-tss clean
    

    点击Add Transfer Set,新增一组设置:

    构建环境增加SSH远程部署(2)
    • Source files:需要上传的文件。target/chl-tss.jar。即maven打包生成后的jar包文件。路径相对于maven工程的根目录。
    • Exec command:在远程服务器上执行的脚本。这里需要先上传文件到服务器,再执行启动脚本
    cd /chl/exec
    sh ./chl-deploy.sh chl-tss start
    
    • 点开“高级”之后勾选上 Flatten files,扁平化文件。只上传文件,不上传文件所属文件夹。否则上传到远程文件夹之后就会多一级 target 目录。

    设置maven执行参数:

    maven执行参数
    • 这里的 -P dev 是我在maven项目中使用了profile来区分测试和生产配置。

    至此,Maven工程配置已基本完成。保存即可返回到工程点击立即构建即可开始构建。
    如果构建失败,可以点击 Build History => Console Output 查看构建日志。

    相关脚本

    1. jenkins.sh
    #!/bin/sh
    ## java env
    export JAVA_HOME=/usr/local/jdk1.8
    export JRE_HOME=$JAVA_HOME/jre
    export JENKINS_HOME=/jenkins/conf
    ## exec shell name
    EXEC_SHELL_NAME=jenkins\.sh
    ## service name
    SERVICE_NAME=jenkins
    SERVICE_DIR=/jenkins
    JAR_NAME=$SERVICE_NAME\.war
    PID=pid/$SERVICE_NAME\.pid
    cd $SERVICE_DIR
    case "$1" in
        start)
            nohup java -Xms256m -Xmx1024m -XX:MaxPermSize=512m  -jar $JAR_NAME --ajp13Port=-1 --httpPort=7076 > jenkins.out 2>&1 &
            echo $! > $SERVICE_DIR/$PID
            echo "#### start $SERVICE_NAME"
            ;;
    
        stop)
            kill `cat $SERVICE_DIR/$PID`
            rm -rf $SERVICE_DIR/$PID
            echo "#### stop $SERVICE_NAME"
            sleep 8
            TEMP_PID=`ps -ef | grep -w "$SERVICE_NAME" | grep  "java" | awk '{print $2}'`
            if [ "$TEMP_PID" == "" ]; then
                echo "#### $SERVICE_NAME process not exists or stop success"
            else
               echo "#### $SERVICE_NAME process pid is:$TEMP_PID"
               kill -9 $TEMP_PID
            fi
            ;;
    
        restart)
            $0 stop
            sleep 2
            $0 start
            echo "#### restart $SERVICE_NAME"
            ;;
    
    esac
    exit 0
    
    1. chl-deploy.sh
     #!/bin/sh
    ## java env
    export JAVA_HOME=/usr/local/jdk1.8
    export JRE_HOME=$JAVA_HOME/jre
    
    ## exec shell name
    EXEC_SHELL_NAME=$1\.sh
    ## service name
    SERVICE_NAME=$1
    SERVICE_DIR=/chl
    JAR_NAME=$SERVICE_NAME\.jar
    PID=pid/$SERVICE_NAME\.pid
    WORK_DIR=$SERVICE_DIR/work
    
    #function start
    start(){
        cd $WORK_DIR
       if [ ! -d "log" ]; then
            mkdir log
        fi
       nohup $JRE_HOME/bin/java -Xms256m -Xmx512m -jar $JAR_NAME >log/$SERVICE_NAME.out 2>&1 &
            echo $! > $SERVICE_DIR/$PID
            echo "#### start $SERVICE_NAME"
    }
    
    # function stop
    stop(){
        cd $WORK_DIR
       if [ -f "$SERVICE_DIR/$PID" ]; then
                    kill `cat $SERVICE_DIR/$PID`
                    rm -rf $SERVICE_DIR/$PID
            fi
            echo "#### stop $SERVICE_NAME"
            sleep 6
            TEMP_PID=`ps -ef | grep -w "$SERVICE_NAME" | grep "java" | awk '{print $2}'`
            if [ "$TEMP_PID" == "" ]; then
                echo "#### $SERVICE_NAME process not exists or stop success"
            else
                echo "#### $SERVICE_NAME process pid is:$TEMP_PID ."
                kill -9 $TEMP_PID
            fi
    }
    
    # function clean
    clean(){
        cd $WORK_DIR
            if [ ! -d "lastDeploy" ]; then
               mkdir lastDeploy
            else
               rm lastDeploy/$SERVICE_NAME*
            fi
            if [ -f "$JAR_NAME" ]; then
               mv $JAR_NAME lastDeploy
            fi 
    }
    
    case "$2" in
    
        start)
       start
            ;;
    
        stop)
       stop
            ;;
    
        restart)
            stop
            sleep 2
            start
            echo "#### restart $SERVICE_NAME"
            ;;
       
        clean)
       stop
        sleep 2
       clean
        echo "#### clean $SERVICE_NAME"
       ;;
    
        *)
           ## restart
           stop
           sleep 2
           start
           ;;
    
    esac
    exit 0
    

    踩坑记

    1. 报错:Exec exit status not zero. Status [-1]
    ERROR: Exception when publishing, exception message [Exec exit status not zero. Status [-1]]
    Finished: UNSTABLE
    

    这个错误是我费时解决最长的一个,现象很奇怪,手动执行脚本没问题,其他环境也没问题,单独使用Jenkins在本地构建也没问题,偏偏用Jenkins+Publish Over SSH部署远程就会出现问题。
    解决办法:检查了许久发现原因是因为之前的 chl-depoly.sh 关闭程序时使用了(35行),是这样写的:

    错误程序

    这会导致SSH当前的执行进程也被kill掉(因为只过滤grep),从而返回-1,而非正常结束的0。改成:

    改正后的脚本
    1. 上传到远程服务器后文件找不到,即使在transfer set中指定Remote directory 也没用。
      解决办法: 在系统设置->全局配置-> SSH Servers中设置 Remote Directory
    设置Remote Directory
    1. 上传到服务器上之后的目录是 target/chl-tss.jar而非期望的jar,多了一层target目录。
      解决办法:
    勾选“Flatten files”

    参考:

    1. Publish Over SSH插件
    2. Jenkins+Maven进行Java项目持续集成
    3. Jenkins官网

    相关文章

      网友评论

      • w_nanan:谢谢,找了很多的帖子也没找到解决,看你这篇文章灵光一现:pray:
      • _fishman:回滚怎么做呢
      • 260b7908254c:非常详尽 赞一个

      本文标题:Jenkins部署SpringBoot应用到远程服务器(含脚本)

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