Docker与Java:应用容器化完全指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

Docker 与 Java 入门:容器化为何改变开发模式

现代软件开发离不开容器化技术。Docker 已成为打包、交付和运行应用程序的事实标准。对于 Java 开发者而言,使用 Docker 解决了两个关键问题:"在我机器上能运行" 和环境配置的复杂性。本文将详细拆解如何将 Java 应用容器化,从简单的 JAR 文件到基于 Spring Boot 的复杂微服务。

Docker 允许将应用程序及其依赖项(JVM、库、系统工具)隔离在轻量级可移植容器中。这对 Java 尤为重要,因为 JDK 版本、内存设置和系统库会显著影响程序行为。

您将从本文中学到

  • 为 Java 应用创建 Dockerfile
  • 优化镜像体积
  • 处理多模块 Maven/Gradle 项目
  • 安全性和性能的最佳实践

1. 基础篇:为 Java 应用创建 Dockerfile

我们从简单示例开始。假设您有一个打包成 JAR 文件的 Java 应用程序。以下是将它打包到容器中的最小 Dockerfile:

# 使用官方 OpenJDK 镜像
FROM openjdk:17-jdk-slim

# 设置工作目录
WORKDIR /app

# 将 JAR 文件复制到容器中
COPY target/myapp.jar app.jar

# 暴露应用程序监听的端口
EXPOSE 8080

# 运行命令
ENTRYPOINT ["java", "-jar", "app.jar"]

这个 Dockerfile 做了三件简单的事:使用 JDK 17 的基础镜像,复制编译好的 JAR,然后运行它。但在实际项目中,这种方法效率低下——每次代码变更时,Docker 都会重建整个镜像,包括重新复制 JAR。

多阶段构建

为了分离构建和执行阶段,请使用多阶段 Dockerfile。这通过排除构建工具(Maven、Gradle、编译用的 JDK)来减小最终镜像体积。

# 构建阶段
FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn clean package -DskipTests

# 最终阶段
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

第一阶段使用完整的 Maven 镜像进行编译,第二阶段使用最小的 JRE 镜像来运行。最终镜像体积约为 200 MB,而不是 700+ MB。

2. 镜像优化:减小体积并加速构建

大型镜像会拖慢部署速度并增加加载时间。以下是一些针对 Java 的技术:

使用 JLink 创建最小 JRE

从 Java 9 开始,您可以创建仅包含必要模块的自定义 JRE。这能大幅减小镜像体积。

FROM openjdk:17-jdk-slim AS jre-builder
RUN jlink \
    --add-modules java.base,java.logging,java.sql \
    --strip-debug \
    --no-man-pages \
    --no-header-files \
    --compress=2 \
    --output /jre

FROM debian:bookworm-slim
COPY --from=jre-builder /jre /jre
WORKDIR /app
COPY target/myapp.jar app.jar
ENV PATH="/jre/bin:${PATH}"
ENTRYPOINT ["java", "-jar", "app.jar"]

这样的镜像重量可能只有 40-60 MB,而不是 200+ MB。

Docker 层缓存

Docker 会缓存每一层。为了加速构建,请将不常更改的文件(依赖项)放在 Dockerfile 的开头,将频繁更改的文件(源代码)放在结尾。

FROM maven:3.9.6-eclipse-temurin-17 AS builder
WORKDIR /build
# 首先,只复制 pom.xml 并下载依赖项
COPY pom.xml .
RUN mvn dependency:go-offline
# 然后复制源代码并构建
COPY src ./src
RUN mvn clean packag                

博客

书籍推荐