本文目录导读:

我来提供一个完整的Docker部署Java应用的实例,从基础到进阶。
基础部署案例
简单的Spring Boot应用部署
项目结构:
my-java-app/
├── src/
│ ├── main/
│ │ ├── java/
│ │ └── resources/
│ └── test/
├── Dockerfile
├── docker-compose.yml
└── pom.xml (或 build.gradle)
使用Maven构建
# 多阶段构建 FROM maven:3.8.3-openjdk-11 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests # 运行阶段 FROM openjdk:11-jre-slim WORKDIR /app COPY --from=builder /app/target/*.jar app.jar EXPOSE 8080 ENV JAVA_OPTS="-Xms256m -Xmx512m" ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
使用Gradle构建
FROM gradle:7.2-jdk11 AS builder WORKDIR /app COPY build.gradle . COPY gradlew . COPY gradle ./gradle RUN ./gradlew dependencies COPY src ./src RUN ./gradlew bootJar FROM openjdk:11-jre-slim WORKDIR /app COPY --from=builder /app/build/libs/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
Docker Compose配置
version: '3.8'
services:
app:
build: .
container_name: java-app
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=dev
- DB_HOST=mysql
- DB_PORT=3306
- DB_NAME=myapp
- DB_USER=root
- DB_PASSWORD=secret
depends_on:
- mysql
networks:
- app-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mysql:
image: mysql:8.0
container_name: mysql-db
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- app-network
volumes:
mysql_data:
networks:
app-network:
driver: bridge
高级部署案例
使用Dockerfile优化技巧
# 基础镜像选择
FROM eclipse-temurin:17-jre-alpine
# 添加非root用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 复制jar包并优化
COPY target/*.jar app.jar
# 设置时区
RUN apk add --no-cache tzdata \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone
# 切换到非root用户
USER appuser
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
CMD wget -q --spider http://localhost:8080/actuator/health || exit 1
# JVM参数优化
ENV JAVA_OPTS="-Xms512m -Xmx1g -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -XX:MaxGCPauseMillis=100"
# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
完整的生产环境部署
docker-compose.prod.yml:
version: '3.8'
services:
app:
image: registry.example.com/myapp:latest
container_name: myapp-prod
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- CONFIG_SERVER_URL=http://config-server:8888
- EUREKA_SERVER_URL=http://eureka:8761/eureka
volumes:
- app-logs:/app/logs
- app-config:/app/config
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
max_attempts: 3
window: 120s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
networks:
- microservice-network
secrets:
- db_password
nginx:
image: nginx:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
networks:
- microservice-network
secrets:
db_password:
external: true
networks:
microservice-network:
driver: overlay
volumes:
app-logs:
app-config:
使用外部配置和JMX监控
version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
- "1099:1099" # JMX端口
environment:
- JAVA_OPTS=-Xms512m -Xmx1g \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=1099 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=localhost
volumes:
- ./config:/app/config:ro # 外部配置文件
- ./logs:/app/logs # 日志持久化
- ./uploads:/app/uploads # 文件上传目录
command: >
sh -c "java $JAVA_OPTS
-Dspring.config.location=file:/app/config/application.yml
-jar app.jar"
容器化最佳实践
多模块Maven项目部署
# 多阶段构建示例 FROM maven:3.8.3-openjdk-11 AS build WORKDIR /workspace # 复制pom文件 COPY pom.xml . COPY common/pom.xml common/ COPY api/pom.xml api/ COPY service/pom.xml service/ # 先下载依赖 RUN mvn dependency:go-offline -B # 复制源码 COPY common/ common/ COPY api/ api/ COPY service/ service/ # 只构建service模块 RUN mvn clean install -pl service -am -DskipTests FROM openjdk:11-jre-slim WORKDIR /app COPY --from=build /workspace/service/target/*.jar app.jar EXPOSE 8080 CMD ["java", "-jar", "app.jar"]
配置外部化
# 使用环境变量配置
spring:
datasource:
url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:myapp}
username: ${DB_USER:root}
password: ${DB_PASSWORD:secret}
# docker-compose覆盖配置
version: '3.8'
services:
app:
environment:
- DB_HOST=production-db.com
- DB_PORT=3306
- DB_NAME=production_db
- DB_USER=prod_user
- DB_PASSWORD=${DB_PASSWORD} # 从.env文件读取
.dockerignore文件
target/ *.class *.jar !.mvn/wrapper/maven-wrapper.jar *.log .DS_Store .idea/ .vscode/ .git/ .gitignore *.iml HELP.md
部署命令和操作
基础命令
# 构建镜像 docker build -t myapp:latest . # 运行容器 docker run -d -p 8080:8080 --name myapp myapp:latest # 查看日志 docker logs -f myapp # 进入容器 docker exec -it myapp /bin/bash # 停止和删除 docker stop myapp && docker rm myapp
生产环境部署命令
# 使用Docker Compose部署
docker-compose up -d
docker-compose down
# 使用Docker Stack部署到Swarm
docker stack deploy -c docker-compose.prod.yml myapp
# 更新容器
docker-compose up -d --build --force-recreate
# 查看健康状态
docker ps --filter "health=health" --format "table {{.Names}}\t{{.Status}}"
自动化部署脚本
#!/bin/bash
# deploy.sh
set -e
echo "Building application..."
./mvnw clean package -DskipTests
echo "Building Docker image..."
docker build -t myapp:${VERSION} .
echo "Stopping old container..."
docker stop myapp || true
docker rm myapp || true
echo "Deploying new container..."
docker run -d \
--name myapp \
--network mynetwork \
-p 8080:8080 \
--env-file .env.prod \
--restart unless-stopped \
myapp:${VERSION}
echo "Deployment completed successfully!"
sleep 10
curl -f http://localhost:8080/actuator/health || exit 1
监控和日志采集
# 集成Prometheus和Elastic Stack
version: '3.8'
services:
app:
build: .
expose:
- "8080"
environment:
- MANAGEMENT_ENDPOINTS_WEB_EXPOSURE=*
labels:
prometheus.io/scrape: "true"
prometheus.io/path: "/actuator/prometheus"
prometheus.io/port: "8080"
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
filebeat:
image: docker.elastic.co/beats/filebeat:7.13.0
volumes:
- app-logs:/var/log/app
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0
environment:
- discovery.type=single-node
ports:
- "9200:9200"
kibana:
image: docker.elastic.co/kibana/kibana:7.13.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
这个完整的部署案例涵盖了从开发到生产的各种场景,你可以根据实际需求选择合适的方式,记住要根据你的应用特点调整JVM参数、资源限制和部署策略。