Compile, package and deploy spring boot projects in Dockerfile

1、Dockerfile

1.1. What is Dockerfile

        Dockerfile is a configuration file that automatically builds a docker image. The image building process is defined in the Dockerfile through instructions. With the docker build command line, automated Docker image building can be achieved.

1.2. Dockerfile syntax analysis

        When we learn a language or document grammar, the fastest way to learn is to see how others write it. Who this "other" is here is very important. The more you play chess with the stinky chess basket, the more stinky you get.

        Therefore, to learn Dockerfile syntax, we need to find a model: you can go to Dockerhub to look at the images officially provided by open source software, and you can find the corresponding Dockerfile and see how others write it. Let’s take the Dockerfile of the nginx:1.20.2 version docker image mentioned above (officially provided) and analyze its syntax and construction process line by line. The scripts involved in this article can be obtained from the official channel of github:docker-nginx.

1.3. Dockerfile command

FROM

        Generally, when we build an image, we need a basic Linux operating system release image, and on this basis we build our own image.
        Therefore, the function of the FROM instruction is to specify the base image. The base Linux image used by nginx here is debian:bullseye-slim. Among them, debian:bullseye is a version of Debian's Linux distribution operating system, and the version name is bullseye. Slim usually means that this image is the smallest installation version in the release version. Because the image we build will be propagated in the subsequent continuous integration process and the network between the warehouse and the docker server, so the image construction should be as easy as possible. The result size is minimized. "When choosing a base image, you should focus on the size. The smaller the image, the better if it meets the basic functions of Linux and the running of your program . "

FROM debian:bullseye-slim

LABEL

        LABEL is used to add some description and explanatory information to the current image , such as the maintainer and contact information of the current image. Use key-value pairs to customize, and you can define multiple in one line.

LABEL <key>=<value> <key>=<value> <key>=<value> ...

maintainer、description

        You can also define multiple lines, such as maintainer information and description image description information. If the description information cannot be written in one line, you can use "\" to break the line.

LABEL maintainer="NGINX Docker Maintainers "
LABEL description="This is a Docker image \
for nginx 1.20.2. "

        There is an instruction in the Dockerfile syntax called MAINTAINER, which is used to describe the maintainer information of the image. However, it is no longer recommended to use it. LABEL is used uniformly.

ENV

        The function of ENV is to set environment variables. After the environment variables are set, they can be used in shell scripts.

        The usage method is: ${NGINX_VERSION}. Students who have studied JAVA, think about how you set up and use your JAVA_HOME environment variable? ENV is the same thing. It's just that the syntax has changed when it is placed in docker. The syntax format is: ENV environment variable KEY environment variable Value.

ENV NGINX_VERSION 1.20.2
ENV NJS_VERSION 0.7.0
ENV PKG_RELEASE 1~bullseye

RUN

        The function of the RUN instruction is to execute the Linux shell script. As you can see from the figure below, the environment variables defined by ENV can be used in the shell script.
        For nginx images, the function of the RUN command is to execute a series of shell command lines (scripts) to complete the installation of nginx. Therefore, the key to mastering the RUN instruction is not the RUN instruction itself, the key lies in:

  • Do you know how to install nginx manually?
  • Do you know Linux shell script syntax?
  • Can you write the nginx installation process as a shell script?

        If the answers to the above three questions are yes, use the RUN command to execute the shell script to complete the software installation. This is also the core of the writing content of Dockerfile. The linux shell is not what this article will explain to you.


COPY

        The function of the COPY instruction is to copy the local file (the server where the image construction is performed) to the image file.

        The syntax is: COPY <local file path>:<image file path> . The image file path is also the path of the file system when the container is running.

COPY docker-entrypoint.sh /
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
COPY 30-tune-worker-processes.sh /docker-entrypoint.d

        If the local file path only has the file name, it means that the file and the Dockerfile are in the same directory (relative path syntax). That is: the following files are in the same directory, and these files can be seen in the nginx official Dockerfile connection I gave above.

        Note: If <local file path> is a directory, only the files inside the directory are copied to the image, not the directory.

WORKDIR

        In addition, you can use the WORKDIR directive to set the local working directory for any RUN, CMD, ENTRYPOINT, COPY, and ADD instructions that follow it in the Dockerfile.

        In this way, the relative path mentioned above is the relative path relative to the path specified by WORKDIR. "But generally, it is not recommended to use WORKDIR because it is difficult to ensure that the working path of the developer's working host executing the build and the working path of the Dockerfile writer are consistent."

WORKDIR  /root

EXPOSE

Docker containers expose specified network ports when running, which can be used for container port mapping. The default protocol is TCP. The format is as follows:

EXPOSE <端口号>
EXPOSE <端口号>/<协议>

        After the container port is exposed, a mapping relationship can be established with the host port, so that the services inside the container can be accessed by accessing the host port. For example, port 80 of the container is exposed on TCP and UDP at the same time.

EXPOSE 80/tcp
EXPOSE 80/udp

STOP SIGNAL

        This command is not commonly used by the author. I checked the issues of docker-nginx on github and the answer is that the purpose of adding the STOPSIGNAL signal is to avoid the zombie process caused by the nginx service not being correctly terminated after the docker container is stopped . The presence.

STOPSIGNAL SIGQUIT

CMD

        The CMD instruction is also used to execute Linux commands or scripts, which is consistent with the RUN instruction. The difference between the two is:

  1. The RUN command is executed when the image is built, that is, when docker builds .
  2. The CMD instruction is executed when the docker run instruction is executed, that is, when the container is created ;

        Precisely because the execution periods of instructions are different, the write operations executed by RUN naming are written to the mirror layer. The CMD instruction execution result includes a write operation and is written to the container layer. (You can refer to my previous article "Mirror Layering Principle" to learn and understand).
        So the CMD and ENTRYPOINT instructions are somewhat similar, they are both run when creating a container.

        What needs to be noted is: "Once the ENTRYPOINT instruction is included in the Dockerfile, the CMD instruction exists as a parameter of the script specified by ENTRYPOINT."

See the format syntax below.

CMD contains three formats:

  • The first is to pass parameters to the script specified by ENTRYPOINT. The exec "$@" in the last line of the ENTRYPOINT script above is executing the command and parameters passed by CMD. To complete the startup of nginx service. **This usage is commonly used by official Dockerfiles (such as: nginx, redis)**, which is to do some configuration preparation work in the script specified by ENTRYPOINT, and then call CMD through exec "$@" in the last line of the ENTRYPOINT script command to start the container service.

CMD ["nginx", "-g", "daemon off;"]

  • The second method is to execute a command or shell script, and you can pass parameters. Note the double quotes. The syntax is the same as the first format, except that there is no ENTRYPOINT specified script, so it does not exist as a parameter of the ENTRYPOINT specified script.

CMD ["executable","param1","param2"]

  • The third type is the common syntax for executing shell scripts, such as executing echo "This is a test." | wc -cshell command line. The author said: "Don't use this method in Dockerfile, there is no need to know why."

CMD echo "This is a test." | wc -c
 

ENTRYPOINT

        If multiple ENTRYPOINTs are defined in a Dockerfile, only the last ENTRYPOINT will take effect , and every time the docker container is started, the script specified by ENTRYPOINT will be executed.

        For nginx:1.20.2, the "/docker-entrypoint.sh" script defines nginx configuration check and nginx service startup instructions. So usually "the script specified by ENTRYPOINT is usually the startup script of the core service in the image."

ENTRYPOINT ["/docker-entrypoint.sh"]

        This script finally executes the nginx service startup, which needs to be completed with the CMD command. Please refer to the CMD command below.

1.4. docker operation

For details, please refer to: 3-Docker basic operation commands · Linux operation and maintenance · Kanyun


1. Generate image

# docker build -t springboot-docker .
# docker build -f ./Dockerfile -t springboot-docker  .
# docker build -f ./Dockerfile -t springboot-docker:0.1  .

[root@ip-100 dockerfile]# docker images
REPOSITORY          TAG       IMAGE ID       CREATED              SIZE
springboot-docker   0.1       54dcc83613d7   About a minute ago   682MB
springboot-docker   latest    54dcc83613d7   About a minute ago   682MB


# Note:
# 1. The command is executed in the directory where the Dockerfile is located;
# 2. Be sure not to forget the following. The springboot-docker here is the actual generated image name.

  • --tag -t: The name and tag of the image, usually in name:tag or name format; multiple tags can be set for one image in one build.
  • -f: Specify the Dockerfile path to use

Reference: https://www.runoob.com/docker/docker-build-command.html

2. Run the image

  • -d: Indicates that the container is running in the background
  • --name: give the container a name
  • -p: Port mapping, the format is host port:container port, the above meaning is to map port 80 in the container to port 80 of the host to provide external access services.

The last field is the image name

# docker run --name springboot-docker01 -d -p 8080:8080 springboot-docker

[root@ip-100 dockerfile]# docker ps 
CONTAINER ID   IMAGE  COMMAND   CREATED  STATUS   PORTS    NAMES
65bb62a54e55   springboot-docker   "java -Djava.securit…"   33 seconds ago   Up 31 seconds   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp   springboot-docker01

Host browser: http://192.168.192.128:8080/getIpAndPort


3. View the startup log

docker logs xxx
docker logs -f springboot-docker01

2. Dockerfile multi-stage construction

2.1. Example 1 of using Dockerfile

FROM openjdk:8-jdk-alpine as build
WORKDIR /workspace/app

COPY mvnw .
COPY .mvn .mvn
COPY pom.xml .
COPY src src

RUN ./mvnw install -DskipTests
RUN mkdir -p target/dependency && (cd target/dependency; jar -xf ../*.jar)

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG DEPENDENCY=/workspace/app/target/dependency
COPY --from=build ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=build ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=build ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","hello.Application"]

2.2. Example 2 of using Dockerfile

Create a Dockerfile in the project root directory:

# 拉取编译环境
FROM maven:3.6.1 as builder

#拷贝源码到固定的目录,注意前面有个 '.'
COPY . /project

# 切换到源码目录
WORKDIR /project

# 使用maven进行编译
RUN mvn clean package -Dmaven.test.skip=true

# 拉取运行环境,这个镜像打包出的镜像比较小,如需要可换成oracle的jre
FROM fabric8/java-alpine-openjdk8-jre

# 从编译好的镜像中将jar拷贝到运行时容器
COPY --from=builder /project/target/your-jar-name.jar /

# 容器启动时执行的命令,这里可加jvm参数
ENTRYPOINT ["java","-jar","/mqtt-rule-engine.jar"]

# 开放端口,根据自己的配置进行开放
EXPOSE 8080

2.3. Example 3 of using Dockerfile

# First stage: complete build environment
FROM maven:3.5.0-jdk-8-alpine AS builder

# add pom.xml and source code
ADD ./pom.xml pom.xml
ADD ./src src/

# package jar
RUN mvn clean package

# Second stage: minimal runtime environment
From openjdk:8-jre-alpine

# copy jar from the first stage
COPY --from=builder target/my-app-1.0-SNAPSHOT.jar my-app-1.0-SNAPSHOT.jar

EXPOSE 8080

CMD ["java", "-jar", "my-app-1.0-SNAPSHOT.jar"]
FROM maven:3.6.3-openjdk-8 AS builder
 #  AS builder 起别名

RUN mkdir /build
# 创建临时文件

ADD src /build/src
#将 src目录复制到临时目录

ADD pom.xml /build
# 将 pom文件复制到临时目录

RUN cd /build && mvn -B -ntp package
# 打包

FROM adoptopenjdk/openjdk8:alpine-jre
# 获取jre

COPY --from=builder /build/target/ems-0.0.1-SNAPSHOT.jar /ems.jar
#从标记点 拷贝jar包 并改名

CMD ["java", "-jar", "/ems.jar"]

# 声明运行方式

 Execute the following command in the project root directory

docker build -t name:tag .
 

3. Plug-in packaging

3.1. spring-boot-maven-plugin plug-in packaging

SpringBoot has its own built-in Dockerimage packaging tool, so spring-boot-starter-parentwe don’t need extra settings. Advantages: No writing is required DockerFile, and there is no need to worry about security, memory, performance and other issues suggested by Spring.

3.2. jib-maven-plugin plug-in

GoogleA packaged plug-in from . Advantages: No local installation Dockeror writing is required DockerFile, and Jibit can be pushed directly to the specified Dockerwarehouse.

3.3. dockerfle-maven-plugin plug-in

It needs to be written DockerFileand needs a local Dockerenvironment, but it is the most useful, stable and freely controllable. Advantages: Stable, not subject to network restrictions, DockerFile is written by oneself, and has a high degree of freedom. You can change it however you want. I personally recommend this.

Plug-in packaging, for specific examples, please refer to: Several ways to package (build) Java (SpringBoot) projects into Docker images - Tencent Cloud Developer Community - Tencent Cloud

4, Reference:

docker compiles Dockerfile to automatically deploy the jar package of the springboot project_dockerfile compiles jar package_xixiyuguang's blog-CSDN blog

The latest multi-stage construction of dockerfile in 2021 implements java source code compilation, jar package and mirroring - Alibaba Cloud Developer Community

Several ways to package (build) Java (SpringBoot) projects into Docker images - Tencent Cloud Developer Community - Tencent Cloud

Compile, package, and deploy spring boot projects in docker_docker compiles during deployment_csdn_meng's blog-CSDN blog

Guess you like

Origin blog.csdn.net/yangyangye/article/details/132622061