天天看点

【综合】微服务(java app)的服务器托管及自动部署

前言

到这一步需要的东西很多,可以参考一下之前的文章,

譬如:

研发模式及运维专栏

里面的maven,nexus,jenkins,zookeeper配置,nohup及centos下的服务,还有:

微服务专栏

下面的项目配置及pom文件处理。

前提

假定已经有一个微服务项目,已经可以用maven正常构建,此为前提。

ps:自动构建流程其实是有矛盾之处的,根据目前的模式,微服务必须先在systemd上面注册成为service,然而,如果不构建的话压根没办法注册和运行这个service,所以,这就是矛盾的地方了。

准备前

1、相关参数路径确定。

我们确认或规定,jenkins对模块的构建物为:

MicroBaseApp-Build.zip

绝对路径为:

/var/lib/jenkins/workspace/MicroBase/MicroBaseModule/MicroBaseApp/target/MicroBaseApp-Build.zip

远程传输的目标文件为:

/data/packages/product/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip

其中,目标文件的名字跟随构建版本走的。

可执行jar包在zip构建物里面的相对位置为:

./MicroBaseApp/MicroBaseApp.jar

用于自动解压缩及部署的脚本应该放在:

/root/deploy-micro-service.sh

内容为【注意,针对部署微服务的脚本内容是固定的—或者说,针对java的jar程序的自动部署脚本内容固定不变】

#!/bin/bash


echo "==========================="
echo "脚本说明:"
echo "当前脚本为自动化部署程序,用于微服务框架的配套打包的部署工具,可用于:"
echo "1、java程序(微服务模块)的部署,具体过程为,自动复制构建包到目标目录,假如当前java程序"
echo " 未在系统注册服务将替其注册服务利用centos的systemd托管java程序;自动关停及重启服务。"
echo "==========================="

echo "==========================="
echo "需求参数说明:"
echo "参数-f、构建文件路径,譬如:/data/package/MicroBase/test/MicroBase-build-0.0.16.zip"
echo "参数-t、解压的目标目录路径,譬如:/usr/micro-service/test/MicroBase"
echo '参数-s、部署时停止及部署成功后启用的系统服务名称(app模块部署时候要用app的系统服务名称,而javaweb部署时候要输入tomcat的服务名称,没有服务的请留空),譬如:"[email protected]",友情提醒,外面要用双引号'
echo "==========================="



echo "==========================="
echo "正在执行:$0"
echo "==========================="

echo "==========================="
echo "脚本执行情况:"
echo "用户输入参数个数:$#"
echo "输入参数列表:[email protected]"
echo "==========================="

###参数设定
#从外界传进来的参数获取工程产出物的具体路径
build_zip_file=""
target_path=""
service_name="";
jar_file_name=""

#获取参数:
while getopts :f:t:s:j: OPTION;do
    case $OPTION in
    f)

    build_zip_file=$OPTARG
    ;; 
    t)
    target_path=$OPTARG
    ;; 
    s)
    service_name=$OPTARG
    ;; 
    j)
    jar_file_name=$OPTARG
;;
    ?)
    ;; 
    esac
done

echo "build_zip_file is:$build_zip_file"
####判断产出物是否存在。
if [ -e $build_zip_file ]
then
echo "工程打包文件存在,继续执行"
else
echo "工程打包文件不存在,无法继续执行!"
exit 
fi

if [ -f $build_zip_file ]
then
echo ""
else
echo "您指定的产出物为目录,系统无法继续执行!"
exit 
fi
###检查输出目录是否存在,不存在则新建目录。

if [ !  $target_path ]
then
echo "输出目录为空,系统无法继续执行!"
exit 

fi

if [ ! -e $target_path ]
then
mkdir -p $target_path
echo "${target_path}不存在,新建成功"
else

    if [ -f $target_path ]
        then
            echo "$target_path 为文件,系统无法处理!"
            exit 
        fi          


fi

echo "$jar_file_name jarfilename"
##检查jar参数是否为空。
if [  $jar_file_name ]
then
echo "指定了jar文件"

else
echo ""

fi


ask4HandleService=
if [  -z  "$service_name" ] 
then
ask4HandleService=
echo "service name为空${service_name}"
else
ask4HandleService=
echo "指定了系统服务${service_name}"
fi



###深水区处理。
###1、判断是否有对应的service服务,有的话就先暂停。。。

has_this_service=

if [ $ask4HandleService -eq  ]
then
##好了,要处理系统服务,那么就要看看chkconfig里面有没有配置好系统服务了。

unit4search=`systemctl list-unit-files | grep $service_name`
echo $unit4search
if [ -z "$unit4search" ]
then
echo "$service_name服务不存在"
else
echo "$service_name服务存在"
has_this_service=
fi
fi


####人性化提示一下,没有配置好系统服务。
if [ $ask4HandleService -eq  -a $has_this_service -eq  ]
then
echo "===============抱歉,脚本无法在当前系统检测到${service_name}这个系统服务,请确认运维人员已经配置好当前模块的系统服务且测试通过且服务名称无误。"
echo "===============部署中断,请对模块的系统服务进行检查。"
exit 
fi



#######有系统服务的话,请先关停系统服务。

if [   $has_this_service -eq  ]

then
echo "....稍等,正在关停系统服务"
systemctl stop $service_name
else
echo "....当前部署行动无指定系统服务,忽略对系统服务的控制。"
fi


####部署开始。
###删除之前所有文件。
for FILE in  $(ls $target_path)
do
echo "删除:$FILE"
rm -rf "${target_path}/${FILE}"
done

###解压缩:
unzip $build_zip_file -d $target_path


#######有系统服务的话,部署完了就启动系统服务吧。

if [ $has_this_service -eq  ]
then
echo "....稍等,正在启动系统服务"
systemctl start $service_name
else
echo "....当前部署行动无指定系统服务,忽略文件部署完成后对系统服务的启动。"
fi

           

2、规定服务名称及路径内容。

本次demo规定服务名称为:

[email protected]

规定nohup的日志为:

/usr/local/logs/test-MicroBase.log

规定jar可执行包的路径为:

/usr/micro-service/apps/test/MicroBase/MicroBaseApp/MicroBaseApp.jar

其实这个是看情况的,需要根据解压缩后jar的实际路径来填。

服务内容模板为:

[Unit]
Description=base micro service

[Service]
Type=simple
PIDFile=/usr/local/pid-files/MicroBaseApp-dev.pid
#ExecStart=/usr/micro-service/apps/Service4MicroBase.sh -e dev -o start
ExecStart=/usr/bin/nohup /usr/bin/java -jar  /usr/micro-service/apps/dev/MicroBase/MicroBaseApp/MicroBaseApp.jar >/usr/local/logs/dev-MicroBase-2.log 2>&1 &

ExecStop=/usr/bin/kill  -9 $MAINPID
Restart=always
#取消启动频率限制吧。
StartLimitInterval=0
PrivateTmp=true
[Install]
WantedBy=multi-user.target
           

以下配置步骤是经过优化的,不是最优也是最简。请按步骤来配置。

配置步骤1、脚本部署

先ssh登录到你的目标机器,假设为appServer,然后,

vim /root/deploy-micro-service.sh
           

然后复制这段脚本区,保存。

#!/bin/bash


echo "==========================="
echo "脚本说明:"
echo "当前脚本为自动化部署程序,用于微服务框架的配套打包的部署工具,可用于:"
echo "1、java程序(微服务模块)的部署,具体过程为,自动复制构建包到目标目录,假如当前java程序"
echo " 未在系统注册服务将替其注册服务利用centos的systemd托管java程序;自动关停及重启服务。"
echo "==========================="

echo "==========================="
echo "需求参数说明:"
echo "参数-f、构建文件路径,譬如:/data/package/MicroBase/test/MicroBase-build-0.0.16.zip"
echo "参数-t、解压的目标目录路径,譬如:/usr/micro-service/test/MicroBase"
echo '参数-s、部署时停止及部署成功后启用的系统服务名称(app模块部署时候要用app的系统服务名称,而javaweb部署时候要输入tomcat的服务名称,没有服务的请留空),譬如:"[email protected]",友情提醒,外面要用双引号'
echo "==========================="



echo "==========================="
echo "正在执行:$0"
echo "==========================="

echo "==========================="
echo "脚本执行情况:"
echo "用户输入参数个数:$#"
echo "输入参数列表:[email protected]"
echo "==========================="

###参数设定
#从外界传进来的参数获取工程产出物的具体路径
build_zip_file=""
target_path=""
service_name="";
jar_file_name=""

#获取参数:
while getopts :f:t:s:j: OPTION;do
    case $OPTION in
    f)

    build_zip_file=$OPTARG
    ;; 
    t)
    target_path=$OPTARG
    ;; 
    s)
    service_name=$OPTARG
    ;; 
    j)
    jar_file_name=$OPTARG
;;
    ?)
    ;; 
    esac
done

echo "build_zip_file is:$build_zip_file"
####判断产出物是否存在。
if [ -e $build_zip_file ]
then
echo "工程打包文件存在,继续执行"
else
echo "工程打包文件不存在,无法继续执行!"
exit 
fi

if [ -f $build_zip_file ]
then
echo ""
else
echo "您指定的产出物为目录,系统无法继续执行!"
exit 
fi
###检查输出目录是否存在,不存在则新建目录。

if [ !  $target_path ]
then
echo "输出目录为空,系统无法继续执行!"
exit 

fi

if [ ! -e $target_path ]
then
mkdir -p $target_path
echo "${target_path}不存在,新建成功"
else

    if [ -f $target_path ]
        then
            echo "$target_path 为文件,系统无法处理!"
            exit 
        fi          


fi

echo "$jar_file_name jarfilename"
##检查jar参数是否为空。
if [  $jar_file_name ]
then
echo "指定了jar文件"

else
echo ""

fi


ask4HandleService=
if [  -z  "$service_name" ] 
then
ask4HandleService=
echo "service name为空${service_name}"
else
ask4HandleService=
echo "指定了系统服务${service_name}"
fi



###深水区处理。
###1、判断是否有对应的service服务,有的话就先暂停。。。

has_this_service=

if [ $ask4HandleService -eq  ]
then
##好了,要处理系统服务,那么就要看看chkconfig里面有没有配置好系统服务了。

unit4search=`systemctl list-unit-files | grep $service_name`
echo $unit4search
if [ -z "$unit4search" ]
then
echo "$service_name服务不存在"
else
echo "$service_name服务存在"
has_this_service=
fi
fi


####人性化提示一下,没有配置好系统服务。
if [ $ask4HandleService -eq  -a $has_this_service -eq  ]
then
echo "===============抱歉,脚本无法在当前系统检测到${service_name}这个系统服务,请确认运维人员已经配置好当前模块的系统服务且测试通过且服务名称无误。"
echo "===============部署中断,请对模块的系统服务进行检查。"
exit 
fi



#######有系统服务的话,请先关停系统服务。

if [   $has_this_service -eq  ]

then
echo "....稍等,正在关停系统服务"
systemctl stop $service_name
else
echo "....当前部署行动无指定系统服务,忽略对系统服务的控制。"
fi


####部署开始。
###删除之前所有文件。
for FILE in  $(ls $target_path)
do
echo "删除:$FILE"
rm -rf "${target_path}/${FILE}"
done

###解压缩:
unzip $build_zip_file -d $target_path


#######有系统服务的话,部署完了就启动系统服务吧。

if [ $has_this_service -eq  ]
then
echo "....稍等,正在启动系统服务"
systemctl start $service_name
else
echo "....当前部署行动无指定系统服务,忽略文件部署完成后对系统服务的启动。"
fi
           

关键的第一步完成。

配置步骤2、jenkins配置及构建项目

在jenkins上面添加一个pipeline任务,自行写构建的流程,注意,pom 文件很重要,具体不细说,参考之前的文章,现在给个pipeline的参考脚本:

ps:我一般一个项目有三个环境,分别是开发,测试和产品,三种配置文件及对应不同的机器,目前就配了test测试环境,其余的先作限制,目前只是demo,dev及product环境还没配置好。

几个参数文件路径说明:

###这是jenkins构建出来的文件包,如果你不知道具体在哪里,可以先将远程复制文件,调用deploy脚本这些都注释掉,先运行第一次构建,然后成功后你会发现构建物路径的。
 /var/lib/jenkins/workspace/MicroBase/MicroBaseModule/MicroBaseApp/target/MicroBaseApp-Build.zip
 ###这是要将构建物复制到目标机器的目录,通常分为test、product及dev三个目录,注意,目标机器你也可以每个环境配一个机器,共三个ip的。当然,本demo就只配置test环境,也没那么多讲究。
 /data/packages/test/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip
 ###这是deploy文件需要将构建物加压缩的目标目录。
 /usr/micro-service/apps/test/MicroBase
 你的目标机器ip地址
 test@MicroBase
           

首先,要先创建目录:

mkdir -p /usr/micro-service/apps/test/MicroBase
           

防止出错。

#!/usr/bin/env groovy
pipeline{
    agent any
  environment {
    REVISION = "0.0.${env.BUILD_ID}"
  }
    options{
        disableConcurrentBuilds()
        skipDefaultCheckout()
        timeout(time: , unit: 'HOURS')
        timestamps()
    }
    parameters{
        choice(name: 'build_env', choices: 'dev\ntest\nproduct\n', description: '请选择构建的环境')
    }
    stages{
        stage ('Initialize') {

          steps {
        script {
          currentBuild.displayName = "${REVISION}"
        }
              sh '''
              echo "任务初始化..."
              echo "构建版本revision:${REVISION}"
              '''
              sh '''
              echo "项目检出...."
              '''
checkout([$class: 'SubversionSCM',
          additionalCredentials: [],
          excludedCommitMessages: '',
          excludedRegions: '',
          excludedRevprop: '',
          excludedUsers: '',
          filterChangelog: false,
          ignoreDirPropChanges: false,
          includedRegions: '',
          locations: [[credentialsId: 'e522721e-4a9a-467c-b154-acb803d8afb0',
                       depthOption: 'infinity',
                       ignoreExternalsOption: true,
                       remote: 'svn://127.0.0.1:3690/MicroBaseModule']],
          workspaceUpdater: [$class: 'UpdateUpdater']])


          }
        }

    stage ('Build') {

      steps {
        echo "您选择了:${params.build_env}"
        echo '构建阶段....'
        echo '构建部署 MicroBaseApi子项目...'
        sh "mvn clean deploy -e -f MicroBaseModule/MicroBaseApi/pom.xml -P ${params.build_env}"
        echo '构建打包MicroBaseApp子项目...'
        sh "mvn clean package -e -f MicroBaseModule/MicroBaseApp/pom.xml -P ${params.build_env}"
      }
    }
    stage ('Deploy') {
      steps {
      echo '发布阶段....'

       script
            {
              if (params.build_env == 'test') {
                  echo '=====》》》测试环境进行远程发布。'
                  sh '''
                  sudo su -s /bin/bash jenkins
                  scp /var/lib/jenkins/workspace/MicroBase/MicroBaseModule/MicroBaseApp/target/MicroBaseApp-Build.zip [email protected]目标机器ip地址:/data/packages/test/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip
                  '''
                  echo "远程发布包含文件的复制及解压缩,假设您尚未配置好服务器上面的目录环境以及系统服务,请手动ssh登录进行配置。"
                  echo "1、需要手动配置服务器的各个模块的系统服务及环境,请以下命令: /root/deploy-micro-service.sh -f /data/packages/test/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip -t /usr/micro-service/apps/test/MicroBase"
                  echo '2、已经配置好环境了,请使用: /root/deploy-micro-service.sh -f /data/packages/test/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip -t /usr/micro-service/apps/test/MicroBase -s "[email protected]"'
                    sh '''
                    ssh -t  -p 22 [email protected]目标机器ip地址 "/root/deploy-micro-service.sh -f /data/packages/test/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip -t /usr/micro-service/apps/test/MicroBase -s \"[email protected]\""                    
                    '''


              }
              if(params.build_env=='product'){
                    echo '=====》》》生产环境进行远程发布。'
                    if(==){
                     echo "抱歉,生产环境尚未搭建完毕,不支持自动构建,测试环境可以一试。"   
                    }
                    else{

                sh '''
                sudo su -s /bin/bash jenkins
                  scp /var/lib/jenkins/workspace/MicroBase/MicroBaseModule/MicroBaseApp/target/MicroBaseApp-Build.zip [email protected]目标机器ip地址:/data/packages/product/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip
                  '''                        
                    }

              }
              else {
                  echo '=====》》》 默认(开发)环境进行远程发布。'
                 if(==){
                     echo "抱歉,dev环境不应在部署到线上,不支持自动构建,测试环境可以一试。"   
                    }
                    else{
                sh '''
                sudo su -s /bin/bash jenkins
                  scp /var/lib/jenkins/workspace/MicroBase/MicroBaseModule/MicroBaseApp/target/MicroBaseApp-Build.zip [email protected]目标机器ip地址:/data/packages/dev/MicroBaseApp/MicroBaseApp-Build-${REVISION}.zip
                  '''      

                    }


              }

              }
      }
    }

    }

post {
        always {
            echo '构建结束...'
        }
        success {
            echo '恭喜您,构建成功!!!'
        }
        failure {
            echo '抱歉,构建失败!!!'
        }
        unstable {
            echo '该任务已经被标记为不稳定任务....'
        }
        changed {
            echo ''
        }
    }

}
           

然后构建一下任务,你会看到:

【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署

第一,已经打包成功了,打包物的路径也知道了。

第二,远程复制scp也成功了。

第三,自动部署失败了,deploy脚本提示找不到[email protected]这个服务,

好了,接下来就是要创建systemd的服务了。

配置步骤3、建立服务

a、手动解压缩

#清空目录
rm -rf /usr/micro-service/apps/test/MicroBase
#创建目录
mkdir -p /usr/micro-service/apps/test/MicroBase
#解压缩
/root/deploy-micro-service.sh -f /data/packages/test/MicroBaseApp/MicroBaseApp-Build-.zip -t /usr/micro-service/apps/test/MicroBase
           
【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署

好了,解压缩完成。

b、配置服务。

vim /usr/lib/systemd/system/[email protected]

           

黏贴以下内容:

[Unit]
Description=base micro service

[Service]
Type=simple
#pid文件请根据情况进行名字命名,记得要创建这个文件啊。
PIDFile=/usr/local/pid-files/MicroBaseApp-test.pid 
#jar路径要根据上个步骤解压出来的jar确定,log日志文件要根据实际进行命名,记得要创建log文件啊。
ExecStart=/usr/bin/nohup /usr/bin/java -jar  /usr/micro-service/apps/test/MicroBase/MicroBaseApp/MicroBaseApp.jar >/usr/local/logs/test-MicroBase.log 2>&1 &

ExecStop=/usr/bin/kill  -9 $MAINPID
Restart=always
#取消启动频率限制吧。
StartLimitInterval=0
PrivateTmp=true
[Install]
WantedBy=multi-user.target
           

建立pid文件:

mkdir -p /usr/local/pid-files
vim /usr/local/pid-files/MicroBaseApp-test.pid
然后保存
           

建立日志文件:

mkdir -p /usr/local/logs/
vim /usr/local/logs/test-MicroBase.log 
然后保存。
           

接下来,权限:

chmod  /usr/lib/systemd/system/[email protected]
           

好了,然后看看能不能正常执行:

注意,java入口类的代码如下:

package net.w2p.MicroBase;


import com.alibaba.fastjson.JSONObject;
import net.w2p.MicroBase.searcher.account.MemberCondition;
import net.w2p.MicroBase.service.account.MemberRoleService;
import net.w2p.MicroBase.service.account.MemberService;
import net.w2p.MicroBase.vo.account.Member;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;

public class Provider {

    public static void main(String[] args) throws IOException {

        System.out.println("============================请稍候,程序开始启动,连接各个服务器可能会有1分钟左右的耗时......");
        System.out.flush();
        try{
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            context.start();

            MemberService tmpService=context.getBean(MemberService.class);
            ArrayList<Member> nowMembers=tmpService.simpleSearch(new MemberCondition());
            String str= JSONObject.toJSONString(nowMembers);
            System.out.println(str);

            System.out.println("服务已经启动...");

            //--这里要阻塞一下主线程啊。。话说不能用system.in.read这种方式,因为要在linux下面用nohup运行,想想都知道
            //--人家没有人机交互这种东西,也不可能接收用户的输入的。
            System.out.flush();
            Semaphore semaphore = new Semaphore();
            try {
                semaphore.acquire();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("假如你看到我就证明-----服务已经结束了。。");
        }
        catch (Exception ed){
            System.out.println(ed.toString());
            ed.printStackTrace();
        }
    }
}
           
systemctl daemon-reload
systemctl stop [email protected]
systemctl start [email protected]
systemctl status [email protected]
journalctl -xe -u [email protected]
           
【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署

第一、程序能够正常运行

第二、dubbo这种服务运行时候会有一定耗时。

然后再在jenkins上构建一下,可以看到:

【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署
【综合】微服务(java app)的服务器托管及自动部署

总结

单单一个自动部署也没什么,systemd+nohup+自动部署脚本,再加上jenkins自动构建,那就有点棘手了,pom要重写,pipeline任务脚本要定制+远程复制+部署脚本调用,再加上dubbo那就。。。

项目要分层,要做个nexus本地仓库,服务器要配置dubbo环境。

所以,这次难度比之前大一点。

继续阅读