SpringBoot项目Docker部署全流程详解

 更新时间:2026年07月28日 09:10:02   作者:奈何不吃鱼  
在Docker部署SpringBoot后台管理系统时,你是否也遇到过Quartz表结构缺失或MySQL外键报错的问题,本文将复盘完整部署流程,从配置修改、Dockerfile编写到容器启动,重点剖析Quartz定时任务框架的数据库初始化陷阱,需要的朋友可以参考下

前言

最近在部署一个基于 Spring Boot 的后台管理系统到 Linux 服务器,采用了 Docker 容器化部署的方式。虽然 Docker 部署已经是主流,但在实际操作中,特别是涉及定时任务框架 Quartz 的数据库表结构初始化时,还是遇到了一些比较隐蔽的“坑”。本文将复盘整个部署流程,从 JAR 包准备、Dockerfile 编写到容器启动、故障排查进行完整记录,希望能帮助大家避坑。

一、 准备工作:配置与环境

在打 JAR 包之前,最重要的一步是修改配置文件以适配生产环境。很多同学习惯在本地用 localhost 开发,如果直接打包丢到服务器,容器内是找不到 localhost 的数据库的。

1. 修改数据库与中间件连接

进入 application-prod.yml(或 application.yml),重点检查以下配置:

  • 数据库 URL:将 localhost 修改为服务器真实的 IP 地址或数据库服务地址。
  • Redis 地址:同上,修改为真实 IP。
  • 文件上传路径:确保路径为 Linux 格式(如 /app/upload),避免使用 Windows 路径(C:/upload)。

2. 打包项目

在项目根目录执行 Maven 命令:

mvn clean package

打包成功后,在target目录下找到myproject-admin.jar(本文以此命名)。

二、 编写 Dockerfile

将 JAR 包上传到服务器(如 /opt/docker/myproject/)目录下,并在同目录下创建 Dockerfile 文件。

Dockerfile 内容详解

# 1. 指定基础镜像
# 这里选用 Eclipse Temurin (JDK 17) 的 Alpine 版本,体积小,安全性好
FROM eclipse-temurin:17-jre-alpine
# 2. 设置工作目录
WORKDIR /app
# 3. 解决时区问题 (关键步骤)
# Alpine 镜像默认时区是 UTC,需要安装 tzdata 并配置为上海时区
# 利用 Docker 缓存机制,将系统依赖安装放在 COPY 之前
RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    apk del tzdata
# 4. 拷贝 JAR 包
COPY myproject-admin.jar .
# 5. 声明服务端口
EXPOSE 8080
# 6. 配置 JVM 参数
# -Xms/Xmx: 限制堆内存,防止容器 OOM
# -Djava.security.egd: 解决 Linux 下随机数生成阻塞导致启动慢的问题
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
# 7. 启动命令
# 使用 sh -c 启动是为了让环境变量 $JAVA_OPTS 生效
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar myproject-admin.jar"]

三、 构建与运行

1. 构建镜像

在 JAR 包所在目录执行:

docker build -t myproject-server:1.0 .

看到 Successfully builtSuccessfully tagged 提示即表示构建成功。

2. 启动容器(生产推荐配置)

docker run -d \
  --name myproject-app \
  -p 8080:8080 \
  -m 1.5g \
  --cpus 1 \
  --restart=on-failure:5 \
  -v /home/myproject/logs:/app/logs \
  myproject-server:1.0

参数解释:

  • -d: 后台运行。
  • -m 1.5g: 限制容器最大内存。JVM 堆内存设置了 1G,给元空间等预留 500M,防止容器被宿主机 Kill。
  • --restart=on-failure:5: 容器异常退出时自动重启,增强健壮性。
  • -v: 挂载日志目录,方便在宿主机直接查看日志。

四、 踩坑实录:Quartz 表结构问题

1. 问题现象

容器启动瞬间报错,通过 docker logs -f myproject-app 查看日志,发现如下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sysJobServiceImpl': ...
Caused by: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: Table 'db_name.QRTZ_LOCKS' doesn't exist

原因分析
项目集用了 Quartz 定时任务框架,且配置了 JDBC 模式持久化。但数据库中缺少了 Quartz 所需的标准表结构(QRTZ_ 开头的表)。

2. 尝试解决与报错

找到项目中的 sql/quartz.sql 脚本并导入,结果执行时报错:

ERROR 1826 (HY000): Duplicate foreign key constraint name 'QRTZ_TRIGGERS_ibfk_1'
ERROR 1824 (HY000): Failed to open the referenced table 'QRTZ_TRIGGERS'

这是因为脚本中的表之间存在外键依赖,且数据库中可能残留了之前的元数据,导致脚本执行中断。

3. 最终解决方案

核心思路:先关闭外键检查,再手动逐表创建(或使用不含外键的建表语句)。
在 MySQL 客户端执行以下 SQL(已去除可能导致报错的外键约束,确保能跑通):

-- 1. 清理环境
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
-- 2. 建表语句(省略具体字段,请参考 Quartz 官方 SQL)
CREATE TABLE QRTZ_JOB_DETAILS (...) ENGINE=InnoDB;
CREATE TABLE QRTZ_TRIGGERS (...) ENGINE=InnoDB;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (...) ENGINE=InnoDB;
-- ... 其他表 ...
-- 3. 恢复检查
SET FOREIGN_KEY_CHECKS = 1;

执行成功后,重启容器:

docker restart myproject-app

服务成功启动,日志显示Started Application。

五、 常用运维命令

部署完成后,记录几个高频使用的运维命令:

查看实时日志

docker logs -f myproject-app

进入容器内部排查(Alpine 镜像用 sh):

docker exec -it myproject-app sh

复制容器内文件到宿主机

docker cp myproject-app:/app/logs/sys-info.log /home/

六、 总结

Docker 部署 Java 应用虽然简单,但细节决定成败:

  1. 配置文件一定要在打包前检查(数据库 IP、端口)。
  2. 数据库表结构要完整,尤其是像 Quartz 这种需要持久化的框架。
  3. 遇到 MySQL 外键报错时,使用 SET FOREIGN_KEY_CHECKS = 0 往往能通过。

以上就是SpringBoot项目Docker部署全流程详解的详细内容,更多关于SpringBoot Docker部署全流程的资料请关注脚本之家其它相关文章!

相关文章

  • MyBatis-Plus 乐观锁的具体实现

    MyBatis-Plus 乐观锁的具体实现

    MyBatis-Plus 的乐观锁通过简单的配置和注解,可以轻松实现高并发场景下的数据并发控制,具有一定的参考价值,感兴趣的可以了解一下
    2024-09-09
  • Java内存溢出常见原因及解决过程

    Java内存溢出常见原因及解决过程

    Java内存溢出分为堆、Metaspace、栈、直接内存及本地内存,由对象过多、泄漏、递归过深、NIO使用不当等引发,解决方法包括调整参数、优化代码、使用MAT分析,及监控预警,关键在分析与调优结合
    2025-07-07
  • Java中引用类型class的用法总结

    Java中引用类型class的用法总结

    这篇文章主要为大家详细介绍了Java中引用类型class的用法的相关资料,文中的示例代码讲解详细,对我们学习Java有一定帮助,感兴趣的可以了解一下
    2022-10-10
  • Hibernate中load方法与get方法的区别

    Hibernate中load方法与get方法的区别

    Hibernate中有两个极为相似的方法get()与load(),他们都可以通过指定的实体类与ID从数据库中读取数据,并返回对应的实例,但Hibernate不会搞两个完全一样的方法的
    2016-01-01
  • 将本地的jar包打到Maven的仓库中实例

    将本地的jar包打到Maven的仓库中实例

    下面小编就为大家分享一篇将本地的jar包打到Maven的仓库中实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • Spring中的接口重试机制spring-retry之listeners参数解析

    Spring中的接口重试机制spring-retry之listeners参数解析

    这篇文章主要介绍了Spring中的接口重试机制spring-retry之listeners参数解析,注解@Retryable有一个参数listeners没有说明,那么本篇文章我们详细介绍一个这个参数的用,需要的朋友可以参考下
    2024-01-01
  • Java注解中的@Override最佳实践

    Java注解中的@Override最佳实践

    文章介绍了Java中的@Override注解,其核心作用是编译期校验重写方法的正确性,避免伪重写,并提升代码可读性,文章还讨论了@Override的使用场景、常见误区以及其底层实现,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • Activiti开发环境的配置

    Activiti开发环境的配置

    本篇文章主要内容介绍了Activiti开发环境的配置,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • Java--Socket通信(客户端服务端双向)

    Java--Socket通信(客户端服务端双向)

    这篇文章主要介绍了Java--Socket通信(客户端服务端双向),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • SpringCloud Webflux过滤器增加header传递方式

    SpringCloud Webflux过滤器增加header传递方式

    这篇文章主要介绍了SpringCloud Webflux过滤器增加header传递方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02

最新评论