Springboot project packaging + shell script deployment practice, too useful!

Time:2021-4-18

Read by little hub:

Very practical shell script, worth collecting and learning ha!


This article is to share with you spring boot packaging and shell script command deployment, focusing on sharing a shell program startup tool, hoping to facilitate the work;

  • Profiles specifies the configuration of different environments
  • Maven assembly plugin
  • Share Shenniu_ publish.sh Program startup tool
  • Using Shenniu on Linux_ publish.sh Start the program

Profiles specifies the configuration of different environments

Usually, a set of programs is divided into many deployment environments: development, testing, UAT, online, etc. if we want to distinguish the configuration files for these environments, we can do it in two ways:

  • Through application.yml Code assignment in profile.active=uat Method assignment
  • Through the profiles in MVN to distinguish the configuration folder corresponding to different environments, manually check in idea to generate packages of different environments (recommended)

Here we are going to talk about the second method. First, configure the following in MVN:

<profiles>
        <profile>
            <id>node</id>
            <properties>
                <! -- parameter value passed to script -- >
                <activeProfile>node</activeProfile>
                <package-name>${scripts_packageName}</package-name>
                <boot-main>${scripts_bootMain}</boot-main>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>node1</id>
            <properties>
                <activeProfile>node1</activeProfile>
                <package-name>${scripts_packageName}</package-name>
                <boot-main>${scripts_bootMain}</boot-main>
            </properties>
        </profile>
        <profile>
            <id>node2</id>
            <properties>
                <activeProfile>node2</activeProfile>
                <package-name>${scripts_packageName}</package-name>
                <boot-main>${scripts_bootMain}</boot-main>
            </properties>
        </profile>
    </profiles>

The rough solution of nodes is as follows

  • ID: used to specify the directory of different environment configuration files, as follows:

Springboot project packaging + shell script deployment practice, too useful!

  • Properties: the node in this node can be passed as a parameter to other configuration files. For example, the package name node value here can be set in another file assembly.xml Or in the shell script file through ${package name}, as follows:

Springboot project packaging + shell script deployment practice, too useful!

  • Activebydefault: Specifies the default environment configuration folder

Maven assembly plugin

For spring boot program packaging, it can be divided into jar and war, here is the jar package; there are scenarios in which the configuration files or third-party dependent packages do not want to be put into the project jar, and these files are compressed into a zip package, which is convenient to upload to Linux; at this time, it can be done through Maven assembly plugin and Maven jar plugin, and the MVN configuration is as follows:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <archive>
            <addMavenDescriptor>false</addMavenDescriptor>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>${scripts_bootMain}</mainClass>
            </manifest>
        </archive>
        <! -- pack exclusions -- >
        <excludes>
            <exclude>**/*.yml</exclude>
            <exclude>**/*.properties</exclude>
            <exclude>**/*.xml</exclude>
            <exclude>**/*.sh</exclude>
        </excludes>
    </configuration>
    <executions>
        <execution>
            <id>make-a-jar</id>
            <phase>compile</phase>
            <goals>
                <goal>jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.4</version>
    <!-- The configuration of the plugin -->
    <configuration>
        <!-- Specifies the configuration file of the assembly plugin -->
        <descriptors>
            <descriptor>${project.basedir}/src/main/assembly/assembly.xml</descriptor>
        </descriptors>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The following points should be noted:

  • Mainclass node: used to specify the entry class path to start the main function, as shown here:

com.sm.EurekaServerApplication

  • Exclude node: exclude some column suffix files such as configuration files in the main jar package, because we want to package these configuration files outside the main package
  • Descriptor node: used to specify the corresponding node of the assembly plug-in assembly.xml configuration file

With the above MVN configuration, we also need to assembly.xml Here we extract the configuration of the publisher combined with shell script

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd
http://maven.apache.org/ASSEMBLY/2.0.0 ">
    <id>${activeProfile}</id>
    <! -- packaged as a zip file for publishing -- >
    <formats>
        <format>zip</format>
    </formats>
    <! -- true: generate the first level directory in zip (it is masked here, and the profiles suffix is required for the script) -- >
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <! -- package in the Lib directory of the zip file -- >
            <useProjectArtifact>false</useProjectArtifact>
            <outputDirectory>${package-name}-${activeProfile}/lib</outputDirectory>
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>

    <fileSets>
        <! -- package the configuration file into the conf directory of the zip file -- >
        <fileSet>
            <directory>${project.basedir}/src/main/profiles/${activeProfile}</directory>
            <outputDirectory>${package-name}-${activeProfile}/conf</outputDirectory>
            <includes>
                <include>**/*</include>
                <!--<include>*.xml</include>-->
                <!--<include>*.properties</include>-->
                <!--<include>*.yml</include>-->
            </includes>
        </fileSet>

        <! -- package the startup script into a zip file -- >
        <fileSet>
            <directory>${project.basedir}/src/main/scripts</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>**/*</include>
            </includes>
            <! -- file permission is 777 -- >
            <fileMode>777</fileMode>
            <! -- directory permission is 777 -- >
            <directoryMode>777</directoryMode>
            <! -- the parameter variable in the script is the key value in POM -- >
            <filtered>true</filtered>
        </fileSet>

        <! -- the jar compiled by the project is packaged into a zip file -- >
        <fileSet>
            <directory>${project.build.directory}</directory>
            <outputDirectory>${package-name}-${activeProfile}/</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

Introduction to key nodes:

  • Formats node: what file formats are used to compress configuration files and jar packages, including zip, tar, etc
  • FileMode node: specify the script file in the scripts directory (here: Shenniu)_ publish.sh )On Linux, the file permission is 777
  • Filtered node: the parameter variable in the script is the value of properties in the profiles of POM (this configuration is to map the property value in MVN to SH file, such as ${package name})

After completing the above configuration, at this time, we can switch different environments to zip the package by checking on idea, as shown in the figure below:

Springboot project packaging + shell script deployment practice, too useful!

Share Shenniu_ publish.sh Program startup tool

After completing the above steps, we will share the shell script of the startup program, which has the following functions:

  • Unzip + start jar package
  • Start jar package
  • Stop the corresponding jar
  • Restart jar program

At present, the shell encapsulates two ways to start jar commands

  • java -cp
  • java -jar

As shown in the figure, the command format is as follows:

Springboot project packaging + shell script deployment practice, too useful!

Look at all the shell code:

#!/usr/bin/env bash
#Variable parameter variable
Languagetype = "javac" # support Java, javac, NETCORE release
#Parameter values are passed by POM file
Basezipname = ${package name} - ${activeprofile} "# package name publish- test.zip Publish for
Package name = ${package name} "ා command to start package name xx.jar XX of
Mainclass = ${boot main} when Java - CP starts, specify the main entry class; command: Java - CP conf; lib \ *. Jar; ${packagename}. Jar ${mainclass}

#Examples
#Basezipname = "publish test" # compressed package name publish- test.zip Publish for
#Packagename = "publish" ා command to start package name publish.jar XX of

#Fixed variable
basePath=$(cd `dirname $0`/; pwd)
Basezippath = ${basepath} / ${basezipname}. Zip "# compressed package path
Basedirpath = ${basepath} decompress the deployment disk path
PID = # process PID

#Decompression
function shenniu_unzip()
{
    Echo "decompression
    Echo "compressed package path: ${basezippath}"
    if [ ! `find ${baseZipPath}` ]
    then
        Echo "there is no compressed package: ${basezippath}"
    else
        Echo "decompression disk path: ${basedirpath} / ${basezipname}"
        Echo "start decompression..."

        #Decompression命令
        unzip -od ${baseDirPath}/${baseZipName} ${baseZipPath}

        #Set execution permission
        chmod +x ${baseDirPath}/${baseZipName}/${packageName}

        Echo "decompression completed. "  
    fi
}

#Detect PID
function getPid()
{
    Echo "detection status
    pid=`ps -ef | grep -n ${packageName} | grep -v grep | awk '{print $2}'`
    if [ ${pid} ] 
    then
        Echo "run PID: ${PID}"
    else
        Echo "not running"
    fi
}

#Start the program
function start()
{
    #Before starting, stop before
    stop
    if [ ${pid} ]
    then
        Echo "stop program failed, unable to start"
    else
        Echo "start program
        
        #Select language type
        Read - P "enter the program type (Java, javac, NETCORE) and press enter next (default: ${languagetype}):" read_ languageType
        if [ ${read_languageType} ]
        then
            languageType=${read_languageType}
        fi
        Echo "select program type: ${languagetype}"

        #Enter the running package directory
        cd ${baseDirPath}/${baseZipName}

        #Classification start
        if [ "${languageType}" == "javac" ] 
        then
            if [ ${mainclass} ] 
            then
                nohup java -cp conf:lib\*.jar:${packageName}.jar ${mainclass} >${baseDirPath}/${packageName}.out 2>&1 &
               #nohup java -cp conf:lib\*.jar:${packageName}.jar ${mainclass} >/dev/null 2>&1 &
            fi
        elif [ "${languageType}" == "java" ] 
        then
            nohup java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar >/dev/null 2>&1 &
            # java -jar ${baseDirPath}/${baseZipName}/${packageName}.jar
        elif [ "${languageType}" == "netcore" ] 
        then
            #nohup dotnet run ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
            nohup ${baseDirPath}/${baseZipName}/${packageName} >/dev/null 2>&1 &
        fi

        #Query whether there is a startup process
        getPid
        if [ ${pid} ]
        then
            Echo "started"
            #Nohup log
            tail -n 50 -f ${baseDirPath}/${packageName}.out
        else
            Echo "start failed"
        fi
    fi
}

#Stop the program
function stop()
{
    getPid
    if [ ${pid} ] 
    then
        Echo "stop program"
        kill -9 ${pid}
        
        getPid
        if [ ${pid} ] 
        then
            #stop
            Echo "stop failed"
        else
            Echo "stop successfully"
        fi
    fi
}

#Start with parameters, according to the parameters
if [ ${#} -ge 1 ] 
then
    case  in
        "start") 
            start
        ;;
        "restart") 
            start
        ;;
        "stop") 
            stop
        ;;
        "unzip") 
            #Perform decompression
            shenniu_unzip
            #Execution start
            start
        ;;
        *) 
            Echo " no operation"
        ;;
    esac
else
    echo "
    The command is as follows:
    Unzip: unzip and start
    Start: start
    Stop: stop the process
    Restart: restart

    Example commands are as follows:. / Shenniu_ publish start
    "
fi

As mentioned in the above section, the parameters package name, activeprofile and boot main in the shell are all provided by the properties of profiles in MVN. They are variable parameters. The script code itself does not need to be modified manually. It only needs to change the MVN parameters. In fact, when we generate a zip package, the parameters in the shell are replaced. You can see the shell in zip The contents of the document are as follows:

Springboot project packaging + shell script deployment practice, too useful!

Using Shenniu on Linux_ publish.sh Start the program

Upload the generated zip to Linux and unzip it by command

1 unzip -od eureka-server-0.0.1-node eureka-server-0.0.1-node.zip

In fact, the shell script contains the decompression command, but I put it in zip when packing, so I can only manually decompress it. Of course, it can be adjusted. At this time, I enter the compression directory as follows:

Springboot project packaging + shell script deployment practice, too useful!

Note: This is the first time_ publish.sh The script prompts an error message. Because I edited the script on windows, the spaces are different from those on Linux, so there will be problems in running. To solve this problem, you can use the VIM command to convert the file to Linux format in Linux, as follows:

vim shenniu_publish.sh
set ff=unix
:wq

After execution, run the script again. / Shenniu_ publish.sh In this case, the following prompt will appear:

Springboot project packaging + shell script deployment practice, too useful!

At the moment, our file is decompressed, so we just need the start command to start the program

Springboot project packaging + shell script deployment practice, too useful!

Come here, Shenniu_ publish.sh As long as the script does not prompt an error, the jar service can be started. Other restart and stop commands can be executed as well

Springboot project packaging + shell script deployment practice, too useful!

You can study the shell code. I hope the script can bring you efficiency and good learning ideas. Here is the GIT address of the test case. The script is in Eureka server project:https://github.com/shenniubuxing3/springcloud-Finchley.SR2

Recommended reading

Great! This Java website has all kinds of projects! https://markerhub.com

The up Master of the B station, Java is really good!

Great! The latest version of Java programming ideas can be seen online!

Recommended Today

Java work for two years, even mybatis plug-in mechanism are not understand, then you work dangerous!

Configuration and use of plug in Configure the plugin node in mybatis-config.xml configuration file, such as a custom log plug-in loginterceptor and an open source paging plug-in pageinterceptor <plugins> <plugin interceptor=”com.crx.plugindemo.LogInterceptor”></plugin> <plugin interceptor=”com.github.pagehelper.PageInterceptor”> <property name=”helperDialect” value=”oracle” /> </plugin> </plugins> How plug-ins work With the help of the responsibility chain mode, a series of filters are […]