在Docker中運行Java JAR包的實戰(zhàn)教程
更新時間:2025年12月19日 08:33:02 作者:不惑_
這篇文章詳細介紹了使用Docker運行Java應用的全過程,從環(huán)境準備到構(gòu)建與運行,再到進階配置和最佳實踐,需要的朋友可以參考下
1. 前言與環(huán)境準備
1.1 為什么使用 Docker 運行 Java 應用?
┌─────────────────────────────────────────────────────────────────┐ │ 傳統(tǒng)部署 vs Docker 部署 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 傳統(tǒng)部署: Docker 部署: │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ App.jar │ │ Container │ │ │ ├─────────────┤ │ ┌─────────┐ │ │ │ │ JDK 8 │ ──────? │ │ App.jar │ │ │ │ ├─────────────┤ │ ├─────────┤ │ │ │ │ CentOS │ │ │ JDK │ │ │ │ └─────────────┘ │ ├─────────┤ │ │ │ │ │ Linux │ │ │ │ ? 環(huán)境不一致 │ └─────────┘ │ │ │ ? 依賴沖突 └─────────────┘ │ │ ? 部署復雜 │ │ ? 環(huán)境一致 │ │ ? 隔離性好 │ │ ? 快速部署 │ └─────────────────────────────────────────────────────────────────┘
1.2 環(huán)境準備
# 檢查 Docker 是否安裝 docker --version # Docker version 24.0.0, build xxxxx # 檢查 Docker 服務狀態(tài) systemctl status docker # 如未安裝,執(zhí)行以下命令(以 CentOS 為例) yum install -y docker-ce docker-ce-cli containerd.io systemctl start docker systemctl enable docker
1.3 項目結(jié)構(gòu)
my-java-app/ ├── src/ │ └── main/ │ └── java/ │ └── com/example/ │ └── Application.java ├── target/ │ └── my-app-1.0.0.jar # 打包后的 JAR 文件 ├── Dockerfile # Docker 構(gòu)建文件 ├── docker-compose.yml # Docker Compose 配置 └── pom.xml
2. 準備 Java 項目
2.1 示例 Spring Boot 應用
// Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@GetMapping("/hello")
public String hello() {
return "Hello from Docker! ??";
}
@GetMapping("/health")
public String health() {
return "OK";
}
}
2.2 Maven 打包配置
<!-- pom.xml -->
<project>
<groupId>com.example</groupId>
<artifactId>my-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- 指定打包后的文件名 -->
<finalName>my-app</finalName>
</build>
</project>
2.3 打包 JAR 文件
# 使用 Maven 打包 mvn clean package -DskipTests # 驗證 JAR 文件 ls -lh target/my-app.jar # 本地測試運行 java -jar target/my-app.jar
3. 編寫 Dockerfile
3.1 基礎(chǔ)版 Dockerfile
# Dockerfile # 使用官方 OpenJDK 鏡像作為基礎(chǔ)鏡像 FROM openjdk:8-jdk-alpine # 維護者信息 LABEL maintainer="your-email@example.com" LABEL version="1.0" LABEL description="My Java Application" # 設置工作目錄 WORKDIR /app # 復制 JAR 文件到容器 COPY target/my-app.jar app.jar # 暴露應用端口 EXPOSE 8080 # 啟動命令 ENTRYPOINT ["java", "-jar", "app.jar"]
3.2 優(yōu)化版 Dockerfile(推薦)
# Dockerfile
# ============ 第一階段:構(gòu)建階段 ============
FROM maven:3.8.6-openjdk-8-slim AS builder
WORKDIR /build
# 先復制 pom.xml,利用 Docker 緩存機制
COPY pom.xml .
RUN mvn dependency:go-offline -B
# 復制源代碼并構(gòu)建
COPY src ./src
RUN mvn clean package -DskipTests
# ============ 第二階段:運行階段 ============
FROM openjdk:8-jre-alpine
# 創(chuàng)建非 root 用戶(安全最佳實踐)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 從構(gòu)建階段復制 JAR 文件
COPY --from=builder /build/target/*.jar app.jar
# 更改文件所有權(quán)
RUN chown -R appuser:appgroup /app
# 切換到非 root 用戶
USER appuser
# 暴露端口
EXPOSE 8080
# 健康檢查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:8080/health || exit 1
# JVM 參數(shù)優(yōu)化
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
# 啟動命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
3.3 不同 JDK 版本選擇
# ============ JDK 版本選擇參考 ============ # JDK 8 (經(jīng)典穩(wěn)定版) FROM openjdk:8-jdk-alpine # 完整 JDK,105MB FROM openjdk:8-jre-alpine # 僅運行時,85MB (推薦) # JDK 11 (LTS 長期支持版) FROM openjdk:11-jdk-slim # 精簡版 FROM eclipse-temurin:11-jre # Eclipse Temurin (推薦) # JDK 17 (最新 LTS 版) FROM eclipse-temurin:17-jdk-alpine FROM eclipse-temurin:17-jre-alpine # 推薦 # JDK 21 (最新 LTS 版) FROM eclipse-temurin:21-jre-alpine
3.4 鏡像大小對比
┌─────────────────────────────────────────────────────────────┐ │ 鏡像大小對比 │ ├─────────────────────────────┬───────────────────────────────┤ │ 基礎(chǔ)鏡像 │ 大小 │ ├─────────────────────────────┼───────────────────────────────┤ │ openjdk:8 │ ~500MB │ │ openjdk:8-jdk-alpine │ ~105MB │ │ openjdk:8-jre-alpine │ ~85MB ? 推薦 │ │ eclipse-temurin:17-jre │ ~260MB │ │ eclipse-temurin:17-jre-alpine │ ~180MB │ └─────────────────────────────┴───────────────────────────────┘
4. 構(gòu)建與運行鏡像
4.1 構(gòu)建 Docker 鏡像
# 基本構(gòu)建命令
docker build -t my-java-app:1.0.0 .
# 帶詳細日志的構(gòu)建
docker build --progress=plain -t my-java-app:1.0.0 .
# 不使用緩存構(gòu)建
docker build --no-cache -t my-java-app:1.0.0 .
# 構(gòu)建時傳遞參數(shù)
docker build \
--build-arg JAR_FILE=target/my-app.jar \
-t my-java-app:1.0.0 .
4.2 查看鏡像信息
# 列出所有鏡像 docker images # 輸出示例: # REPOSITORY TAG IMAGE ID CREATED SIZE # my-java-app 1.0.0 a1b2c3d4e5f6 30 seconds ago 145MB # 查看鏡像詳細信息 docker inspect my-java-app:1.0.0 # 查看鏡像歷史層 docker history my-java-app:1.0.0
4.3 運行容器
# 基本運行
docker run -d -p 8080:8080 --name my-app my-java-app:1.0.0
# 帶環(huán)境變量運行
docker run -d \
-p 8080:8080 \
--name my-app \
-e SPRING_PROFILES_ACTIVE=prod \
-e DATABASE_URL=jdbc:mysql://db:3306/mydb \
my-java-app:1.0.0
# 帶資源限制運行
docker run -d \
-p 8080:8080 \
--name my-app \
--memory=512m \
--cpus=1.0 \
my-java-app:1.0.0
# 完整運行命令
docker run -d \
--name my-app \
-p 8080:8080 \
-v /host/logs:/app/logs \
-v /host/config:/app/config:ro \
-e JAVA_OPTS="-Xms256m -Xmx512m" \
-e SPRING_PROFILES_ACTIVE=prod \
--memory=512m \
--cpus=1.0 \
--restart=unless-stopped \
my-java-app:1.0.0
4.4 運行參數(shù)說明
┌──────────────────────────────────────────────────────────────────┐ │ Docker Run 參數(shù)說明 │ ├────────────────────┬─────────────────────────────────────────────┤ │ 參數(shù) │ 說明 │ ├────────────────────┼─────────────────────────────────────────────┤ │ -d │ 后臺運行容器 │ │ -p 8080:8080 │ 端口映射 (宿主機:容器) │ │ --name my-app │ 指定容器名稱 │ │ -e KEY=VALUE │ 設置環(huán)境變量 │ │ -v /host:/container│ 掛載數(shù)據(jù)卷 │ │ --memory=512m │ 限制內(nèi)存使用 │ │ --cpus=1.0 │ 限制 CPU 使用 │ │ --restart │ 重啟策略 (no/always/unless-stopped) │ │ --network │ 指定網(wǎng)絡 │ └────────────────────┴─────────────────────────────────────────────┘
4.5 驗證運行狀態(tài)
# 查看運行中的容器 docker ps # 查看容器日志 docker logs -f my-app # 查看最近 100 行日志 docker logs --tail 100 my-app # 進入容器內(nèi)部 docker exec -it my-app /bin/sh # 測試應用 curl http://localhost:8080/hello # 輸出: Hello from Docker! ?? # 查看容器資源使用 docker stats my-app
5. 進階配置
5.1 多環(huán)境配置
# Dockerfile with args
FROM eclipse-temurin:17-jre-alpine
ARG PROFILE=dev
ARG APP_PORT=8080
ENV SPRING_PROFILES_ACTIVE=${PROFILE}
ENV SERVER_PORT=${APP_PORT}
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE ${APP_PORT}
ENTRYPOINT ["sh", "-c", "java -jar app.jar"]
# 構(gòu)建不同環(huán)境的鏡像 docker build --build-arg PROFILE=dev -t my-app:dev . docker build --build-arg PROFILE=prod -t my-app:prod .
5.2 配置文件外置
# application.yml
server:
port: ${SERVER_PORT:8080}
spring:
profiles:
active: ${SPRING_PROFILES_ACTIVE:dev}
datasource:
url: ${DATABASE_URL:jdbc:h2:mem:testdb}
username: ${DATABASE_USER:sa}
password: ${DATABASE_PASSWORD:}
logging:
level:
root: ${LOG_LEVEL:INFO}
file:
path: /app/logs
# 運行時掛載外部配置
docker run -d \
-p 8080:8080 \
-v /opt/config/application-prod.yml:/app/config/application.yml:ro \
-v /opt/logs:/app/logs \
my-java-app:1.0.0
5.3 JVM 參數(shù)優(yōu)化
# Dockerfile
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
# 容器環(huán)境 JVM 優(yōu)化參數(shù)
ENV JAVA_OPTS="\
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-XX:InitialRAMPercentage=50.0 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:+UseStringDeduplication \
-Djava.security.egd=file:/dev/./urandom \
-Dfile.encoding=UTF-8"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
5.4 時區(qū)配置
FROM eclipse-temurin:17-jre-alpine
# 設置時區(qū)為中國
ENV TZ=Asia/Shanghai
RUN apk add --no-cache tzdata && \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
6. 使用 Docker Compose
6.1 基礎(chǔ)配置
# docker-compose.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
image: my-java-app:1.0.0
container_name: my-java-app
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- TZ=Asia/Shanghai
volumes:
- ./logs:/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
6.2 完整微服務配置
# docker-compose.yml
version: '3.8'
services:
# Java 應用
app:
build: .
image: my-java-app:1.0.0
container_name: my-java-app
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- DATABASE_URL=jdbc:mysql://mysql:3306/mydb?useSSL=false&serverTimezone=Asia/Shanghai
- DATABASE_USER=root
- DATABASE_PASSWORD=rootpassword
- REDIS_HOST=redis
- REDIS_PORT=6379
volumes:
- app-logs:/app/logs
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- app-network
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
# MySQL 數(shù)據(jù)庫
mysql:
image: mysql:8.0
container_name: my-mysql
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=mydb
- TZ=Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports:
- "3306:3306"
networks:
- app-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# Redis 緩存
redis:
image: redis:7-alpine
container_name: my-redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- app-network
restart: unless-stopped
# Nginx 反向代理
nginx:
image: nginx:alpine
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
networks:
- app-network
restart: unless-stopped
networks:
app-network:
driver: bridge
volumes:
app-logs:
mysql-data:
redis-data:
6.3 Docker Compose 常用命令
# 啟動所有服務 docker-compose up -d # 查看服務狀態(tài) docker-compose ps # 查看服務日志 docker-compose logs -f app # 重新構(gòu)建并啟動 docker-compose up -d --build # 停止所有服務 docker-compose down # 停止并刪除數(shù)據(jù)卷 docker-compose down -v # 重啟單個服務 docker-compose restart app # 擴展服務實例 docker-compose up -d --scale app=3
7. 最佳實踐
7.1 Dockerfile 最佳實踐
# ? 最佳實踐示例
FROM eclipse-temurin:17-jre-alpine
# 1. 使用標簽
LABEL maintainer="dev@example.com" \
version="1.0.0" \
description="Production Java Application"
# 2. 創(chuàng)建非 root 用戶
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 3. 設置工作目錄
WORKDIR /app
# 4. 最小化層數(shù),清理緩存
RUN apk add --no-cache tzdata curl && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apk del tzdata
# 5. 復制文件并設置權(quán)限
COPY --chown=appuser:appgroup target/*.jar app.jar
# 6. 切換用戶
USER appuser
# 7. 設置健康檢查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# 8. 暴露端口
EXPOSE 8080
# 9. 使用 ENTRYPOINT
ENTRYPOINT ["java", \
"-XX:+UseContainerSupport", \
"-XX:MaxRAMPercentage=75.0", \
"-jar", "app.jar"]
7.2 安全最佳實踐
┌─────────────────────────────────────────────────────────────────┐ │ Docker 安全最佳實踐 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ? 使用非 root 用戶運行應用 │ │ ? 使用最小化基礎(chǔ)鏡像 (alpine) │ │ ? 定期更新基礎(chǔ)鏡像 │ │ ? 掃描鏡像漏洞 (Trivy, Snyk) │ │ ? 不在鏡像中存儲敏感信息 │ │ ? 使用 secrets 管理敏感數(shù)據(jù) │ │ ? 限制容器資源使用 │ │ ? 只暴露必要端口 │ │ ? 使用只讀文件系統(tǒng) (--read-only) │ │ │ └─────────────────────────────────────────────────────────────────┘
7.3 鏡像優(yōu)化清單
# 1. 使用多階段構(gòu)建減少鏡像大小 # 2. 使用 .dockerignore 排除無關(guān)文件 # .dockerignore .git .gitignore README.md .idea *.iml target/ !target/*.jar node_modules *.log docker-compose*.yml
8. 常見問題排查
8.1 問題排查命令
# 查看容器日志 docker logs my-app # 實時查看日志 docker logs -f my-app # 進入容器調(diào)試 docker exec -it my-app /bin/sh # 查看容器進程 docker top my-app # 查看容器資源使用 docker stats my-app # 檢查容器詳細信息 docker inspect my-app # 查看容器文件系統(tǒng)變化 docker diff my-app
8.2 常見問題與解決方案
┌─────────────────────────────────────────────────────────────────┐ │ 常見問題排查 │ ├────────────────────────┬────────────────────────────────────────┤ │ 問題 │ 解決方案 │ ├────────────────────────┼────────────────────────────────────────┤ │ OOM (內(nèi)存不足) │ 增加 --memory 限制 │ │ │ 調(diào)整 JVM 參數(shù) -Xmx │ ├────────────────────────┼────────────────────────────────────────┤ │ 容器啟動后立即退出 │ 檢查 ENTRYPOINT/CMD │ │ │ 查看 docker logs │ ├────────────────────────┼────────────────────────────────────────┤ │ 端口無法訪問 │ 檢查端口映射 -p │ │ │ 檢查防火墻設置 │ ├────────────────────────┼────────────────────────────────────────┤ │ 時區(qū)不正確 │ 設置 TZ 環(huán)境變量 │ │ │ 掛載時區(qū)文件 │ ├────────────────────────┼────────────────────────────────────────┤ │ 中文亂碼 │ 設置 LANG=C.UTF-8 │ │ │ 安裝字體包 │ ├────────────────────────┼────────────────────────────────────────┤ │ 無法連接數(shù)據(jù)庫 │ 檢查網(wǎng)絡配置 │ │ │ 使用容器名作為主機名 │ └────────────────────────┴────────────────────────────────────────┘
8.3 性能監(jiān)控
# 實時監(jiān)控資源使用 docker stats # 使用 jps 查看 Java 進程 docker exec my-app jps -l # 查看 JVM 堆內(nèi)存使用 docker exec my-app jmap -heap <PID> # 導出堆轉(zhuǎn)儲文件 docker exec my-app jmap -dump:format=b,file=/tmp/heap.hprof <PID> docker cp my-app:/tmp/heap.hprof ./heap.hprof
?? 總結(jié)
┌─────────────────────────────────────────────────────────────────┐ │ Docker 部署 Java 應用流程 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. 準備階段 │ │ └── 打包 JAR 文件 (mvn package) │ │ │ │ 2. 容器化階段 │ │ ├── 編寫 Dockerfile │ │ ├── 構(gòu)建鏡像 (docker build) │ │ └── 測試運行 (docker run) │ │ │ │ 3. 部署階段 │ │ ├── 推送鏡像到倉庫 (docker push) │ │ ├── 拉取鏡像 (docker pull) │ │ └── 運行容器 (docker-compose up) │ │ │ │ 4. 運維階段 │ │ ├── 日志監(jiān)控 (docker logs) │ │ ├── 性能監(jiān)控 (docker stats) │ │ └── 故障排查 (docker exec) │ │ │ └─────────────────────────────────────────────────────────────────┘
快速參考命令
# 完整工作流 mvn clean package -DskipTests # 1. 打包 docker build -t my-app:1.0.0 . # 2. 構(gòu)建鏡像 docker run -d -p 8080:8080 my-app:1.0.0 # 3. 運行容器 curl http://localhost:8080/hello # 4. 驗證 docker logs -f <container-id> # 5. 查看日志
以上就是在Docker中運行Java JAR包的實戰(zhàn)教程的詳細內(nèi)容,更多關(guān)于Docker運行Java JAR包的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用Docker安裝Nginx并配置端口轉(zhuǎn)發(fā)問題及解決方法
這篇文章主要介紹了使用Docker安裝Nginx并配置端口轉(zhuǎn)發(fā),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-01-01
docker 安裝nacos并配置數(shù)據(jù)庫的教程詳解
這篇文章主要介紹了docker 安裝nacos并配置數(shù)據(jù)庫的教程詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12
解決誤刪docker目錄/var/lib/docker/overlay2,導致容器build失敗問題
文章介紹了Docker的overlay2存儲驅(qū)動,解釋了其分層存儲機制和節(jié)省空間的方式,刪除/var/lib/docker/overlay2目錄下的文件導致容器無法啟動,通過重啟Docker并使用`docker?system?prune`和`docker?system?prune?-a`命令可以清理不必要的鏡像、容器和網(wǎng)絡,釋放磁盤空間2025-10-10
Docker Consul概述以及集群環(huán)境搭建步驟(圖文詳解)
本文主要介紹了Docker-Consul概述以及集群環(huán)境搭建步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12

