Spring Boot3 集成 Docker 总踩坑?从环境到部署30分钟带你避坑实战

61 阅读8分钟

前言

作为互联网开发,你是不是也遇到过这样的情况:好不容易用 Spring Boot3 开发完项目,一到 Docker 集成环节就频繁掉坑 —— 要么是 Dockerfile 编写错误导致镜像构建失败,要么是容器启动后报 “端口映射冲突”,甚至有时候打包的镜像体积大到离谱,部署时卡半天?其实不止你一个,我最近在技术社区逛的时候,发现不少同行都在吐槽 Spring Boot3 和 Docker 集成的 “坑点”,今天就结合实战经验,把从环境准备到最终部署的全流程拆解开,帮你避开那些容易踩的雷。

为什么现在都要做 Spring Boot3+Docker 集成?

可能有刚接触容器化的朋友会问:我直接把 Spring Boot3 项目部署到服务器上不行吗?为啥非要多一步 Docker 集成?这就不得不提当下互联网开发的大趋势了 —— 微服务架构越来越普及,一个项目往往拆分成十几个甚至几十个服务,要是每个服务都单独在服务器上配置环境、解决依赖冲突,不仅效率低,还很容易出现 “本地能跑、线上跑不通” 的问题。

而 Docker 的核心优势就是 “环境一致性”—— 把 Spring Boot3 项目和它依赖的 JDK、配置文件等打包成镜像,不管是在开发环境、测试环境还是生产环境,只要能运行 Docker,项目就能稳定启动,不会因为环境差异出问题。另外,Spring Boot3 本身对容器化做了不少优化,比如支持分层打包来减小镜像体积,还能通过配置直接指定容器内的 JVM 参数,这些特性让两者的集成变得更有必要。根据某云厂商的统计数据,2024 年使用 Spring Boot3 开发的项目中,有 82% 都会选择用 Docker 进行容器化部署,足以见得这个集成方案已经成为行业主流。

避坑第一步:先把环境配置对

很多人集成时第一步就栽在环境上,比如 JDK 版本不匹配、Docker daemon 没启动,或者 Maven 打包时少了关键插件。咱们先从基础环境开始,一步一步确认:

1. 确认本地环境版本(这 3 个版本要对应)

首先,你的本地环境需要满足这三个条件:

  • JDK 版本:至少是 JDK17,因为 Spring Boot3 最低要求 JDK17,要是用低于 17 的版本,哪怕 Docker 镜像构建成功,容器启动时也会报 “Unsupported class file major version” 错误;
  • Docker 版本:建议用 Docker Desktop 4.0 以上(Windows/Mac),Linux 系统建议 Docker 20.10 以上,低版本可能不支持 Spring Boot3 的分层打包特性;
  • Maven/Gradle 版本:Maven 建议 3.8+,Gradle 建议 7.5+,主要是为了兼容 Spring Boot3 的插件。

这里教你一个快速检查版本的小技巧:打开终端,依次输入java -version、docker -v、mvn -v,确保输出的版本符合要求。如果 JDK 版本不对,别慌,现在很多 IDE 都支持多 JDK 切换,比如 IntelliJ IDEA 在 “Project Structure” 里就能快速指定 JDK17。

2. 配置 Spring Boot3 项目的 pom.xml(关键插件别漏)

如果是 Maven 项目,一定要在 pom.xml 里加入 Docker 相关的插件,不然没办法打包成 Docker 镜像。这里推荐用 Spotify 的 docker-maven-plugin,配置起来简单,还支持分层打包。正确的配置应该是这样的(注意替换成你的项目信息):

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>1.2.2</version>
    <configuration>
        <!-- 镜像名称:格式为 仓库名/镜像名:标签 -->
        <imageName>your-docker-repo/springboot3-demo:1.0.0</imageName>
        <!-- Dockerfile所在路径,默认是项目根目录 -->
        <dockerDirectory>${project.basedir}</dockerDirectory>
        <resources>
            <resource>
                <targetPath>/</targetPath>
                <!-- 指向打包后的jar包路径 -->
                <directory>${project.build.directory}</directory>
                <include>${project.build.finalName}.jar</include>
            </resource>
        </resources>
    </configuration>
</plugin>

这里有个容易踩的坑:很多人会把dockerDirectory配置成src/main/docker,但如果你的 Dockerfile 在项目根目录,就会导致插件找不到 Dockerfile,构建镜像时直接报错。所以一定要确认 Dockerfile 的路径和配置里的一致。

核心步骤:Dockerfile 编写 + 镜像构建 + 容器启动

环境准备好之后,就进入最核心的集成环节了。这一步我拆成 3 个小步骤,每个步骤都标注了容易踩的坑,你照着做就能少走弯路。

1. 编写 Dockerfile(这 3 个配置别写错)

Dockerfile 是构建镜像的 “说明书”,Spring Boot3 项目的 Dockerfile 其实不复杂,但有几个关键配置绝对不能错:

# 第一步:指定基础镜像,建议用openjdk的slim版本,体积更小
FROM openjdk:17-jdk-slim

# 第二步:创建工作目录,避免文件混乱
WORKDIR /app

# 第三步:把本地打包好的jar包复制到容器里(左边是本地路径,右边是容器路径)
COPY target/springboot3-demo-1.0.0.jar /app/app.jar

# 第四步:指定容器启动时执行的命令
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

这里有 3 个避坑点必须注意:

  • 基础镜像别用错:很多人会用openjdk:17-jdk,但这个版本包含很多不必要的工具,镜像体积会比slim版本大 200M 以上,部署时会浪费带宽和存储空间,所以优先选slim版本;
  • COPY 路径别写反:COPY 命令的格式是 “本地文件路径 容器内路径”,要是写成COPY /app/app.jar target/springboot3-demo-1.0.0.jar,就会导致把容器里的文件复制到本地,完全搞反了;
  • ENTRYPOINT 别漏括号:如果写成ENTRYPOINT java -jar /app/app.jar,虽然也能启动,但在传递参数时会有问题,比如想指定 JVM 参数就会失效,所以一定要用数组格式的 ENTRYPOINT。

2. 构建 Docker 镜像(执行命令前先确认 2 件事)

编写完 Dockerfile 后,就可以用 Maven 命令构建镜像了。打开终端,进入项目根目录,执行以下命令:

mvn clean package docker:build

执行命令前,一定要确认 2 件事:

  • 本地 Docker 已经启动:如果 Docker 没启动,插件会报 “Cannot connect to the Docker daemon” 错误,Windows 用户可以打开 Docker Desktop,Linux 用户执行systemctl start docker;
  • 项目已经打包成功:docker:build命令依赖package命令生成的 jar 包,如果 jar 包没生成,就会导致 COPY 命令找不到文件。所以如果之前没打包过,最好先执行mvn clean package,确认 target 目录下有 jar 包再执行构建命令。

构建成功后,执行docker images命令,就能看到你刚才构建的镜像了。比如我构建的镜像名称是
your-docker-repo/springboot3-demo:1.0.0,在列表里能看到它的 TAG 和 IMAGE ID,就说明构建成功了。

3. 启动 Docker 容器(端口映射别冲突)

镜像构建成功后,下一步就是启动容器。执行以下命令:

docker run -d -p 8080:8080 --name springboot3-demo-container your-docker-repo/springboot3-demo:1.0.0

这里的参数解释一下:

  • -d:表示后台运行容器;
  • -p 8080:8080:表示端口映射,左边是宿主机端口,右边是容器内端口(Spring Boot 项目默认端口是 8080);
  • --name:给容器起个名字,方便后续管理。

这一步最容易踩的坑就是 “端口冲突”—— 如果宿主机的 8080 端口已经被其他程序占用,容器就会启动失败,报 “Bind for 0.0.0.0:8080 failed: port is already allocated” 错误。解决方法有两个:要么停止占用 8080 端口的程序,要么把宿主机端口改成其他未占用的端口,比如-p 8081:8080(用 8081 端口访问宿主机)。

容器启动后,执行docker ps命令,如果能看到
springboot3-demo-container这个容器的状态是 “Up”,就说明启动成功了。此时你打开浏览器,访问http://localhost:8080(如果改了端口就用改后的端口),就能看到 Spring Boot3 项目的默认页面,或者你自己写的接口返回结果了。

最后总结:3 个核心避坑点 + 1 个行动呼吁

回顾整个 Spring Boot3 与 Docker 的集成流程,其实最容易踩坑的地方就 3 个:

  1. 环境版本不匹配:尤其是 JDK 版本低于 17,或者 Docker 版本太低,会导致后续步骤全走不通,所以第一步一定要确认版本;
  2. Dockerfile 配置错误:比如基础镜像用错、COPY 路径写反,这些小错误会直接导致镜像构建失败,建议写完后对照着我给的示例再检查一遍;
  3. 端口映射冲突:启动容器时如果报端口占用错误,别慌,要么换端口,要么停掉占用端口的程序,很快就能解决。

其实 Spring Boot3 和 Docker 的集成并没有那么复杂,只要按照 “环境准备→Dockerfile 编写→镜像构建→容器启动” 的步骤来,避开上面说的那些坑,30 分钟就能搞定。

最后想跟你说:光看教程没用,一定要动手实践。今天就把你手里的 Spring Boot3 项目拿出来,按照文中的步骤试一遍,要是遇到问题,比如镜像构建失败、容器启动后访问不到,都可以在评论区留言,我会帮你分析原因。也欢迎你把实践过程中发现的新避坑点分享出来,咱们一起帮更多同行少走弯路~