Java項(xiàng)目打包Docker鏡像全流程
環(huán)境準(zhǔn)備
1. 開(kāi)發(fā)環(huán)境要求
- JDK 8+ (推薦JDK 11/17 LTS版本)
- Maven 3.6+ 或 Gradle 7+
- Docker Desktop (Mac/Windows) 或 Docker Engine (Linux)
- 推薦IDE: IntelliJ IDEA (社區(qū)版即可)
2. 安裝Docker
不同操作系統(tǒng)的安裝方式:
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 # 設(shè)置穩(wěn)定版?zhèn)}庫(kù) 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 # 驗(yàn)證安裝 sudo docker run hello-world
Mac/Windows:直接下載Docker Desktop安裝包:
https://www.docker.com/products/docker-desktop
3. 驗(yàn)證安裝
docker --version # 輸出類似: Docker version 20.10.12, build e91ed57 docker-compose --version # 輸出類似: docker-compose version 1.29.2, build 5becea4c
項(xiàng)目結(jié)構(gòu)說(shuō)明
我們以一個(gè)典型的Spring Boot項(xiàng)目為例:
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基礎(chǔ)概念
在開(kāi)始之前,先了解幾個(gè)核心概念:
- 鏡像(Image): 只讀模板,包含運(yùn)行應(yīng)用所需的所有內(nèi)容
- 容器(Container): 鏡像的運(yùn)行實(shí)例
- Dockerfile: 構(gòu)建鏡像的指令文件
- Registry: 鏡像倉(cāng)庫(kù)(如Docker Hub)
Docker的優(yōu)勢(shì):
- 一致的運(yùn)行環(huán)境
- 快速部署和擴(kuò)展
- 資源隔離
- 易于版本管理和回滾
編寫Dockerfile
基礎(chǔ)Dockerfile示例
# 第一階段:構(gòu)建 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 # 第二階段:運(yùn)行 FROM openjdk:11-jre-slim WORKDIR /app # 從構(gòu)建階段復(fù)制jar包 COPY --from=build /app/target/my-java-app-*.jar app.jar # 暴露端口 EXPOSE 8080 # 啟動(dòng)命令 ENTRYPOINT ["java", "-jar", "app.jar"]
逐行解析
FROM maven:3.8.4-openjdk-11 AS build
使用Maven鏡像作為構(gòu)建階段的基礎(chǔ)鏡像,并命名為"build"WORKDIR /app
設(shè)置工作目錄為/appCOPY pom.xml .
復(fù)制pom.xml到工作目錄RUN mvn dependency:go-offline
下載所有依賴項(xiàng)(利用Docker緩存層)COPY src ./src
復(fù)制源代碼RUN mvn package -DskipTests
打包應(yīng)用(跳過(guò)測(cè)試)FROM openjdk:11-jre-slim
第二階段使用更小的JRE鏡像COPY --from=build /app/target/my-java-app-*.jar app.jar
從構(gòu)建階段復(fù)制生成的jar包EXPOSE 8080
聲明容器暴露的端口ENTRYPOINT ["java", "-jar", "app.jar"]
容器啟動(dòng)時(shí)執(zhí)行的命令
多階段構(gòu)建優(yōu)化
多階段構(gòu)建有三大優(yōu)勢(shì):
- 減小鏡像體積 - 最終鏡像只包含運(yùn)行時(shí)必要內(nèi)容
- 提高安全性 - 構(gòu)建工具不會(huì)出現(xiàn)在生產(chǎn)鏡像中
- 更清晰的構(gòu)建流程 - 分離構(gòu)建和運(yùn)行環(huán)境
進(jìn)階優(yōu)化技巧
使用.dockerignore文件
避免將不必要的文件復(fù)制到鏡像中:
.git .idea *.iml target/ *.log *.tmp
選擇合適的基礎(chǔ)鏡像
openjdk:11-jdk
- 完整JDK(較大)openjdk:11-jre
- 僅運(yùn)行時(shí)(較小)openjdk:11-jre-slim
- 更精簡(jiǎn)版本openjdk:11-alpine
- 基于Alpine Linux(最小)
層緩存優(yōu)化
將不常變化的指令放在前面,充分利用緩存:
# 先復(fù)制pom.xml并下載依賴 COPY pom.xml . RUN mvn dependency:go-offline # 然后復(fù)制源代碼 COPY src ./src
構(gòu)建與運(yùn)行鏡像
1. 構(gòu)建鏡像
# -t 指定鏡像名稱和標(biāo)簽 # . 表示使用當(dāng)前目錄的Dockerfile docker build -t my-java-app:1.0 .
構(gòu)建過(guò)程輸出示例:
[+] 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. 運(yùn)行容器
# -d 后臺(tái)運(yùn)行 # -p 端口映射(主機(jī)端口:容器端口) # --name 容器名稱 docker run -d -p 8080:8080 --name my-app my-java-app:1.0
4. 查看運(yùn)行狀態(tài)
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
推送鏡像到倉(cāng)庫(kù)
1. 登錄Docker Hub
docker login -u your-username
2. 標(biāo)記鏡像
# 格式: 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. 從倉(cāng)庫(kù)拉取運(yùn)行
docker run -d -p 8080:8080 your-username/my-java-app:1.0
生產(chǎn)環(huán)境部署
1. 使用docker-compose
創(chuàng)建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
啟動(dòng)服務(wù):
docker-compose up -d
2. Kubernetes部署示例
創(chuàng)建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
總結(jié)與最佳實(shí)踐
最佳實(shí)踐總結(jié)
鏡像優(yōu)化:
- 使用多階段構(gòu)建減小鏡像體積
- 選擇合適的基礎(chǔ)鏡像(Alpine/slim版本)
- 定期更新基礎(chǔ)鏡像以獲取安全補(bǔ)丁
構(gòu)建優(yōu)化:
- 合理利用層緩存(.dockerignore + 指令順序)
- 固定基礎(chǔ)鏡像版本(避免使用latest標(biāo)簽)
- 在CI/CD中實(shí)現(xiàn)自動(dòng)化構(gòu)建
運(yùn)行優(yōu)化:
- 限制容器資源(cpu/memory)
- 配置健康檢查
- 使用非root用戶運(yùn)行
- 正確處理信號(hào)(如SIGTERM)
安全建議:
- 不要將敏感信息硬編碼在鏡像中(使用環(huán)境變量/secret)
- 掃描鏡像中的漏洞(使用docker scan)
- 最小化容器權(quán)限(避免–privileged)
常見(jiàn)問(wèn)題解決
Q: 構(gòu)建時(shí)下載依賴很慢怎么辦?
A: 配置Maven鏡像倉(cāng)庫(kù):
RUN mkdir -p /root/.m2 && \ echo 'aliyunhttps://maven.aliyun.com/repository/publiccentral' > /root/.m2/settings.xml
Q: 容器啟動(dòng)后立即退出?
A: 可能原因:
- 應(yīng)用啟動(dòng)失敗 - 查看日志
docker logs
- 沒(méi)有前臺(tái)進(jìn)程 - 確保應(yīng)用不是以daemon方式運(yùn)行
- 端口沖突 - 檢查端口映射
Q: 如何調(diào)試容器內(nèi)的應(yīng)用?
A: 進(jìn)入運(yùn)行中的容器:
docker exec -it /bin/bash
或者直接附加到進(jìn)程:
docker attach
下一步學(xué)習(xí)建議
- 學(xué)習(xí)Docker網(wǎng)絡(luò)和存儲(chǔ)卷配置
- 掌握Docker Compose編排多容器應(yīng)用
- 了解Kubernetes容器編排
- 探索CI/CD流水線與Docker集成
- 學(xué)習(xí)服務(wù)網(wǎng)格(如Istio)與容器化應(yīng)用
通過(guò)本文的學(xué)習(xí),你已經(jīng)掌握了Java項(xiàng)目容器化的核心技能。Docker的世界還有很多值得探索的地方,繼續(xù)實(shí)踐,你將發(fā)現(xiàn)更多容器化帶來(lái)的便利與效率提升!
以上就是Java項(xiàng)目打包Docker鏡像全流程的詳細(xì)內(nèi)容,更多關(guān)于Java打包Docker鏡像的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺談java switch如果case后面沒(méi)有break,會(huì)出現(xiàn)什么情況?
這篇文章主要介紹了淺談java switch如果case后面沒(méi)有break,會(huì)出現(xiàn)什么情況?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨想小編過(guò)來(lái)看看吧2020-09-09使用arthas命令redefine實(shí)現(xiàn)Java熱更新(推薦)
今天分享一個(gè)非常重要的命令 redefine ,主要作用是加載外部的 .class 文件,用來(lái)替換 JVM 已經(jīng)加載的類,總結(jié)起來(lái)就是實(shí)現(xiàn)了 Java 的熱更新,感興趣的朋友跟隨小編一起看看吧2020-05-05async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法詳解
這篇文章主要介紹了async-excel實(shí)現(xiàn)多sheet異步導(dǎo)出方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-12-12MyBatis實(shí)現(xiàn)萬(wàn)能Map和模糊查詢
本文主要介紹了MyBatis實(shí)現(xiàn)萬(wàn)能Map和模糊查詢,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07淺談Java循環(huán)中的For和For-each哪個(gè)更快
本文主要介紹了淺談Java循環(huán)中的For和For-each哪個(gè)更快,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Java實(shí)現(xiàn)整合文件上傳到FastDFS的方法詳細(xì)
FastDFS是一個(gè)開(kāi)源的輕量級(jí)分布式文件系統(tǒng),對(duì)文件進(jìn)行管理,功能包括:文件存儲(chǔ)、文件同步、文件上傳、文件下載等,解決了大容量存儲(chǔ)和負(fù)載均衡的問(wèn)題。本文將提供Java將文件上傳至FastDFS的示例代碼,需要的參考一下2022-02-02Mybatis日期格式自動(dòng)轉(zhuǎn)換需要用到的兩個(gè)注解說(shuō)明
這篇文章主要介紹了Mybatis日期格式自動(dòng)轉(zhuǎn)換需要用到的兩個(gè)注解說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08