前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无快不破,在本地 docker 运行 IDEA 里面的项目?

无快不破,在本地 docker 运行 IDEA 里面的项目?

作者头像
秦怀杂货店
发布2022-02-17 08:28:22
9690
发布2022-02-17 08:28:22
举报
文章被收录于专栏:技术杂货店技术杂货店
  • 💻 剑指Offer & LeetCode刷题仓库:https://github.com/Damaer/CodeSolution
  • 📒 编程知识库:https://github.com/Damaer/Coding
    • 文档地址:https://damaer.github.io/Coding/#/
  • 前言
  • Docker改造
    • 1. 插件配置
    • 2. DockerFile 文件配置
    • 3. 以 jar 包方式运行
    • 4. maven & Docker编译
    • 5. 报错解决
  • 坑点

前言

前面已经搭建好了本地基于springboot,redismybatis的项目,其中redis,mybatis都是在docker中运行的,但是整个项目还是在IDEA上运行的,不如折腾一下,让项目在docker上跑起来。

注意:项目是在之前的项目基础上改造而来的:如何基于 Docker 快速搭建 Springboot + Mysql + Redis 项目

项目地址:https://github.com/Damaer/DemoCode/tree/main/springboot/springDocker

Docker改造

1. 插件配置

首先pom文件里面需要增加docker 的maven打包插件

代码语言:javascript
复制
            <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>

里面配置了几个项:

  • ${docker.image.prefix}:镜像名字的前缀,这里我使用aphysia
  • ${project.artifactId}: 项目的artifactId,坐标
  • <dockerDirectory>src/main/docker</dockerDirectory>:配置的是docker生成镜像需要用到的文件路径

2. DockerFile 文件配置

因此,我们需要在src/main下新建一个docker文件夹,里面放了DockerFile,生成docker镜像:

代码语言:javascript
复制
FROM openjdk:8-jdk-alpine
EXPOSE 8081
VOLUME /tmp
ADD springbootdocker-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
  • FROM: 要构建的镜像基于哪个镜像,基于openjdk:8-jdk-alpine
  • EXPOSE: Docker这个容器在运行时需要监听哪些端口,我们用8081
  • VOLUME: 数据卷,用于保存持久化的数据,一般数据都要持久化到主机上,要不容器删除了,数据就没有了,所以VOLUME可以把主机上的目录和容器中的目录对应起来,作为持久化目录,相当于在主机的/var/lib/docker目录下创建一个临时文件并把它链接到容器中的/tmp目录。
  • ADD:把这个jar包(文件)拷贝到docker中,并且改名为app.jar
  • ENTRYPOINT:指定执行命令,用于运行镜像的,这里是用java -jar命令来运行jar

关于VOLUME,我们可以使用docker inspect eaf13c07d079daba6ecb8f2d59019ad053d79bbce1e6c8e10a52e79637730e70命令去查看(长长的那串是镜像的id):

image-20211123083941908

我们可以看到里面有这么一段:

代码语言:javascript
复制
"Mounts": [
            {
                "Type": "volume",
                "Name": "e8863daa5874f6446560673f0a260a4fd2b127b71d31318e6546843f8b283a48",
                "Source": "/var/lib/docker/volumes/e8863daa5874f6446560673f0a260a4fd2b127b71d31318e6546843f8b283a48/_data",
                "Destination": "/tmp",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]

Source是我们主机中的目录,Destination是我们容器中的目录,两者关联起来了,也就是数据卷。

3. 以 jar 包方式运行

既然前面我们需要拷贝 jar 包,那么 jar 包从哪里来呢?答案是我们需要配置成以jar包运行,才能看到:

代码语言:javascript
复制
    <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>

编译运行,就会看到target下生成了jar包文件:

image-20211123084611668

4. maven & Docker编译

先在IDEAmaven编译:

代码语言:javascript
复制
mvn clean package -U
mvn clean install

这个时候,我遇到了一些环境变量的错误,是MavenJava的环境变量的,注意需要配置,本人是Mac,用的的zsh,所以需要配置zsh的环境变量:

可以用open ~/.bash_profile以及open ~/.zshrc看看里面的配置:

代码语言:javascript
复制
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"

修改完,记得用source ~/.bash_profile 刷新一下。

mvn编译完,生成了jar包,我们可以用java -jar命令运行一下:

代码语言:javascript
复制
java -jar springBootDocker-0.0.1-SNAPSHOT.jar

如果没有问题,就可以用docker命令编译镜像:

代码语言:javascript
复制
mvn docker:build -Dmaven.test.skip 

DockerFile 文件,五步都成功了:

image-20211123090108680

查看docker镜像:

代码语言:javascript
复制
% 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

是时候到使用docker编译运行镜像了(注意先运行RedisMysql镜像):

代码语言:javascript
复制
docker run -p 8081:8081 -t aphysia/springbootdocker

5. 报错解决

上面命令执行,看起来没啥报错,但是请求:http://localhost:8081/getUserList的时候,报了以下的错误:

代码语言:javascript
复制

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]

这是什么原因呢?

原因是docker中的每一个容器之间的网络是相互隔离的,我们在应用中用的是127.0.0.1,在IDEA里面运行当然用的是本机网络,但是都部署到Docker容器中的时候,localhost用的肯定是容器本身的,但是应用容器本身没有redis,也没有mysql,所以请求就失败了

简单来说:因为容器和容器之间的ip是隔离的,无法互相通过本地端口访问。

那我们怎么解决呢?

我们可以去看看容器是不是真的有自己的ip,可以先用docker images查看镜像,再用docker exec -it c178e8998e68 bash(c178e8998e68 是容器id),然后用cat -etc/hosts查看ip:

代码语言:javascript
复制
% 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

或者直接从docker中点击cli也可以,用cat -etc/hosts查看ip,可以看到该容器对外的ip172.17.0.3:

image-20211124230444387

同样的我们可以获取到mysql容器的ip,在项目里重新配置链接,然后重新打包,docker运行,就可以了,再访问http://localhost:8081/getUserList,容器的日志也可以看出来正常了。

image-20211124230907588

坑点

在用docker命令build镜像的时候,出现了以下的报错:

代码语言:javascript
复制
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]

遭遇了人生的滑铁卢,咋一看,貌似是打包插件的docker-maven-plugin问题,一顿搜索,换了版本,居然不行,我的版本:

代码语言:javascript
复制
        <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>

最后发现了问题,我之前的项目中有大写字母,而<imageName>

github上有对应的讨论:https://github.com/spotify/docker-maven-plugin/issues/357

image-20211124231536247

【作者简介】

秦怀,技术之路不在一时,山高水长,纵使缓慢,驰而不息。个人写作方向:Java源码解析,JDBC,Mybatis,Spring,Redis,分布式,剑指Offer,LeetCode等,认真写好每一篇文章,不喜欢标题党,不喜欢花里胡哨,大多写系列文章,不能保证我写的都完全正确,但是我保证所写的均经过实践或者查找资料。遗漏或者错误之处,还望指正。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 秦怀杂货店 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Docker改造
    • 1. 插件配置
      • 2. DockerFile 文件配置
        • 3. 以 jar 包方式运行
          • 4. maven & Docker编译
            • 5. 报错解决
            • 坑点
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档