Spring Boot Setup Method Using Docker Hierarchical Packaging

  • 2021-11-02 03:43:53
  • OfStack

The Spring Boot project uses a layered package of docker containers, jar, and war.

Spring Boot now supports layered packaging technology. Let's also use 1 to speed up Docker packaging, and the construction speed will be very fast.

Hierarchical setting

First of all, pom should be set similarly:


<plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>${spring-boot.version}</version>
                    <configuration>
                        <!--  Enable hierarchical packaging support  -->
                        <layers>
                            <enabled>true</enabled>
                        </layers>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

Declared spring-boot-maven-plugin Plug-in, set layers configuration, and turn on hierarchical support.

After packing, we check the jar package or war package, and we will find that there is an extra layers. idx file, which contains a list of hierarchical files


- "dependencies":
  - "WEB-INF/lib-provided/"
  - "WEB-INF/lib/HikariCP-4.0.3.jar"
  - "WEB-INF/lib/aspectjweaver-1.9.5.jar"
  ...
  ...
- "spring-boot-loader":
  - "org/"
- "snapshot-dependencies":
  - "WEB-INF/lib/ms-fundmain-base-1.0-SNAPSHOT.jar"
  - "WEB-INF/lib/xpower-main-1.0.3-SNAPSHOT.jar"
  - "WEB-INF/lib/xpower-utils-1.0.3-SNAPSHOT.jar"
- "application":
  - "META-INF/"
  - "WEB-INF/classes/"
  - "WEB-INF/jetty-web.xml"
  - "WEB-INF/layers.idx"
  - "pages/"
  - "static/"

This file is the basis for the following hierarchical settings.

If it's jar, there's another one in it classpath.idx File, which lists all dependent jar packages.

When packaging, we can use docker build or use docker-maven-plugin Plug-in to implement.

Note: spring-boot-maven-plugin plug-in

docker itself package function, but download package speed is too slow, very touching, all here is not recommended.---The advantage is not to write Dockerfile, simple and convenient, the disadvantage is that you can not customize Docker file.
The configuration is similar to the following:


<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <image>
            <!-- Configure the image name -->
            <name>127.0.0.1:5000/springcnscud/${project.name}:${project.version}</name>
            <!-- After the image is packaged, it is automatically pushed to the image warehouse -->
            <publish>true</publish>
        </image>
        <docker>
            <!--Docker Remote management address -->
            <host>http://127.0.0.1:2375</host>
            <!--  Do not use TLS Visit -->
            <tlsVerify>false</tlsVerify>
            <!--  Docker Push Mirror Warehouse Configuration -->
            <publishRegistry>
                <!-- Push Mirror Warehouse User Name -->
                <username>cnscud</username>
                <!-- Push Mirror Warehouse Password -->
                <password>123456</password>
                <!-- Push Mirror Warehouse Address -->
                <url>http://127.0.0.1:5000</url>
            </publishRegistry>
        </docker>
    </configuration>
</plugin>

If you use docker-maven-plugin + Custom Dockerfile:

pom configuration:


    <plugin>
                    <groupId>io.fabric8</groupId>
                    <artifactId>docker-maven-plugin</artifactId>
                    <version>${docker.plugin.version}</version>
                    <configuration>
                        <!-- Docker Remote Api-->
                        <!--  This machine can be commented out ,  If there is no listening 2375 Port  -->
                        <dockerHost>${docker.host}</dockerHost>
                        <!-- Docker  Mirror image private service -->
                        <registry>${docker.registry}</registry>

                        <images>
                            <image>
                                <name>${docker.registry}/${docker.namespace}/${project.name}:${project.version}</name>
                                <build>
                                    <dockerFileDir>${project.basedir}</dockerFileDir>
                                </build>
                            </image>
                        </images>
                    </configuration>
                </plugin>

Let's look at the Dockerfile format in jar mode of Spring Boot:


#  Hierarchical construction ,  Accelerate incremental build 

FROM adoptopenjdk/openjdk8:centos-slim as builder

WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
RUN java -Djarmode=layertools -jar app.jar extract && rm app.jar

FROM adoptopenjdk/openjdk8:centos-slim

LABEL maintainer="cnscud@gmail.com"

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV JAVA_OPTS="-Xms128m -Xmx256m"

WORKDIR application

COPY --from=builder /application/dependencies/ ./
COPY --from=builder /application/snapshot-dependencies/ ./
COPY --from=builder /application/spring-boot-loader/ ./
COPY --from=builder /application/application/ ./

EXPOSE 9001

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

Please modify the jdk according to your own situation, and use JarLauncher in the case of jar.

If it is war, how to set it up?

First of all, if you want to run independently, you can use embedded tomcat or jetty, and do not set provider in pom


 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>

In this way, the embedded tomcat will be included when packaging.

Dockerfile settings are as follows:


#  Hierarchical construction ,  Accelerate incremental build 

FROM adoptopenjdk/openjdk8:centos-slim as builder

WORKDIR application
ARG JAR_FILE=target/*.war
COPY ${JAR_FILE} app.war
RUN java -Djarmode=layertools -jar app.war extract && rm app.war

FROM adoptopenjdk/openjdk8:centos-slim
LABEL maintainer="cnscud@gmail.com"

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV JAVA_OPTS="-Xms128m -Xmx256m"

WORKDIR application

COPY --from=builder /application/dependencies/ ./
COPY --from=builder /application/snapshot-dependencies/ ./
COPY --from=builder /application/spring-boot-loader/ ./
COPY --from=builder /application/application/ ./

EXPOSE 8000

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS org.springframework.boot.loader.WarLauncher"]

Note the filename and run using WarLauncher.

Using external tomcat

Without experimentation, building layers can be cumbersome... but in theory, it is possible to use the decompressed war package instead of letting tomcat decompress itself

I won't try it here. The main point is that the basic package is replaced by tomcat, the running ENTRYPOINT is replaced by tomcat, and the files are copied to the container in the middle.


FROM tomcat:9.0

# Will target Under xx.war Copy to /usr/local/tomcat/webapps/ Under 
ADD ./target/xx.war /usr/local/tomcat/webapps/

# Port 
EXPOSE 8080

# Set the startup command 
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]

Related articles: