Docker实战:Spring Boot应用容器化
以"Spring Boot + MySQL"为例,详细讲解容器化部署的关键步骤,重点关注多阶段构建、环境配置与网络通信等核心要点。适用于企业级应用部署参考。
1. 项目结构
springboot-demo/
├── Dockerfile # 多阶段构建脚本(定义镜像构建流程,包含编译和运行阶段)
├── pom.xml # Maven依赖配置(管理Java项目第三方库及版本)
├── src/ # 业务代码(包含Controller、Service、Entity等核心逻辑)
├── application.yml # 应用配置(基础参数设置,支持通过环境变量动态覆盖)
└── entrypoint.sh # 启动脚本(检查MySQL依赖就绪状态并注入环境变量)
2. 多阶段Dockerfile构建
# 阶段1:代码编译(使用maven镜像编译代码并提取分层依赖)
FROM maven:3.8.6-openjdk-11 AS builder
WORKDIR /app
# 缓存依赖(当pom.xml不变时复用缓存,避免重复下载)
COPY pom.xml .
RUN mvn dependency:go-offline
# 复制源代码并编译打包
COPY src ./src
RUN mvn package -DskipTests && \
# 提取Spring Boot分层文件(优化镜像层缓存,仅更新变动层)
java -Djarmode=layertools -jar target/*.jar extract
# 阶段2:运行环境(仅包含运行时必需组件,大幅减小镜像体积)
FROM openjdk:11-jre-slim
WORKDIR /app
# 按变更频率排序复制分层文件,优化缓存利用率
COPY --from=builder /app/dependencies/ ./
COPY --from=builder /app/spring-boot-loader/ ./
COPY --from=builder /app/snapshot-dependencies/ ./
COPY --from=builder /app/application/ ./
# 配置启动脚本
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh
# 声明应用端口
EXPOSE 8080
# 容器启动入口
ENTRYPOINT ["./entrypoint.sh"]
3. 启动脚本(依赖检查)
#!/bin/bash
set -e # 脚本执行出错时立即退出
# 等待MySQL服务就绪(避免应用启动时数据库未初始化完成)
echo "等待MySQL服务: $MYSQL_HOST:$MYSQL_PORT"
while ! nc -z $MYSQL_HOST $MYSQL_PORT; do
sleep 1 # 每1秒检查一次连接
done
echo "MySQL服务已就绪,启动应用..."
# 启动Spring Boot应用(通过环境变量注入数据库配置)
exec java org.springframework.boot.loader.JarLauncher \
--spring.datasource.url=jdbc:mysql://$MYSQL_HOST:$MYSQL_PORT/$MYSQL_DATABASE?useSSL=false&serverTimezone=UTC \
--spring.datasource.username=$MYSQL_USER \
--spring.datasource.password=$MYSQL_PASSWORD
4. 应用配置(环境变量覆盖)
server:
port: 8080 # 应用监听端口
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库默认配置(可被环境变量覆盖)
url: jdbc:mysql://localhost:3306/defaultdb?useSSL=false&serverTimezone=UTC
username: root
password: password
jpa:
hibernate:
ddl-auto: update # 开发环境自动创建表结构(生产环境建议改为none)
show-sql: true # 打印执行的SQL语句(开发环境使用)
5. 部署流程
# 1. 构建镜像
docker build -t springboot-demo:v1 .
# 2. 启动MySQL容器(带数据持久化和字符集配置)
docker run -d --name mysql \
-v mysql-data:/var/lib/mysql \ # 数据卷持久化
-e MYSQL_DATABASE=appdb \ # 初始化应用数据库
-e MYSQL_ROOT_PASSWORD=123456 \ # 数据库密码
mysql:8.0 \
--character-set-server=utf8mb4 \ # 支持特殊字符
--collation-server=utf8mb4_unicode_ci
# 3. 创建自定义网络
docker network create app-net
docker network connect app-net mysql # 将MySQL加入网络
# 4. 启动Spring Boot应用
docker run -d --name springboot-app \
--network app-net \ # 加入自定义网络
-p 8080:8080 \ # 端口映射
-e MYSQL_HOST=mysql \ # 数据库配置
-e MYSQL_PORT=3306 \
-e MYSQL_DATABASE=appdb \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=123456 \
springboot-demo:v1
# 5. 验证启动
curl http://localhost:8080/health
# 输出示例:{"status":"UP","components":{"db":{"status":"UP","details":{"database":"MySQL","version":"8.0.28"}}}}
6. 问题排查指南
数据库连接问题:
# 检查网络连通性 docker exec -ti springboot-app ping mysql # 查看应用日志 docker logs -f springboot-app | grep -i "could not connect to database"
镜像优化:
- 运行
docker history springboot-demo:v1
检查镜像层 - 基础镜像对比:
openjdk:11-jre-slim
:约80MBopenjdk:11-jre-alpine
:约50MB(注意musl-libc兼容性)
- 运行
容器调试:
docker exec -ti springboot-app /bin/bash # 执行网络诊断命令
最佳实践
使用Docker Compose管理多容器:
version: '3' services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: appdb volumes: - mysql-data:/var/lib/mysql app: image: springboot-demo:v1 ports: - "8080:8080" environment: MYSQL_HOST: mysql depends_on: - mysql volumes: mysql-data:
生产环境建议:
- 敏感配置使用Docker Secrets或配置中心管理
- 镜像标签关联Git Commit ID(如
springboot-demo:abc123
) - 配置健康检查(
HEALTHCHECK
指令)