Learn Spring Boot: using Docker in Spring Boot

preface

Simply learn how to use Docker to build and publish an image in Spring Boot. Now we build an image, run a container, publish an image and so on through the remote docker api.

Only two methods are introduced here:

  1. Remote command api (need to know Docker command)
  2. maven plug-in (you don't need to know the Docker command)

Enable Docker api remote access

Enable the remote operation function of docker api,
For example, in centos 7, in the / usr/lib/systemd/system/docker.service file, modify the parameters of ExecStart:

ExecStart=/usr/bin/dockerd  -H tcp://0.0.0.0:2375  -H unix:///var/run/docker.sock

You can customize the port settings.

Reload all modified configuration files and restart docker,

systemctl daemon-reload    
systemctl restart docker.service 

It should be noted that because there is no password to log in and any permission verification, the certificate is required for the external network or production environment.

Command mode to build image

This method is actually very simple. You need to understand the docker command before you can operate it.

After opening the Docker Api above, we can use the network environment to operate the Docker engine.

  1. Create a Dockerfile to build the image file. Create a new folder to store the files needed to build the image. I created / src/docker/

    FROM java:8
    EXPOSE 8080
    
    VOLUME /tmp
    ADD springboot-docker.jar app.jar
    ENTRYPOINT ["java","-jar","/app.jar"]
    
  2. Execute the maven command to package the project mvn clean package --DskipTests, and then put the jar package into the Dockerfile project directory.

  3. Then enter the src/docker directory and execute:

    docker -H tcp://xxx.xxx.xxx.xxx:2375 build -t test .
    

    Start building the mirror:

    Sending build context to Docker daemon  31.74MB
    Step 1/5 : FROM java:8
     ---> d23bdf5b1b1b
    Step 2/5 : EXPOSE 8080
     ---> Using cache
     ---> 060a43a42146
    Step 3/5 : VOLUME /tmp
     ---> Using cache
     ---> b4f88fde6181
    Step 4/5 : ADD springboot-docker.jar app.jar
     ---> 3a40188825b0
    Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
     ---> Running in ab093916fc4c
    Removing intermediate container ab093916fc4c
     ---> 45a3966feb60
    Successfully built 45a3966feb60
    Successfully tagged test:latest
    

    ?

Building images using docker Maven plugin

Add docker maven plugin under maven project

            <!--pack docker Configuration of plug-in related parameters-->
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>0.4.14</version>
                <configuration>
                    <!--Packaged image name-->
                    <imageName>${project.groupId}/${project.artifactId}</imageName>
                    <!--Dockerfile File location to project root The directory is the root node. It is recommended to create a separate directory-->
                    <dockerDirectory>./src/docker/</dockerDirectory>
                    <!--Docker Remote API Address and port-->
                    <dockerHost>http://xxx.xxx.xxx.199:2375</dockerHost>
                    <imageTags>
                        <imageTag>latest</imageTag>
                    </imageTags>
                    <!--Execute build docker What files are needed for mirroring, springboot Project specified packaged jar Just mirror-->
                    <resources>
                        <resource>
                            <!--The file specified here is target Medium jar file-->
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>

Create Dockerfile

It needs to be consistent with the path configured above in pom.xml, so my path is ${baseProjectFolder}/src/docker. Create a new file Dockerfile and add the command parameters related to building docker:

FROM java:8
EXPOSE 8080

VOLUME /tmp 
ADD springboot-docker.jar app.jar # Modify according to the file name of the packaged jar package
ENTRYPOINT ["java","-jar","/app.jar"]

pack

Execute the command under the root directory of the application (package and dokcer build):

$ mvn clean package docker:build -DskipTests

For example, I use my project to package and complete the construction of docker:

[INFO] Building image com.wuwii/springboot-docker
Step 1/5 : FROM java:8

 ---> d23bdf5b1b1b
Step 2/5 : EXPOSE 8080

 ---> Running in b7936baae57f
Removing intermediate container b7936baae57f
 ---> 060a43a42146
Step 3/5 : VOLUME /tmp

 ---> Running in 65e2b8ac44d3
Removing intermediate container 65e2b8ac44d3
 ---> b4f88fde6181
Step 4/5 : ADD springboot-docker.jar app.jar

 ---> aa3762cda143
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]

 ---> Running in d9f5f63b9736
Removing intermediate container d9f5f63b9736
 ---> 622a7d1e315c
ProgressMessage{id=null, status=null, stream=null, error=null, progress=null, progressDetail=null}
Successfully built 622a7d1e315c
Successfully tagged com.wuwii/springboot-docker:latest

Use mirror

  1. Enter the host where docker is installed and use the command to view the image (the IMAGE ID is consistent with the above):

    $ docker image ls com.wuwii/springboot-docker
    REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
    com.wuwii/springboot-docker   latest              622a7d1e315c        22 minutes ago      659MB
    
  2. Run container:

    $ docker run -d -p 8080:8080 --name learn  com.wuwii/springboot-docker
    
    180fe4a7ddfc10c0cf2c37649ae1628e804564bfe1594ef05840e707801e6da3   
    

    Listen to port 8080 and test whether it is successful.

Service composition

In general, many external tools are used in our WEB projects, such as Redis, MYSQL, ES, etc. if we start building and deploying one by one, it's too troublesome. We have to test. Can we use this set of environment elsewhere?

Using service orchestration can avoid these pitfalls.

Add Mysql database to our project, and create a docker-compose.yml in the root directory:

version: '3'
services:
  web:
    depends_on:
      - db
    ports:
      - "8080:8080" # Quotation marks are recommended. If a single two digit number, parsing problems may occur
    restart: always
   # build:
    #  context: ./src/docker # The directory of Dockerfile file, which can be a remote address, absolute or relative
     # dockerfile: Dockerfile # If your Dockerfile is renamed, you need to specify
    image: test:latest
    environment:
      DB_HOST: db:3306
      DATABASE: learn
      DB_USERNAME: root # root for test
      DB_PASSWORD: 123456 #  # It is recommended to use secret

  db:
    image: mysql:5.7
    volumes:
        - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: learn
      MYSQL_USER: kronchan
      MYSQL_PASSWORD: 123456

volumes:
  db_data:  # The data volume used must be declared

Above, I use the previously built image and then execute the orchestration. Better, I use build directly to make it choreograph the service itself.

The system configuration file application.yml uses the default value, which does not affect the use of development:

spring:
  datasource:
    url: jdbc:mysql://${DB_HOST:localhost:3306}/${DATABASE:learn}?useSSL=false&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8
    username: ${DB_USERNAME:root}
    password: ${DB_PASSWORD:123456}
    driver-class-name: com.mysql.jdbc.Driver
  jpa:
    show-sql: true
    database: mysql
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL57Dialect # Select the dialect according to the database version

You can also use different spring.profiles to specify different environments. It is also common to override the specified environment for executing commands in docker-compose.yml: Command: MVN clean spring boot: Run - dspring boot. Run. Profiles = XXX

Finally, start and execute in the docker-compose.yml Directory: docker compose up

Close the service docker compose down

be careful

The problem of docker compose sequence is a problem that needs attention when learning orchestration. If mysql starts slowly in the above service orchestration, the web project will fail to start. When it starts, it does not know whether the dependent service is started or not.

The solutions are as follows:

  • Sufficient fault tolerance and retry mechanisms, such as connecting to the database. When the initial connection fails, the service consumer can continue to retry until the location is connected
  • Docker composition is split and deployed in two parts. The services to be started first are placed in one docker composition, and the services to be started later are placed in two docker compositions. They are started twice and use the same network.
  • Wait synchronously. Use wait-for-it.sh or other shell scripts to start blocking the current service until the dependent service is loaded
    The github address of wait for it is: wait-for-it

summary

  1. When writing Dockerfile, I'd better take out a separate folder and put it in the root path of the project. As a result, when building the image, it always appears that other files are copied to the Docker directory together. For the operation of using the maven plug-in under windows, we need to pay attention to this context, Otherwise, it's easy to copy all the files on a disk. It's a lesson for beginners. The solution is to create a separate folder and put the things you need separately, so you don't have to consider so many problems.

Keywords: Java Spring Boot Back-end

Added by Ken2k7 on Thu, 18 Nov 2021 17:25:35 +0200