Java项目打包Docker镜像全流程

 更新时间:2025年04月10日 09:58:45   作者:魔道不误砍柴功  
本文是一份超详细的Java项目Docker化实战手册,从环境准备到最终上线,手把手带你完成整个容器化部署流程,无论你是刚接触Docker的新手,还是想系统梳理容器化流程的开发者,这篇文章都能给你带来实实在在的帮助,需要的朋友可以参考下

环境准备

1. 开发环境要求

  • JDK 8+ (推荐JDK 11/17 LTS版本)
  • Maven 3.6+ 或 Gradle 7+
  • Docker Desktop (Mac/Windows) 或 Docker Engine (Linux)
  • 推荐IDE: IntelliJ IDEA (社区版即可)

2. 安装Docker

不同操作系统的安装方式:

Linux (Ubuntu为例):

# 卸载旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc

# 安装依赖
sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 添加Docker官方GPG密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 设置稳定版仓库
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装Docker引擎
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# 验证安装
sudo docker run hello-world

Mac/Windows:直接下载Docker Desktop安装包:
https://www.docker.com/products/docker-desktop

3. 验证安装

docker --version
# 输出类似: Docker version 20.10.12, build e91ed57

docker-compose --version
# 输出类似: docker-compose version 1.29.2, build 5becea4c

项目结构说明

我们以一个典型的Spring Boot项目为例:

my-java-app/
├── src/
│   ├── main/
│   │   ├── java/com/example/demo/
│   │   │   ├── DemoApplication.java
│   │   │   └── controllers/
│   │   └── resources/
│   │       ├── application.properties
│   │       └── static/
│   └── test/
├── target/
│   ├── my-java-app-0.0.1-SNAPSHOT.jar
│   └── ...
├── pom.xml
└── Dockerfile

Docker基础概念

在开始之前,先了解几个核心概念:

  • 镜像(Image): 只读模板,包含运行应用所需的所有内容
  • 容器(Container): 镜像的运行实例
  • Dockerfile: 构建镜像的指令文件
  • Registry: 镜像仓库(如Docker Hub)

Docker的优势:

  • 一致的运行环境
  • 快速部署和扩展
  • 资源隔离
  • 易于版本管理和回滚

编写Dockerfile

基础Dockerfile示例

# 第一阶段:构建
FROM maven:3.8.4-openjdk-11 AS build
WORKDIR /app
COPY pom.xml .
# 利用缓存下载依赖
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests

# 第二阶段:运行
FROM openjdk:11-jre-slim
WORKDIR /app
# 从构建阶段复制jar包
COPY --from=build /app/target/my-java-app-*.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]

逐行解析

  1. FROM maven:3.8.4-openjdk-11 AS build
    使用Maven镜像作为构建阶段的基础镜像,并命名为"build"

  2. WORKDIR /app
    设置工作目录为/app

  3. COPY pom.xml .
    复制pom.xml到工作目录

  4. RUN mvn dependency:go-offline
    下载所有依赖项(利用Docker缓存层)

  5. COPY src ./src
    复制源代码

  6. RUN mvn package -DskipTests
    打包应用(跳过测试)

  7. FROM openjdk:11-jre-slim
    第二阶段使用更小的JRE镜像

  8. COPY --from=build /app/target/my-java-app-*.jar app.jar
    从构建阶段复制生成的jar包

  9. EXPOSE 8080
    声明容器暴露的端口

  10. ENTRYPOINT ["java", "-jar", "app.jar"]
    容器启动时执行的命令

多阶段构建优化

多阶段构建有三大优势:

  1. 减小镜像体积 - 最终镜像只包含运行时必要内容
  2. 提高安全性 - 构建工具不会出现在生产镜像中
  3. 更清晰的构建流程 - 分离构建和运行环境

进阶优化技巧

  1. 使用.dockerignore文件
    避免将不必要的文件复制到镜像中:

.git
.idea
*.iml
target/
*.log
*.tmp
  1. 选择合适的基础镜像

    • openjdk:11-jdk - 完整JDK(较大)
    • openjdk:11-jre - 仅运行时(较小)
    • openjdk:11-jre-slim - 更精简版本
    • openjdk:11-alpine - 基于Alpine Linux(最小)
  2. 层缓存优化
    将不常变化的指令放在前面,充分利用缓存:

# 先复制pom.xml并下载依赖
COPY pom.xml .
RUN mvn dependency:go-offline

# 然后复制源代码
COPY src ./src

构建与运行镜像

1. 构建镜像

# -t 指定镜像名称和标签
# . 表示使用当前目录的Dockerfile
docker build -t my-java-app:1.0 .

构建过程输出示例:

[+] Building 45.3s (12/12) FINISHED
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 37B                                        0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 35B                                           0.0s
 => [internal] load metadata for docker.io/library/openjdk:11-jre-slim    1.5s
 => [internal] load metadata for docker.io/library/maven:3.8.4-openjdk-11  1.5s
 => [build 1/5] FROM docker.io/library/maven:3.8.4-openjdk-11@sha256:9c... 0.0s
 => [internal] load build context                                          0.1s
 => => transferring context: 3.01kB                                        0.0s
 => CACHED [build 2/5] WORKDIR /app                                        0.0s
 => [build 3/5] COPY pom.xml .                                             0.0s
 => [build 4/5] RUN mvn dependency:go-offline                              20.1s
 => [build 5/5] COPY src ./src                                             0.0s
 => [build 6/5] RUN mvn package -DskipTests                               18.2s
 => [stage-1 1/2] FROM docker.io/library/openjdk:11-jre-slim@sha256:9c... 0.0s
 => [stage-1 2/2] COPY --from=build /app/target/my-java-app-*.jar app.jar  0.1s
 => exporting to image                                                     0.1s
 => => exporting layers                                                    0.1s
 => => writing image sha256:7e9b6e5ba...                                   0.0s
 => => naming to docker.io/library/my-java-app:1.0                         0.0s

2. 查看镜像

docker images

# 输出示例
REPOSITORY     TAG       IMAGE ID       CREATED         SIZE
my-java-app    1.0       7e9b6e5ba123   2 minutes ago   215MB

3. 运行容器

# -d 后台运行
# -p 端口映射(主机端口:容器端口)
# --name 容器名称
docker run -d -p 8080:8080 --name my-app my-java-app:1.0

4. 查看运行状态

docker ps

# 输出示例
CONTAINER ID   IMAGE             COMMAND               CREATED         STATUS         PORTS                    NAMES
a3b8d7e6f5g4   my-java-app:1.0   "java -jar app.jar"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp   my-app

5. 查看日志

docker logs -f my-app

# 输出示例
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.6.3)

6. 停止和删除容器

# 停止容器
docker stop my-app

# 删除容器
docker rm my-app

# 删除镜像
docker rmi my-java-app:1.0

推送镜像到仓库

1. 登录Docker Hub

docker login -u your-username

2. 标记镜像

# 格式: docker tag local-image:tagname username/repository:tagname
docker tag my-java-app:1.0 your-username/my-java-app:1.0

3. 推送镜像

docker push your-username/my-java-app:1.0

4. 从仓库拉取运行

docker run -d -p 8080:8080 your-username/my-java-app:1.0

生产环境部署

1. 使用docker-compose

创建docker-compose.yml文件:

version: '3.8'

services:
  app:
    image: your-username/my-java-app:1.0
    container_name: my-java-app
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    restart: unless-stopped
    volumes:
      - ./logs:/app/logs
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 10s
      retries: 3

启动服务:

docker-compose up -d

2. Kubernetes部署示例

创建deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: java-app
  template:
    metadata:
      labels:
        app: java-app
    spec:
      containers:
      - name: java-app
        image: your-username/my-java-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "1024Mi"
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 5

总结与最佳实践

最佳实践总结

  1. 镜像优化

    • 使用多阶段构建减小镜像体积
    • 选择合适的基础镜像(Alpine/slim版本)
    • 定期更新基础镜像以获取安全补丁
  2. 构建优化

    • 合理利用层缓存(.dockerignore + 指令顺序)
    • 固定基础镜像版本(避免使用latest标签)
    • 在CI/CD中实现自动化构建
  3. 运行优化

    • 限制容器资源(cpu/memory)
    • 配置健康检查
    • 使用非root用户运行
    • 正确处理信号(如SIGTERM)
  4. 安全建议

    • 不要将敏感信息硬编码在镜像中(使用环境变量/secret)
    • 扫描镜像中的漏洞(使用docker scan)
    • 最小化容器权限(避免–privileged)

常见问题解决

Q: 构建时下载依赖很慢怎么办?
A: 配置Maven镜像仓库:

RUN mkdir -p /root/.m2 && \
    echo 'aliyunhttps://maven.aliyun.com/repository/publiccentral' > /root/.m2/settings.xml

Q: 容器启动后立即退出?
A: 可能原因:

  1. 应用启动失败 - 查看日志docker logs
  2. 没有前台进程 - 确保应用不是以daemon方式运行
  3. 端口冲突 - 检查端口映射

Q: 如何调试容器内的应用?
A: 进入运行中的容器:

docker exec -it  /bin/bash

或者直接附加到进程:

docker attach 

下一步学习建议

  1. 学习Docker网络和存储卷配置
  2. 掌握Docker Compose编排多容器应用
  3. 了解Kubernetes容器编排
  4. 探索CI/CD流水线与Docker集成
  5. 学习服务网格(如Istio)与容器化应用

通过本文的学习,你已经掌握了Java项目容器化的核心技能。Docker的世界还有很多值得探索的地方,继续实践,你将发现更多容器化带来的便利与效率提升!

以上就是Java项目打包Docker镜像全流程的详细内容,更多关于Java打包Docker镜像的资料请关注脚本之家其它相关文章!

相关文章

  • 浅谈java switch如果case后面没有break,会出现什么情况?

    浅谈java switch如果case后面没有break,会出现什么情况?

    这篇文章主要介绍了浅谈java switch如果case后面没有break,会出现什么情况?具有很好的参考价值,希望对大家有所帮助。一起跟随想小编过来看看吧
    2020-09-09
  • 使用arthas命令redefine实现Java热更新(推荐)

    使用arthas命令redefine实现Java热更新(推荐)

    今天分享一个非常重要的命令 redefine ,主要作用是加载外部的 .class 文件,用来替换 JVM 已经加载的类,总结起来就是实现了 Java 的热更新,感兴趣的朋友跟随小编一起看看吧
    2020-05-05
  • async-excel实现多sheet异步导出方法详解

    async-excel实现多sheet异步导出方法详解

    这篇文章主要介绍了async-excel实现多sheet异步导出方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-12-12
  • MyBatis实现万能Map和模糊查询

    MyBatis实现万能Map和模糊查询

    本文主要介绍了MyBatis实现万能Map和模糊查询,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • JMS 之 Active MQ 的消息传输(详解)

    JMS 之 Active MQ 的消息传输(详解)

    下面小编就为大家带来一篇JMS 之 Active MQ 的消息传输(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 浅谈Java循环中的For和For-each哪个更快

    浅谈Java循环中的For和For-each哪个更快

    本文主要介绍了浅谈Java循环中的For和For-each哪个更快,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Java实现整合文件上传到FastDFS的方法详细

    Java实现整合文件上传到FastDFS的方法详细

    FastDFS是一个开源的轻量级分布式文件系统,对文件进行管理,功能包括:文件存储、文件同步、文件上传、文件下载等,解决了大容量存储和负载均衡的问题。本文将提供Java将文件上传至FastDFS的示例代码,需要的参考一下
    2022-02-02
  • Java如何把int类型转换成byte

    Java如何把int类型转换成byte

    这篇文章主要介绍了Java如何把int类型转换成byte,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Mysql中备份表的多种方法

    Mysql中备份表的多种方法

    本文给大家分享Mysql中备份表的四种方法,第一种方式是小表的备份,第二种是对整个数据库的备份与恢复,第三种是对某个数据表进行备份,每种方式给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2022-11-11
  • Mybatis日期格式自动转换需要用到的两个注解说明

    Mybatis日期格式自动转换需要用到的两个注解说明

    这篇文章主要介绍了Mybatis日期格式自动转换需要用到的两个注解说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论