优先选 eclipse-temurin(如 eclipse-temurin:17-jre-jammy),因其轻量、定期更新CVE、支持ARM64;避免已弃用的 java:8 或体积大且无多阶段构建支持的 openjdk 官方镜像。

Java应用打包成Docker镜像时,Dockerfile里该用哪个JDK基础镜像
优先选 eclipse-temurin(原 adoptopenjdk),不是 openjdk 官方镜像,也不是 java:8-jdk 这类已弃用的旧标签。后者在 Docker Hub 上已标记为 deprecated,且不更新安全补丁。
常见错误是直接写 FROM openjdk:17-jdk-slim —— 它虽能跑,但镜像体积大、无多阶段构建支持、底层 OS 包管理混乱。而 eclipse-temurin:17-jre-jammy 更轻量、定期扫描 CVE、支持 ARM64。
-
eclipse-temurin:17-jre-jammy:适合 Spring Boot 打包成jar后直接运行,体积约 120MB -
eclipse-temurin:17-jdk-jammy:需要编译或调试时才用,比如集成 Jacoco 或运行javac - 避免
FROM java:8:该镜像基于 Debian Jessie,2020 年已 EOL,存在已知 SSL/TLS 握手失败问题
Spring Boot应用构建Docker镜像时,为什么java -jar启动失败报ClassNotFoundException
根本原因不是类没打进 jar,而是 Docker 构建时用了错误的 COPY 路径,或者没跳过 Maven 的 test 阶段导致 fat jar 没生成。
典型错误:COPY target/*.jar app.jar 在多模块项目中会匹配到空目录或 pom.xml 生成的非可执行 jar;正确做法是明确指定构建产物名。
立即学习“Java免费学习笔记(深入)”;
- 确保
mvn clean package -DskipTests成功执行,检查target/your-app-0.0.1-SNAPSHOT.jar是否存在且可执行(java -jar能打印 help) -
Dockerfile中用精确路径:COPY target/your-app-*.jar app.jar,别依赖通配符匹配 - 若用 Spring Boot 3+,需确认 jar 内
META-INF/MANIFEST.MF含Start-Class和Spring-Boot-Classes,否则java -jar不识别为 Boot 应用
容器内Java进程无法被docker stop优雅终止,怎么修复
因为 Java 进程没收到 SIGTERM,或收到后未注册 shutdown hook,导致 docker stop 等 10 秒后强制发 SIGKILL,数据库连接、线程池、Actuator 的 /actuator/shutdown 全部失效。
关键点:必须让 JVM 成为 PID 1,且不被 shell 封装。错误写法:ENTRYPOINT ["sh", "-c", "java -jar app.jar"] —— 此时 sh 是 PID 1,Java 是子进程,SIGTERM 只发给 sh,不会透传。
- 正确写法:
ENTRYPOINT ["java", "-jar", "/app.jar"](exec form) - 加 JVM 参数确保信号处理:
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0,避免 OOMKilled - Spring Boot 项目中显式注册 hook:
Runtime.getRuntime().addShutdownHook(new Thread(() -> { logger.info("Shutting down gracefully..."); }));
本地开发时用docker-compose连MySQL,Java应用总是连不上host.docker.internal
这个 DNS 名在 macOS / Windows 的 Docker Desktop 默认可用,但在 Linux 上默认不存在,直接导致 Connection refused。不能靠改 /etc/hosts 硬编码 IP,因为容器网络每次重启可能变。
根本解法是让 Java 应用和 MySQL 同属一个自定义网络,并用服务名通信 —— 这才是 Docker 原生推荐方式,不是 hack。
- 删掉所有
host.docker.internal引用,把 JDBC URL 改成jdbc:mysql://mysql:3306/mydb -
docker-compose.yml中定义mysql服务,并与应用服务同级,不加network_mode: host - 验证方法:
docker-compose exec app ping mysql,能通说明网络就绪
Connection refused、FileNotFoundException、OutOfMemoryError,但容器本身明明显示 running。










