Run the projects in the IDEA in the local docker?

  • 💻 Sword finger offer & leetcode question brushing warehouse: https://github.com/Damaer/CodeSolution
  • 📒 Programming knowledge base: https://github.com/Damaer/Coding
    • Document address: https://damaer.github.io/Coding/#/
  • preface
  • Docker transformation
    • 1. Plug in configuration
    • 2. DockerFile file configuration
    • 3. Run in jar package mode
    • 4. Maven & docker compilation
    • 5. Error reporting solution
  • Pit point

preface

The local projects based on springboot,redis and mybatis have been built. Redis and mybatis are all run in docker, but the whole project still runs on IDEA. It's better to toss around and let the project run on docker.

Note: the project is transformed from the previous project: How to quickly build a Springboot + Mysql + Redis project based on Docker

Project address: https://github.com/Damaer/DemoCode/tree/main/springboot/springDocker

Docker transformation

1. Plug in configuration

First, you need to add docker's maven packaging plug-in in the pom file:

            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>

Several items are configured:

  • ${docker.image.prefix}: prefix of image name. Here I use aphysia
  • ${project.artifactId}: artifactId of the project, coordinates
  • < dockerdirectory > Src / main / docker < / dockerdirectory >: configure the file path that docker needs to generate the image

2. DockerFile file configuration

Therefore, we need to create a docker folder under src/main with DockerFile in it to generate a docker image:

FROM openjdk:8-jdk-alpine
EXPOSE 8081
VOLUME /tmp
ADD springbootdocker-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
  • FROM: which image to build is based on, based on openjdk:8-jdk-alpine
  • Export: which ports does the docker container need to listen to when running? We use 8081
  • VOLUME: data VOLUME, which is used to store persistent data. Generally, the data should be persistent to the host, otherwise the container will be deleted, and the data will be lost. Therefore, VOLUME can correspond the directory on the host with the directory in the container as the persistent directory, It is equivalent to creating a temporary file in the / var/lib/docker directory of the host and linking it to the / tmp directory in the container.
  • ADD: copy the jar package (file) to docker and rename it app jar
  • ENTRYPOINT: Specifies the execution command to run the image. Here, use the java -jar command to run the jar package

For VOLUME, we can use the docker inspect eaf13c07d079daba6ecb8f2d59019ad053d79bbce1e6c8e10a52e79637730e70 command to check (the long string is the id of the image):

image-20211123083941908

We can see that there is such a paragraph:

"Mounts": [
            {
                "Type": "volume",
                "Name": "e8863daa5874f6446560673f0a260a4fd2b127b71d31318e6546843f8b283a48",
                "Source": "/var/lib/docker/volumes/e8863daa5874f6446560673f0a260a4fd2b127b71d31318e6546843f8b283a48/_data",
                "Destination": "/tmp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]

Source is the directory in our host and Destination is the directory in our container. The two are associated, that is, the data volume.

3. Run in jar package mode

Since we need to copy the jar package earlier, where does the jar package come from? The answer is that we need to configure it to run as a jar package to see:

    <groupId>com.aphysia</groupId>
    <artifactId>springbootdocker</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springbootdocker</name>
    <packaging>jar</packaging>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <docker.image.prefix>aphysia</docker.image.prefix>
    </properties>

After compiling and running, you will see that the jar package file is generated under target:

image-20211123084611668

4. Maven & docker compilation

First compile with maven in IDEA:

mvn clean package -U
mvn clean install

At this time, I encountered some errors in environment variables, which are those of Maven and Java. Note that I need to configure them. I am a Mac and use zsh, so I need to configure the environment variables of zsh:

You can use open ~ / bash_ Profile and open ~ / Zshrc see the configuration inside:

export M2_HOME="/Users/aphysia/config/apache-maven-3.6.3"
export PATH="$M2_HOME/bin:$PATH"
export PATH
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_261.jdk/Contents/Home
export JAVA_HOME
CLASS_PATH="$JAVA_HOME/lib"
PATH=".$PATH:$JAVA_HOME/bin"

After modification, remember to use source ~ / bash_ Refresh the profile.

After mvn is compiled, a jar package is generated. We can run it with the Java jar command:

java -jar springBootDocker-0.0.1-SNAPSHOT.jar

If there is no problem, you can compile the image with the docker command:

mvn docker:build -Dmaven.test.skip 

DockerFile file, five steps are successful:

image-20211123090108680

View docker image:

% docker images
REPOSITORY                 TAG            IMAGE ID       CREATED         SIZE
aphysia/springbootdocker   latest         dde6911c8e25   47 hours ago    137MB
<none>                     <none>         ee52277559a6   47 hours ago    137MB
redis                      latest         40c68ed3a4d2   5 days ago      113MB
redis                      <none>         84c5f6e03bf0   14 months ago   104MB
mysql                      latest         e1d7dc9731da   14 months ago   544MB
docker/getting-started     latest         1f32459ef038   16 months ago   26.8MB
openjdk                    8-jdk-alpine   a3562aa0b991   2 years ago     105MB

It's time to compile and run the image using docker (please run Redis and Mysql image first):

docker run -p 8081:8081 -t aphysia/springbootdocker

5. Error reporting solution

The above command is executed, and there seems to be no error, but the request is: http://localhost:8081/getUserList The following errors are reported when:

io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:6379
Caused by: java.net.ConnectException: Connection refused
	at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_212]
	at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) ~[na:1.8.0_212]
	at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:707) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_212]

2021-11-23 15:50:08.446 DEBUG 1 --- [ioEventLoop-4-1] io.lettuce.core.RedisChannelHandler      : closeAsync()
2021-11-23 15:50:08.447 DEBUG 1 --- [ioEventLoop-4-1] i.lettuce.core.protocol.DefaultEndpoint  : [unknown, epid=0x1] closeAsync()
2021-11-23 15:50:08.464 DEBUG 1 --- [ioEventLoop-4-1] io.lettuce.core.protocol.CommandHandler  : [channel=0x6d227ef0, [id: 0x5a58ec1f] (inactive), epid=0x1, chid=0x1] channelUnregistered()
2021-11-23 15:50:08.467 DEBUG 1 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Failed to complete request: org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379
2021-11-23 15:50:08.478 ERROR 1 --- [nio-8081-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to 127.0.0.1:6379] with root cause

java.net.ConnectException: Connection refused
	at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_212]
	at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) ~[na:1.8.0_212]
	at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:707) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.69.Final.jar!/:4.1.69.Final]
	at java.lang.Thread.run(Thread.java:748) [na:1.8.0_212]

What is the reason?

The reason is that the network between each container in docker is isolated from each other. We use 127.0.0.1 in the application. Of course, the local network is used when running in IDEA, but when deployed in docker container, localhost must use the container itself, but the application container itself does not have redis or mysql, so the request fails

Simply put: because the ip addresses between containers are isolated, they cannot be accessed through local ports.

How can we solve it?

We can check whether the container really has its own ip. We can first use docker images to view the image, then docker exec -it c178e8998e68 bash(c178e8998e68 is the container id), and then use cat -etc/hosts to view the ip:

% docker ps
CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
3f27e28aa3f6   aphysia/springbootdocker   "java -jar /app.jar"     9 minutes ago   Up 9 minutes   0.0.0.0:8081->8081/tcp, :::8081->8081/tcp              epic_mendeleev
c178e8998e68   mysql                      "docker-entrypoint.s..."   21 hours ago    Up 21 hours    0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql
7a5056f4c28b   redis                      "docker-entrypoint.s..."   21 hours ago    Up 21 hours    0.0.0.0:6379->6379/tcp, :::6379->6379/tcp              redis

% docker exec -it c178e8998e68 bash

root@c178e8998e68:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 c178e8998e68

Or you can directly click cli from docker, and use cat -etc/hosts to view the ip. You can see that the external ip of the container is 172.17.0.3:

image-20211124230444387

Similarly, we can get the ip of mysql container, reconfigure the link in the project, repackage it, run docker, and then visit http://localhost:8081/getUserList , you can see that the container log is normal.

image-20211124230907588

Pit point

When using the docker command to build the image, the following error messages appear:

Failed to execute goal com.spotify:docker-maven-plugin:1.0.0:build (default-cli) on project dockerDemo: Exception caught: java.util.concurrent.ExecutionException: com.spotify.docker.client.shaded.javax.ws.rs.ProcessingException: org.apache.http.client.ClientProtocolException: Cannot retry request with a non-repeatable request entity: Connection reset by peer -> [Help 1]

I've encountered a Waterloo in my life. At first glance, it seems to be the docker made plugin problem of packaging plug-ins. After a search, I changed the version, but it doesn't work. My version:

        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <imageName>${docker.image.prefix}/${project.artifactId}</imageName>
                    <dockerDirectory>src/main/docker</dockerDirectory>
                    <resources>
                        <resource>
                            <targetPath>/</targetPath>
                            <directory>${project.build.directory}</directory>
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>

Finally, I found a problem. My previous project had capital letters, while < imagename >

There are corresponding discussions on GitHub: https://github.com/spotify/docker-maven-plugin/issues/357

image-20211124231536247

Added by danlindley on Thu, 17 Feb 2022 03:20:50 +0200