Docker 打包部署 Java 程序全流程(含 Spring Boot 示例)

一、前置條件

  1. 環境準備:
  • 安裝 Docker(Windows/Mac 用 Docker Desktop,Linux 直接安裝 Docker Engine,驗證:docker --version
  • 安裝 JDK(1.8 或以上,驗證:java -version
  • 項目構建工具(Maven 或 Gradle,驗證:mvn -v./gradlew -v
  1. 核心前提:Java 程序已能打包為 可獨立運行的 JAR 包(Spring Boot 項目默認支持,普通 Java 項目需配置 manifest.mf 指定主類)

二、全流程操作步驟(以 Spring Boot 項目為例)

步驟 1:打包 Java 項目為可運行 JAR

先確保本地能正常運行 JAR 包,避免後續鏡像運行報錯。

1.1 Maven 項目打包(推薦)

進入項目根目錄(含 pom.xml 的目錄),執行打包命令:

# 清理舊構建產物 + 編譯 + 打包(跳過測試加速)
mvn clean package -Dmaven.test.skip=true
  • 打包成功後,JAR 包會生成在 項目根目錄/target/ 下,命名格式通常為 項目名-版本號.jar(例:demo-springboot-1.0.0.jar)。
1.2 驗證 JAR 可用性(關鍵步驟)

本地運行 JAR 包,確認程序能正常啓動:

# 運行 JAR 包(默認端口 8080,可通過 --server.port 修改)
java -jar target/demo-springboot-1.0.0.jar
  • 訪問 http://localhost:8080 或項目接口,確認服務正常後,停止進程(Ctrl+C)。

步驟 2:編寫 Dockerfile(核心配置)

項目根目錄 下新建文件 Dockerfile(無後綴名),根據需求選擇「基礎版」或「優化版」。

2.1 基礎版(快速上手,適合測試)
# 1. 選擇基礎鏡像(OpenJDK 官方鏡像,需與項目 JDK 版本一致)
# JDK1.8 用:openjdk:8-jdk-slim;JDK17 用:openjdk:17-jdk-slim
FROM openjdk:17-jdk-slim

# 2. 設定工作目錄(容器內的目錄,類似本地文件夾)
WORKDIR /app

# 3. 複製本地打包好的 JAR 到容器內(左側是本地路徑,右側是容器路徑)
# 注意:本地路徑是相對 Dockerfile 的路徑,若 JAR 在 target 下,直接寫 target/xxx.jar
COPY target/demo-springboot-1.0.0.jar app.jar

# 4. 暴露容器端口(與項目運行端口一致,僅聲明,不映射)
EXPOSE 8080

# 5. 容器啓動時執行的命令(運行 JAR 包)
# ENTRYPOINT 確保容器啓動時必執行,["java", "-jar", "app.jar"] 是命令拆分
ENTRYPOINT ["java", "-jar", "app.jar"]
2.2 優化版(生產環境推薦,含時區、非root、日誌配置)
# 基礎鏡像(slim 版本體積更小,適合生產)
FROM openjdk:17-jdk-slim

# 維護者信息(可選)
LABEL maintainer="your-name <your-email>"

# 設定工作目錄
WORKDIR /app

# 1. 解決時區問題(默認鏡像時區為 UTC,改為 Asia/Shanghai)
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# 2. 創建非 root 用户(避免容器以 root 運行,提升安全性)
RUN addgroup --system appgroup && adduser --system --group appuser
USER appuser

# 3. 複製 JAR 包(若需自定義配置文件,可額外複製:COPY config /app/config)
COPY target/demo-springboot-1.0.0.jar app.jar

# 4. 暴露端口(與項目端口一致)
EXPOSE 8080

# 5. 啓動命令(可添加 JVM 參數,如 -Xms512m -Xmx1024m 限制內存)
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]
2.3 補充:.dockerignore 文件(可選但推薦)

在項目根目錄新建 .dockerignore 文件,排除無關文件,減少鏡像體積:

# 排除 Maven/Gradle 構建目錄
target/
.gradle/
.mvn/
# 排除 IDE 配置文件
.idea/
*.iml
# 排除日誌、臨時文件
logs/
tmp/
# 排除 Docker 相關臨時文件
.dockerignore
Dockerfile

步驟 3:構建 Docker 鏡像

在項目根目錄執行 docker build 命令,生成鏡像。

3.1 基本構建命令
# -t:給鏡像打標籤(格式:鏡像名:版本號,版本號可選,默認 latest)
# .:指定 Docker 構建上下文(即當前目錄,Docker 會掃描該目錄下所有文件)
docker build -t demo-springboot:1.0.0 .
  • 執行後,Docker 會按 Dockerfile 步驟構建鏡像,過程中會下載基礎鏡像(首次較慢,後續緩存)。
  • 構建成功驗證:執行 docker images,能看到 demo-springboot:1.0.0 鏡像。
3.2 常見參數説明
  • --no-cache:不使用緩存,強制重新構建(適合修改 Dockerfile 後使用)
  • -f:指定自定義名稱的 Dockerfile(例:-f Dockerfile.prod

步驟 4:運行 Docker 容器(部署程序)

通過 docker run 命令啓動容器,將鏡像「實例化」為運行的服務。

4.1 基礎運行命令(後台啓動+端口映射)
# -d:後台運行容器(守護進程模式)
# -p:端口映射(本地端口:容器端口,本地端口可自定義,避免衝突)
# --name:給容器起別名(方便後續操作)
# 最後跟 鏡像名:版本號(若版本號為 latest,可省略)
docker run -d -p 8080:8080 --name demo-app demo-springboot:1.0.0
4.2 生產環境推薦命令(含持久化+重啓策略)
# -v:數據卷掛載(將容器內日誌目錄映射到本地,避免容器刪除後日志丟失)
# --restart=always:容器異常退出時自動重啓(確保服務高可用)
# -e:傳遞環境變量(例:指定 Spring  profiles,或修改 JVM 參數)
docker run -d \
  -p 8080:8080 \
  --name demo-app \
  -v /本地目錄/logs:/app/logs \  # 本地日誌目錄需提前創建(mkdir -p /本地目錄/logs)
  -e SPRING_PROFILES_ACTIVE=prod \  # 激活 Spring 生產環境配置
  -e JAVA_OPTS="-Xms512m -Xmx1024m" \  # 自定義 JVM 參數
  --restart=always \
  demo-springboot:1.0.0
4.3 容器運行驗證
# 1. 查看運行中的容器
docker ps

# 2. 查看容器日誌(實時輸出,Ctrl+C 退出)
docker logs -f demo-app

# 3. 訪問服務(與本地運行一致)
curl http://localhost:8080 或瀏覽器打開該地址

步驟 5:常用維護命令(容器/鏡像管理)

# 停止容器
docker stop demo-app

# 啓動已停止的容器
docker start demo-app

# 重啓容器
docker restart demo-app

# 刪除容器(需先停止)
docker rm demo-app
# 強制刪除運行中的容器
docker rm -f demo-app

# 刪除鏡像(需先刪除依賴該鏡像的容器)
docker rmi demo-springboot:1.0.0

# 查看容器詳細信息(端口、掛載、環境變量等)
docker inspect demo-app

三、進階優化與補充場景

1. 鏡像瘦身(減少體積)

  • 基礎鏡像選擇:優先用 openjdk:xx-jdk-slim(比 openjdk:xx-jdk 小 50%+),或 eclipse-temurin:xx-jre-alpine(Alpine 系統,體積最小,需注意 glibc 兼容問題)
  • 多階段構建(適合複雜項目):先用構建鏡像打包 JAR,再用運行鏡像複製 JAR,示例:
# 第一階段:構建 JAR(用 Maven 鏡像)
FROM maven:3.8.8-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml .
# 下載依賴(緩存依賴,後續修改代碼無需重新下載)
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -Dmaven.test.skip=true

# 第二階段:運行 JAR(用輕量鏡像)
FROM openjdk:17-jdk-slim
WORKDIR /app
# 從構建階段複製 JAR
COPY --from=builder /app/target/demo-springboot-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

2. 多模塊 Maven 項目處理

若項目是多模塊(例:父模塊 demo-parent,子模塊 demo-service),JAR 包在 demo-service/target/ 下,Dockerfile 需調整 COPY 路徑:

# 複製子模塊的 JAR 包(相對 Dockerfile 的路徑)
COPY demo-service/target/demo-service-1.0.0.jar app.jar

3. 推送鏡像到私有倉庫(團隊共享)

# 1. 登錄私有倉庫(例:Docker Hub、阿里雲鏡像倉庫)
docker login --username=你的賬號 倉庫地址(Docker Hub 可省略)

# 2. 給鏡像打標籤(格式:倉庫地址/鏡像名:版本號)
docker tag demo-springboot:1.0.0 倉庫地址/demo-springboot:1.0.0

# 3. 推送鏡像
docker push 倉庫地址/demo-springboot:1.0.0

# 4. 其他機器拉取鏡像
docker pull 倉庫地址/demo-springboot:1.0.0

四、常見問題排查

  1. 容器啓動失敗(docker ps 看不到)
  • 查看錯誤日誌:docker logs demo-app(無需 -f,直接看啓動失敗原因)
  • 常見原因:端口被佔用(換本地端口,如 -p 8081:8080)、JAR 包路徑錯誤(檢查 Dockerfile 的 COPY 命令)、JDK 版本不匹配(基礎鏡像版本與項目 JDK 一致)
  1. 訪問服務超時
  • 確認端口映射正確(docker ps 查看 PORTS 列)
  • 檢查容器內服務是否啓動(docker logs -f demo-app 看是否有「Started Application」日誌)
  • 雲服務器需開放安全組端口(如阿里雲、騰訊雲的 8080 端口)
  1. 鏡像體積過大
  • slimalpine 基礎鏡像
  • 排除無關文件(完善 .dockerignore
  • 採用多階段構建