Docker 打包部署 Java 程序全流程(含 Spring Boot 示例)
一、前置條件
- 環境準備:
- 安裝 Docker(Windows/Mac 用 Docker Desktop,Linux 直接安裝 Docker Engine,驗證:
docker --version) - 安裝 JDK(1.8 或以上,驗證:
java -version) - 項目構建工具(Maven 或 Gradle,驗證:
mvn -v或./gradlew -v)
- 核心前提: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
四、常見問題排查
- 容器啓動失敗(docker ps 看不到):
- 查看錯誤日誌:
docker logs demo-app(無需-f,直接看啓動失敗原因) - 常見原因:端口被佔用(換本地端口,如
-p 8081:8080)、JAR 包路徑錯誤(檢查 Dockerfile 的COPY命令)、JDK 版本不匹配(基礎鏡像版本與項目 JDK 一致)
- 訪問服務超時:
- 確認端口映射正確(
docker ps查看PORTS列) - 檢查容器內服務是否啓動(
docker logs -f demo-app看是否有「Started Application」日誌) - 雲服務器需開放安全組端口(如阿里雲、騰訊雲的 8080 端口)
- 鏡像體積過大:
- 用
slim或alpine基礎鏡像 - 排除無關文件(完善
.dockerignore) - 採用多階段構建