jenkins通过80端口部署java服务

起因

有一些运行在内网的服务器需要通过vpn去访问,无法外网直接通过ssh登录,无法使用scp命令,从而导致无法使用jenkins自动部署服务

后来想到内网的服务器也对外开放80端口提供web服务,就可以直接使用80端口部署服务

具体做法

一、直接在项目中创建controller


@RestController
public class DeployController extends BaseController {
    /**
     * 部署上传war包的默认路径
     */
    private String DEFAULT_DEPLOY_UPLOAD_PATH="";
    /**
     * 部署执行脚本的位置
     */
    private String DEFAULT_DEPLOY_SCRIPT_FILE="";
    /**
     * 密码是:KnLEkez50d84J7zPuBRyi4bg1oCWsDjP
     */
    private String PASSWORD="6c94c97418f8c64ca63ec8acb34dff49";

    /**
     * 上传文件
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = {"/deploy/upload"}, method = {RequestMethod.POST})
    public String deployUpload(MultipartHttpServletRequest request){
        log.info("开始上传war包");
        try {
            //检查密码
            checkPassword(request.getParameter("password"));
            //检查部署平台
            checkPlatform(request.getParameter("platform"));
            //获取内容
            MultipartFile multipartFile = request.getFile("file");
            //保存成文件
            if (multipartFile != null) {
                //输入流
                BufferedInputStream bufferedInputStream = new BufferedInputStream(multipartFile.getInputStream());
                //输出流
                FileOutputStream fileOutputStream = new FileOutputStream(DEFAULT_DEPLOY_UPLOAD_PATH +"/"+ multipartFile.getOriginalFilename());
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                FileUtil.createFile(bufferedInputStream,bufferedOutputStream);
                log.info("上传war包成功");
                return "上传成功!";
            } else {
                return "file参数不正确,获取不到数据!";
            }
        }catch (FileNotFoundException e){
            return "文件没有权限!"+e.getMessage();
        } catch (IOException e) {
            log.error("上传war包失败!",e);
            return "上传war包失败!"+e.getMessage();
        } catch (Exception e) {
            log.error("上传war包失败!",e);
            return "上传war包失败!"+e.getMessage();
        }
    }

    /**
     * 开始执行部署
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = {"/deploy/execute"}, method = {RequestMethod.GET})
    public String deployExecute(HttpServletRequest request){
        log.info("开始执行部署脚本");
        try {
            checkPassword(request.getParameter("password"));
            //检查部署平台
            checkPlatform(request.getParameter("platform"));
            String command = "java -classpath "+DEFAULT_DEPLOY_UPLOAD_PATH+" RuntimeExec sh " + DEFAULT_DEPLOY_SCRIPT_FILE;
            Runtime.getRuntime().exec(command);
            log.info("执行部署脚本成功.命令:"+command);
            return "执行部署脚本成功!";
        } catch (Exception e) {
            log.error("执行部署脚本失败!");
            return "执行部署脚本失败!"+e.getMessage();
        }
    }
    /**
     * 检查密码
     * @return
     */
    private void checkPassword(String password) {
        log.warn("密码:" + password);
        log.warn("密码md5值:" + MD5.md5(password));
        log.warn("正确密码md5值:" + PASSWORD);
        if (!PASSWORD.equalsIgnoreCase(MD5.md5(password))) {
            log.warn("密码错误");
            throw new RuntimeException("密码错误");
        }
    }
    /**
     * 检查平台通用方法
     * @return
     */
    private void checkPlatform(String platform) throws RuntimeException{
        //广东
        log.info("platform:"+platform);
        if("guangdong".equals(platform)){
            DEFAULT_DEPLOY_UPLOAD_PATH = "/mnt";
            DEFAULT_DEPLOY_SCRIPT_FILE = "/mnt/publish.sh " + platform;
        }else{
            throw new RuntimeException("platform参数错误!未知平台:"+platform);
        }
    }
}

对外暴露两个接口,一个是上传war包的接口,一个是开始执行部署的接口。(注意:做好安全验证) 

1、可以使用先登录,才可调用两个接口,否则被拦截。(或者是再增加一下角色校验,例如只有管理员账户才能调用接口)

2、或者为了方便,可以增加免拦截,增加一些密码校验等(上图采用这种)

 

二、创建一个java类供第一步调用

public class RuntimeExec{
        public static void main(String[] args) throws Exception{
                for (String arg : args) {
                        System.out.println("参数:"+arg);
                }
                Runtime.getRuntime().exec(args);
                Thread.sleep(3*60*1000);
        }
}

 

执行:javac RuntimeExec  编译一下生成class文件

问:为什么要创建一个java类供第一步调用,直接让项目执行部署任务不行吗?

不行,因为项目执行/mnt/publish.sh脚本,执行的过程中还是由项目驱动。现在脚本中要kill掉项目,那就等于把自己杀死了,部署也就停止了。

现在把驱动publish.sh脚本的任务转交给RuntimeExec,它是一个独立的线程运行,kill掉项目不会对它执行publish.sh脚本有影响。

三、配置部署脚本

#/bin/bash
set -e
tomcatName=""
tomcatPort=""
deploy_dir=""
datetime=$(date "+%y%m%d-%H:%M:%S")
# 处理部署目录、tomcat名称和端口
deploy_dir="jsw"
tomcatName=apache-tomcat-6.0.24-gd-jsw-7085-shengchan
tomcatPort=7085

#备份ROOT文件夹及properties配置文件
echo "备份ROOT文件夹及properties配置文件" >> /mnt/RuntimeExec.log
if [ -f "/mnt/$deploy_dir/$tomcatName/webapps/ROOT/WEB-INF/classes/application.properties" ]; then
        cp -rf /mnt/$deploy_dir/$tomcatName/webapps/ROOT/WEB-INF/classes/application.properties /mnt/$deploy_dir
fi
if [ -d "/mnt/$deploy_dir/$tomcatName/webapps/ROOT" ]; then
        tar -zcf /mnt/war_bak/ROOT_$1_$datetime.tar.gz -C /mnt/$deploy_dir/$tomcatName/webapps ROOT
fi
#结束tomcat进程
echo "结束tomcat进程" >> /mnt/RuntimeExec.log
pid=$(ps -ef|grep tomcat| grep $tomcatPort | grep -v grep|awk '{print $2}' | xargs);
if [ -n "$pid" ]; then
        echo "$pid not null" >> /mnt/RuntimeExec.log
       kill -9 $pid
fi

#复制部署文件
echo "删除旧war包,复制新war包" >> /mnt/RuntimeExec.log
rm -rf  /mnt/$deploy_dir/$tomcatName/webapps/ROOT
rm -f  /mnt/$deploy_dir/$tomcatName/webapps/ROOT.war
cp -rf /mnt/jsw_platform.war /mnt/$deploy_dir/$tomcatName/webapps/ROOT.war

#启动tomcat
echo "启动tomcat" >> /mnt/RuntimeExec.log
cd /mnt/$deploy_dir/$tomcatName/bin
./startup.sh

四、配置jenkins

export path=/mnt/jenkins/workspace/jsw_gd
#进入git目录
cd $path
# maven打包
  mvn -q clean

#1、替换配置文件
if [ -f "$path/src/main/resouces/application_product.properties" ]; then
  cp -rf $path/src/main/resouces/application_product.properties $path/src/main/resouces/application.properties
  cp -rf $path/src/main/resouces/kuaidipay_product.properties $path/src/main/resouces/kuaidipay.properties
  cp -rf $path/src/main/resouces/weixinpay_product.properties $path/src/main/resouces/weixinpay.properties
  echo "替换生产环境配置文件"
fi

#2、maven打包
  mvn -q package -Dmaven.test.skip=true
  
#3、上传war包
echo "生产环境"
#用curl命令模拟post请求上传war包
curl -L -F file=@/mnt/jenkins/workspace/jsw_gd/target/jsw_gd.war -F password=KnLEkez50d84J7zPuBRyi4bg1oCWsDjP -F platform=xxx http://baidu.com/deploy/upload
#睡眠10秒,为了刚上传的文件留出保存的时间
sleep 10s

#4、执行开始部署接口
curl https://baidu.com/deploy/execute\?password=KnLEkez50d84J7zPuBRyi4bg1oCWsDjP\&platform=xxx

echo $platformname"生产环境部署完成"

五、验证

部署成功!jenkins console日志

 

延伸

还有一种方法,就是新创建一个java web   deploy项目,专门用于部署工作。这样可以免于污染项目代码。

只需修改nginx配置,把某些特定的请求(例如上传war包和执行部署接口),转发到此deploy项目即可部署目标项目,就可以省去上面第二步操作。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值