使用Maven将Java项目打包为Docker镜像的实战方法

 更新时间:2026年02月09日 09:50:33   作者:Jinkxs  
本文介绍了两种使用Maven将Java项目打包为Docker镜像的实战方法: Google Jib插件方案:无需Dockerfile,直接通过Maven插件构建镜像,优势包括分层构建、安全高效、镜像体积小,特别适合SpringBoot项目,文章详细展示了使用Maven构建Java项目并生成Docker镜像的完整流程

引言

在云原生时代,容器化(Containerization) 已成为现代应用部署的标准范式。Docker 凭借其轻量、可移植、一致性的优势,彻底改变了软件交付流程。而作为 Java 生态中最主流的构建工具,Maven 如何与 Docker 无缝集成,高效地将 Spring Boot 或普通 Java 应用打包为 Docker 镜像,是每一位 Java 开发者必须掌握的核心技能。

本文将带你从零开始,深入实战 使用 Maven 构建 Java 项目并生成 Docker 镜像的完整流程。我们将覆盖:

  • 传统手动构建镜像的痛点
  • 使用 Jib 插件 实现“零 Dockerfile”构建
  • 使用 Dockerfile + Maven Resources 插件 精细控制镜像内容
  • 多阶段构建(Multi-stage Build)优化镜像大小
  • 镜像标签策略、推送私有仓库、CI/CD 集成
  • 安全最佳实践与性能调优

全文包含大量可运行代码示例、Mermaid 架构图、真实外链资源(均经验证可访问),助你打造生产级 Java 容器化流水线。

为什么需要将 Java 项目容器化?

尽管 Java 应用“一次编写,到处运行”,但在实际部署中仍面临诸多挑战:

  • 环境差异:开发机(macOS)、测试服务器(Ubuntu)、生产集群(CentOS)的 JDK 版本、系统库不一致。
  • 依赖冲突:应用依赖的本地库(如 native lib)在不同机器缺失。
  • 部署复杂:需手动配置 JVM 参数、日志路径、启动脚本。
  • 资源隔离差:多个应用共享同一台服务器,互相影响。

Docker 的价值

  • 环境一致性:镜像包含 OS + JDK + App,彻底消除“在我机器上能跑”问题。
  • 快速部署:docker run 一键启动,无需安装 JDK。
  • 资源隔离:CPU、内存、网络独立分配。
  • 弹性伸缩:配合 Kubernetes 轻松实现水平扩展。

传统方式:手写 Dockerfile + 手动构建

最直观的方式是先用 Maven 打包 JAR,再编写 Dockerfile 构建镜像。

步骤 1:Maven 打包

mvn clean package -DskipTests

生成 target/myapp-1.0.0.jar

步骤 2:编写 Dockerfile

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

# 设置工作目录
WORKDIR /app

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

# 暴露端口(假设应用监听 8080)
EXPOSE 8080

# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]

步骤 3:构建并运行镜像

# 构建镜像
docker build -t myapp:1.0.0 .

# 运行容器
docker run -d -p 8080:8080 --name myapp-container myapp:1.0.0

优点:简单直观,适合学习
缺点

  • 需维护 Dockerfile
  • 构建过程分两步(Maven + Docker),效率低
  • 镜像体积大(含完整 JDK)
  • 无法利用 Maven 生命周期自动化

方案一:使用 Google Jib 插件 —— “零 Dockerfile” 构建 

Jib 是 Google 开源的 Maven/Gradle 插件,专为 Java 应用容器化设计。它无需 Dockerfile、无需本地 Docker daemon,直接从 Maven 构建镜像并推送到仓库。

核心优势

  • 分层构建:将应用拆分为 dependenciessnapshot dependenciesresourcesclasses 多层,仅变更代码时只需上传少量层。
  • 安全:不依赖本地 Docker,避免权限问题。
  • 快速:直接与 Registry 通信,跳过本地镜像存储。
  • 小体积:默认使用 distroless 基础镜像(仅含必要运行时)。

官方 GitHub(持续活跃):https://github.com/GoogleContainerTools/jib

实战:Spring Boot 项目集成 Jib

1. 在pom.xml中添加插件

<build>
    <plugins>
        <plugin>
            <groupId>com.google.cloud.tools</groupId>
            <artifactId>jib-maven-plugin</artifactId>
            <version>3.4.0</version>
            <configuration>
                <!-- 目标镜像名 -->
                <to>
                    <image>myregistry.com/myapp:${project.version}</image>
                </to>
                <!-- 基础镜像(可选) -->
                <from>
                    <image>eclipse-temurin:17-jre-alpine</image>
                </from>
                <!-- 容器配置 -->
                <container>
                    <ports>
                        <port>8080</port>
                    </ports>
                    <environment>
                        <SPRING_PROFILES_ACTIVE>prod</SPRING_PROFILES_ACTIVE>
                    </environment>
                    <creationTime>USE_CURRENT_TIMESTAMP</creationTime>
                </container>
            </configuration>
        </plugin>
    </plugins>
</build>

2. 构建并推送到本地 Docker 守护进程

# 构建镜像并加载到本地 Docker
mvn jib:dockerBuild

# 查看镜像
docker images | grep myapp

3. 推送到远程仓库(如 Docker Hub)

# 先登录
docker login

# 推送(需在 <to> 中配置镜像名,如 yourname/myapp)
mvn jib:build

提示:若使用私有仓库(如 Harbor、Nexus),需配置认证信息(见后文)。

Jib 分层机制 Mermaid 图示

优势体现:当仅修改业务代码时,只有 Classes Layer 变更,推送速度极快!

方案二:Dockerfile + Maven Resources 插件 —— 精细控制

当需要完全掌控镜像内容(如添加 shell 脚本、配置文件、非 Java 资源),可结合 Maven Resources 插件Dockerfile

项目结构设计

myapp/
├── src/
├── pom.xml
├── docker/
│   ├── Dockerfile
│   └── entrypoint.sh
└── target/
    └── myapp-1.0.0.jar

1. 配置 Maven 将资源复制到 target/docker

pom.xml 中添加:

<build>
    <plugins>
        <!-- 复制 Docker 相关文件到 target/docker -->
        <plugin>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.3.1</version>
            <executions>
                <execution>
                    <id>copy-docker-resources</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/docker</outputDirectory>
                        <resources>
                            <resource>
                                <directory>docker</directory>
                                <filtering>false</filtering>
                            </resource>
                        </resources>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <!-- 打包 JAR -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

2. 编写增强版 Dockerfile

docker/Dockerfile:

# 构建阶段:使用 JDK 编译(若需在容器内编译)
# FROM maven:3.8.6-openjdk-17 AS builder
# COPY . /app
# WORKDIR /app
# RUN mvn clean package -DskipTests

# 运行阶段:仅使用 JRE
FROM eclipse-temurin:17-jre-alpine

# 安装必要工具(如 curl、bash)
RUN apk add --no-cache bash curl

# 创建应用用户(安全最佳实践)
RUN addgroup -g 1001 -S appuser && \
    adduser -u 1001 -S appuser -G appuser

# 设置工作目录
WORKDIR /app

# 复制 JAR 和启动脚本
COPY myapp-*.jar app.jar
COPY entrypoint.sh /app/entrypoint.sh

# 赋予执行权限
RUN chmod +x /app/entrypoint.sh

# 切换到非 root 用户
USER appuser

# 暴露端口
EXPOSE 8080

# 启动脚本(可处理信号、设置 JVM 参数等)
ENTRYPOINT ["/app/entrypoint.sh"]

docker/entrypoint.sh:

#!/bin/bash
set -e

# 设置默认 JVM 参数
JVM_OPTS="${JVM_OPTS:-"-Xms256m -Xmx512m"}"

# 处理优雅关闭(接收 SIGTERM)
function shutdown() {
    echo "Shutting down gracefully..."
    kill -TERM "$PID"
    wait "$PID"
    exit 0
}

# 启动 Java 应用
java $JVM_OPTS -jar app.jar &
PID=$!

# 注册信号处理器
trap shutdown SIGTERM SIGINT

# 等待应用结束
wait $PID

3. 构建镜像

# 先执行 Maven 构建(复制资源 + 打包 JAR)
mvn clean package -DskipTests

# 再构建 Docker 镜像
docker build -t myapp:1.0.0 target/docker

适用场景

  • 需要自定义启动逻辑
  • 集成非 Java 组件(如 Python 脚本)
  • 严格的安全合规要求(非 root 用户、最小化 OS)

多阶段构建(Multi-stage Build):极致优化镜像大小

Java 应用镜像常因包含完整 JDK 而臃肿(>500MB)。多阶段构建 可将构建环境与运行环境分离,显著减小体积。

示例:Spring Boot + Multi-stage

# 第一阶段:构建
FROM maven:3.8.6-eclipse-temurin-17 AS builder

# 复制 pom.xml 和源码
COPY pom.xml .
COPY src ./src

# 执行 Maven 构建(缓存依赖)
RUN mvn clean package -DskipTests

# 第二阶段:运行
FROM eclipse-temurin:17-jre-alpine

# 从 builder 阶段复制 JAR
COPY --from=builder /target/*.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

构建效果对比

方式镜像大小是否含 Maven/JDK
单阶段(openjdk:17)~450 MB
多阶段(jre-alpine)~180 MB
Jib(distroless)~120 MB

建议:生产环境优先使用 Jib + distroless多阶段 + alpine

镜像标签策略:语义化版本与 Git Commit ID

合理的镜像标签(Tag)便于追踪和回滚。

推荐策略

场景标签示例说明
发布版本v1.2.0与 Git tag 对应
开发快照dev-abc1234dev- + Git commit short SHA
最新稳定版latest谨慎使用,避免意外升级

在 Maven 中动态生成标签

利用 git-commit-id-plugin 获取 Git 信息:

<plugin>
    <groupId>pl.project13.maven</groupId>
    <artifactId>git-commit-id-plugin</artifactId>
    <version>8.0.2</version>
    <executions>
        <execution>
            <goals>
                <goal>revision</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <verbose>false</verbose>
        <dateFormat>yyyy.MM.dd HH:mm:ss</dateFormat>
        <generateGitPropertiesFile>true</generateGitPropertiesFile>
        <includeOnlyProperties>
            <includeOnlyProperty>^git.commit.id.abbrev$</includeOnlyProperty>
        </includeOnlyProperties>
    </configuration>
</plugin>

然后在 Jib 配置中使用:

<configuration>
    <to>
        <image>myapp:dev-${git.commit.id.abbrev}</image>
    </to>
</configuration>

插件官网:https://github.com/git-commit-id/git-commit-id-maven-plugin

推送镜像到私有仓库:Harbor/Nexus 示例

企业通常使用私有镜像仓库保障安全。

1. 配置 Jib 推送至 Harbor

<configuration>
    <to>
        <image>harbor.example.com/project/myapp:${project.version}</image>
        <auth>
            <username>admin</username>
            <password>Harbor12345</password>
        </auth>
    </to>
</configuration>

安全提示:密码不应硬编码!应使用 Maven Settings 或 CI/CD Secrets。

2. 使用 Maven Settings 管理凭证

~/.m2/settings.xml:

<settings>
    <servers>
        <server>
            <id>harbor-registry</id>
            <username>admin</username>
            <password>Harbor12345</password>
        </server>
    </servers>
</settings>

pom.xml 中引用:

<configuration>
    <to>
        <image>harbor.example.com/project/myapp</image>
        <auth>
            <username>${settings.servers.harbor-registry.username}</username>
            <password>${settings.servers.harbor-registry.password}</password>
        </auth>
    </to>
</configuration>

3. CI/CD 中使用 Secrets(GitHub Actions 示例)

- name: Build and Push with Jib
  run: mvn jib:build
  env:
    JIB_REGISTRY_USERNAME: ${{ secrets.HARBOR_USER }}
    JIB_REGISTRY_PASSWORD: ${{ secrets.HARBOR_TOKEN }}

GitHub Secrets 文档:https://docs.github.com/en/actions/security-guides/encrypted-secrets

安全最佳实践:扫描漏洞与最小化攻击面

容器镜像可能包含已知漏洞(CVE),需主动防御。

1. 使用 Trivy 扫描镜像

Trivy 是开源漏洞扫描器。

# 安装 Trivy(macOS)
brew install aquasecurity/trivy/trivy

# 扫描本地镜像
trivy image myapp:1.0.0

输出示例:

myapp:1.0.0 (alpine 3.17.2)
============================
Total: 2 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

2. 在 CI 中集成扫描

- name: Scan Docker image
  run: |
    docker build -t myapp:latest .
    trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest

Trivy 官网(活跃维护):https://aquasecurity.github.io/trivy/

3. 其他安全建议

  • 使用非 root 用户运行(见前文 Dockerfile)
  • 禁用 Shell:distroless 镜像默认无 shell,防止入侵后执行命令
  • 定期更新基础镜像:订阅安全公告,及时 rebuild

性能调优:JVM 与容器资源匹配

容器环境中的 JVM 需正确识别 CPU/内存限制。

问题:JVM 忽略 Docker 内存限制

旧版 JVM(<8u131, <9)无法感知 -m 512m 等 Docker 内存限制,导致 OOM。

解决方案

1. 使用新版 JDK(推荐)

JDK 10+ 默认启用 Container Awareness,JDK 8u191+ 需手动开启:

ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-jar", "app.jar"]

2. 显式设置堆内存

# 通过环境变量控制
ENV JAVA_OPTS="-Xmx300m -Xms300m"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

3. 使用 Jib 自动配置

Jib 默认添加 -XX:+UseContainerSupport,无需额外配置。

Oracle 官方文档:JDK 8 Updates for Docker

CI/CD 集成:GitHub Actions 完整流水线

下面是一个完整的 GitHub Actions Workflow,实现 代码提交 → 构建 → 扫描 → 推送

name: Build and Push Docker Image

on:
  push:
    branches: [ main ]
    tags: [ 'v*' ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Cache Maven packages
        uses: actions/cache@v3
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}

      - name: Build with Maven
        run: mvn -B clean verify

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Extract metadata (tags, labels)
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: myname/myapp
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=sha

      - name: Build and push with Jib
        run: mvn jib:build -Djib.to.image=${{ steps.meta.outputs.tags }}

      - name: Scan image with Trivy
        run: |
          docker pull ${{ steps.meta.outputs.tags }}
          trivy image --exit-code 1 --severity HIGH,CRITICAL ${{ steps.meta.outputs.tags }}

流程说明

  1. 拉取代码
  2. 设置 JDK + 缓存 Maven 依赖
  3. 执行单元测试
  4. 登录 Docker Hub
  5. 自动生成语义化标签
  6. 使用 Jib 构建并推送
  7. 安全扫描,高危漏洞阻断发布

常见问题排查指南

问题 1:Jib 构建失败,提示“Cannot connect to the Docker daemon”

原因:使用了 jib:build(需推送远程仓库),但未配置 registry 认证。

解决

  • 改用 jib:dockerBuild(仅构建到本地)
  • 或正确配置 <to><auth> 或 Maven Settings

问题 2:容器启动后立即退出

原因:ENTRYPOINT 命令执行完毕,容器生命周期结束。

解决

  • 确保 Java 进程在前台运行(不要加 &
  • 检查应用是否抛出异常(docker logs container_name

问题 3:镜像太大,超过 500MB

解决

  • 改用 eclipse-temurin:17-jre-alpine 或 Jib 的 distroless
  • 使用多阶段构建
  • 排查是否误将 src/target/ 全量复制

问题 4:时区不正确

解决:在 Dockerfile 中设置时区

ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

方案对比:Jib vs Dockerfile + Maven 🆚

特性JibDockerfile + Maven
是否需要 Dockerfile❌ 否✅ 是
是否需要本地 Docker❌ 否(jib:build
✅ 是(jib:dockerBuild
✅ 是
镜像分层优化✅ 自动分层⚠️ 需手动设计
构建速度⚡ 极快(仅传变更层)🐢 较慢(全量构建)
控制粒度中(插件配置)✅ 极高(任意命令)
学习成本
适用场景标准 Java 应用复杂定制需求

结论

  • 90% 场景用 Jib:快速、安全、高效
  • 10% 场景用 Dockerfile:需深度定制(如集成 sidecar、特殊 init 流程)

结语:拥抱云原生,从容器化开始

将 Java 应用容器化不再是“可选项”,而是现代软件工程的“必修课”。Maven 与 Docker 的结合,为我们提供了从构建到部署的端到端解决方案。无论是使用 Jib 的便捷性,还是 Dockerfile 的灵活性,核心目标都是:交付一致、安全、高效的容器镜像

记住:好的容器化不是终点,而是云原生旅程的起点。下一步,你可以探索:

  • 使用 Helm 管理 Kubernetes 部署
  • 集成 Prometheus + Grafana 监控
  • 实现蓝绿发布/金丝雀发布

以上就是使用Maven将Java项目打包为Docker镜像的实战方法的详细内容,更多关于Maven将Java打包为Docker镜像的资料请关注脚本之家其它相关文章!

相关文章

  • Async的线程池使用选择解析

    Async的线程池使用选择解析

    这篇文章主要为大家介绍了Async的线程池使用选择解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-06-06
  • SpringBoot中实时监控Redis命令流的实现

    SpringBoot中实时监控Redis命令流的实现

    在Redis的日常使用和调试中,监控命令流有助于我们更好地理解 Redis的工作状态,Redis提供了MONITOR命令,可以实时输出Redis中所有客户端的命令请求,本文将介绍如何使用Jedis实现这一功能,并对比telnet实现MONITOR机制的工作方式,需要的朋友可以参考下
    2024-11-11
  • Java开发必备的三大修饰符

    Java开发必备的三大修饰符

    JAVA的三个修饰:static,final,abstract,在JAVA语言里无处不在,但是它们都能修饰什么组件,修饰组件的含义又有什么限制,总是混淆.所以来总结一下,需要的朋友可以参考下
    2021-06-06
  • JavaWeb开发使用Cookie创建-获取-持久化、自动登录、购物记录、作用路径

    JavaWeb开发使用Cookie创建-获取-持久化、自动登录、购物记录、作用路径

    这篇文章主要介绍了JavaWeb开发使用Cookie创建-获取-持久化、自动登录、购物记录、作用路径的相关知识,非常不错,对cookie持久化知识感兴趣的朋友一起学习吧
    2016-08-08
  • Springboot @Value注入boolean设置默认值方式

    Springboot @Value注入boolean设置默认值方式

    这篇文章主要介绍了Springboot @Value注入boolean设置默认值方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Gradle构建基本的Web项目结构

    Gradle构建基本的Web项目结构

    这篇文章主要为大家介绍了Gradle创建Web项目基本的框架结构搭建,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • servlet3文件上传操作

    servlet3文件上传操作

    这篇文章主要介绍了servlet3文件上传操作的相关资料,需要的朋友可以参考下
    2017-11-11
  • springboot内嵌Tomcat安全漏洞修复方式

    springboot内嵌Tomcat安全漏洞修复方式

    针对CVE-2020-1938漏洞,建议升级Tomcat至安全版本以避免受影响,影响版本包括:Apache Tomcat 9.x小于9.0.31、Apache Tomcat 8.x小于8.5.51、Apache Tomcat 7.x小于7.0.100及Apache Tomcat 6.x,
    2024-10-10
  • springboot2.x整合shiro权限框架的使用

    springboot2.x整合shiro权限框架的使用

    这篇文章主要介绍了springboot2.x整合shiro权限框架的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java CPU性能分析工具代码实例

    Java CPU性能分析工具代码实例

    这篇文章主要介绍了Java CPU性能分析工具代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01

最新评论