引言:为什么 Docker 对 Java 开发者很重要?
现代 Java 开发很少能离开容器化。Docker 允许将应用程序及其所有依赖项、JVM 和配置打包到一个隔离的容器中。这解决了“在我机器上能运行”的问题,并简化了 CI/CD。在本文中,我们将分析完整的流程:从安装 Docker 到优化生产环境镜像。
1. Java 的 Docker 基础
1.1 什么是 Docker,为什么 Java 项目需要它?
Docker 是一个用于在容器中创建、交付和运行应用程序的平台。对于 Java 来说,这尤其重要:
- JVM 版本隔离 — 可以在同一主机上为一个服务使用 Java 11,为另一个服务使用 Java 17。
- 可重现性 — 镜像包含精确版本的 JDK、库和系统工具。
- 可扩展性 — 通过 Kubernetes 或 Docker Swarm 轻松运行多个实例。
1.2 安装 Docker
首先,安装 Docker Desktop(Windows/Mac)或 Docker Engine(Linux)。验证安装:
docker --versiondocker info2. 为 Java 应用程序创建 Dockerfile
考虑一个简单的 Spring Boot 应用程序。在项目根目录下创建一个 Dockerfile 文件。
2.1 基础 Dockerfile
# 使用官方 OpenJDK 镜像FROM openjdk:17-jdk-alpine
# 设置工作目录WORKDIR /app
# 复制 JAR 文件COPY target/myapp.jar app.jar
# 开放端口EXPOSE 8080
# 启动命令ENTRYPOINT ["java", "-jar", "app.jar"]2.2 构建并运行容器
# 构建镜像docker build -t my-java-app .
# 运行容器docker run -p 8080:8080 my-java-app运行后,应用程序可通过 http://localhost:8080 访问。
3. 优化 Java 的 Docker 镜像
大型镜像会减慢部署速度。让我们探讨关键优化技术。
3.1 多阶段构建
允许将构建阶段与运行阶段分开。最终镜像中只包含 JAR,不包含 Maven/Gradle 和源代码。
# 构建阶段FROM maven:3.8.5-openjdk-17 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests
# 运行阶段FROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/myapp.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]3.2 层优化
Docker 会缓存层。将数据复制分开:先复制依赖项(很少更改),再复制代码(经常更改)。
FROM maven:3.8.5-openjdk-17 AS buildWORKDIR /app# 仅复制 POM 并下载依赖项COPY pom.xml .RUN mvn dependency:go-offline# 复制源代码并构建COPY src ./srcRUN mvn package -DskipTests
FROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]3.3 使用 jlink 创建最小 JRE
如果您使用 Java 9+,可以创建仅包含所需模块的自定义 JRE。
FROM openjdk:17-slim AS jre-buildRUN jlink --add-modules java.base,java.logging,java.sql \ --output /jre \ --strip-debug \ --no-man-pages \ --no-header-files
FROM alpine:latestCOPY --from=jre-build /jre /jreCOPY target/app.jar /app.jarENTRYPOINT ["/jre/bin/java", "-jar", "/app.jar"]这样的镜像可能小于 50 MB,而不是 300+ MB。
4. 用于 Java 微服务的 Docker Compose
如果您有多个服务(例如 Spring Boot + PostgreSQL),请使用 docker-compose.yml。