Windows 下将 Java 项目打包为 Docker 容器并部署的完整指南

在微服务和云原生架构日益普及的今天,Docker 已成为 Java 应用部署的事实标准。然而,许多开发者在 Windows 环境下尝试将 Spring Boot 等 Java 项目打包成 Docker 镜像时,常会遇到权限、路径或脚本兼容性问题------例如经典的错误:

bash 复制代码
/bin/sh: 1: touch: not found
or
exec: "sh": executable file not found in $PATH

甚至在 Dockerfile 中执行 RUN sh -c 'touch /app.jar' 时失败。本文将手把手教你如何在 Windows 系统下正确构建 Java 项目的 Docker 镜像,并成功部署运行,避开常见陷阱。


一、准备工作

1. 安装必要工具

  • JDK 8/11/17+ :用于编译 Java 项目
  • Maven 或 Gradle:构建工具(本文以 Maven 为例)
  • Docker Desktop for Windows:确保已启用 WSL2 后端(推荐)
  • IDE(如 IntelliJ IDEA 或 VS Code)

✅ 建议:使用 WSL2(Windows Subsystem for Linux)可极大减少跨平台兼容问题。

2. 构建可执行 JAR 包

以 Spring Boot 项目为例,在项目根目录执行:

go 复制代码
mvn clean package -DskipTests

生成的 JAR 文件通常位于 target/your-app.jar


二、编写正确的 Dockerfile

关键点:避免在非 Linux 环境下使用不兼容的 shell 命令,并选择合适的 base 镜像。

bash 复制代码
# 使用官方 OpenJDK 镜像(Alpine 更小,但注意 glibc 兼容性)
FROM openjdk:17-jdk-slim

# 设置工作目录
WORKDIR /app

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

# 【关键】解决"touch"问题:仅在需要修改时间戳时才使用
# 实际上,现代 Spring Boot 应用通常不需要 touch
# 若你看到旧教程中的 RUN touch /app.jar,可直接删除!

# 暴露端口(根据应用配置调整)
EXPOSE 8080

# 启动应用
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

⚠️ 注意:

  • 不要写 RUN sh -c 'touch /app.jar' ------ 这是早期为解决 Spring Boot 在某些只读文件系统中启动失败而引入的 hack,在现代 Docker 和 Spring Boot 版本中已不再需要
  • 如果你坚持使用 Alpine 镜像(openjdk:17-alpine),请确保你的应用不依赖 glibc(Alpine 使用 musl libc),否则可能报错。

三、在 Windows 下构建镜像

打开 PowerShell 或 CMD(建议在项目根目录操作):

perl 复制代码
# 构建镜像(注意末尾的 . 表示上下文路径)
docker build -t my-java-app:1.0 .

# 查看镜像是否创建成功
docker images

🔍 常见问题排查:

  • 文件路径错误 :确保 COPY target/*.jar app.jar 中的 target 目录存在且包含 JAR。
  • 换行符问题(CRLF vs LF) :若使用 Git Bash 或 WSL,确保 Dockerfile 为 Unix 换行(LF)。可在 VS Code 右下角切换。
  • 权限问题:Windows 一般不会出现,但在 WSL 中需确保文件可读。

四、运行容器

css 复制代码
docker run -d --name my-app -p 8080:8080 my-java-app:1.0
  • -d:后台运行
  • -p 8080:8080:将宿主机 8080 端口映射到容器 8080 端口

查看日志验证是否启动成功:

perl 复制代码
docker logs -f my-app

五、优化建议(进阶)

1. 多阶段构建(减小镜像体积)

bash 复制代码
# 构建阶段
FROM maven:3.8-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
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"]

2. 使用 .dockerignore

避免将 target/ 以外的临时文件(如 .git, *.log)复制进镜像:

bash 复制代码
.git
*.log
README.md
Dockerfile
.dockerignore

3. 健康检查(可选)

bash 复制代码
HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1

六、关于 "RUN touch /app.jar" 的真相

该命令最早出现在 Spring Boot 官方早期文档中,目的是确保 JAR 文件的时间戳不是未来时间(某些构建环境如 CI/CD 可能导致时间异常),从而避免 Spring Boot 启动时因"非法时间"拒绝加载。

但在以下情况下完全不需要

  • 本地正常构建(mvn package
  • 使用现代 JDK 和 Spring Boot(2.3+)
  • 容器文件系统可写(默认情况)

因此,除非你明确遇到时间戳相关错误,否则应删除该行,避免引入不必要的复杂性。


结语

在 Windows 下打包 Java 项目为 Docker 容器并非难事,关键在于理解 Docker 构建上下文、选择合适的 base 镜像,并摒弃过时的"经验代码"。通过本文的步骤,你可以快速、可靠地将 Spring Boot 应用容器化,并为后续部署到 Kubernetes 或云平台打下基础。

💡 最后提醒:开发环境尽量贴近生产环境。若生产使用 Linux,建议在 WSL2 或 Linux 虚拟机中测试 Docker 镜像,以提前暴露兼容性问题。

相关推荐
掘金者阿豪43 分钟前
搭了一个白噪音服务,才意识到之前那些“助眠APP”有多浪费钱
后端
码事漫谈1 小时前
OpenSpec实战:AI编程告别“瞎写”
后端
DyLatte1 小时前
我做了个AI项目后才发现:会做事的人,正在输给会讲故事的人
前端·后端·程序员
deviant-ART2 小时前
java stream 的 findFirst 和 findAny 踩坑点
java·开发语言·后端
神奇小汤圆2 小时前
MySQL / MariaDB 主从复制架构实战指南
后端
用户6757049885022 小时前
【AI开发实战】从想法到上线,我用AI全栈开发了一款记账微信小程序
后端·aigc·ai编程
Moment2 小时前
作为前端,如果使用 Langgraph 实现第一个 Agent
前端·javascript·后端
神奇小汤圆2 小时前
高并发接口总被打崩?我用 ArrayBlockingQueue + 底层源码深度剖析搞定流控
后端
木易 士心2 小时前
MyBatis Plus 核心功能与用法
java·后端·mybatis
Victor3562 小时前
MongoDB(93)如何使用变更流跟踪数据变化?
后端