Docker 部署 SpringBoot 项目实战(生产环境可用)

引言:随着微服务架构的普及,Docker 因其轻量、可移植、隔离性强的特性,已成为 Java 后端项目部署的主流方案。本文针对有基础的 Java 后端开发者,提供一套生产环境可用的 SpringBoot 项目 Docker 部署完整流程,涵盖环境准备、镜像构建、容器编排、问题排查四大核心环节,所有代码可直接复制使用,同时记录实战中的典型踩坑点及解决方案。

一、环境准备:生产环境基础配置

1.1 服务器环境要求

生产环境推荐配置(最小化):

  • 操作系统:CentOS 7.x / Ubuntu 20.04 LTS(64位)

  • 内存:2GB+(建议4GB及以上,支撑 SpringBoot 运行+容器基础占用)

  • 磁盘:20GB+ 可用空间

  • 网络:确保 80/443 端口开放(业务端口)、2375/2376 端口(Docker 远程访问,生产环境建议关闭公网访问)

1.2 Docker 环境安装与配置

以下以 CentOS 7 为例,提供 Docker 官方推荐的安装步骤(可直接复制执行):

# 1. 卸载旧版本(若有)
yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

# 2. 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2

# 3. 设置 Docker 官方镜像源(国内推荐阿里云镜像源,速度更快)
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 4. 安装 Docker CE(社区版,生产环境足够使用)
yum install -y docker-ce docker-ce-cli containerd.io

# 5. 启动 Docker 并设置开机自启
systemctl start docker
systemctl enable docker

# 6. 验证 Docker 安装成功
docker --version  # 输出类似:Docker version 24.0.7, build afdd53b
docker run hello-world  # 运行测试镜像,输出 "Hello from Docker!" 即成功

1.3 SpringBoot 项目预处理

确保 SpringBoot 项目满足以下条件(生产环境适配):

  • 项目已打包为 Jar 包(通过 mvn clean package -Dmaven.test.skip=true 构建,跳过测试)

  • 配置文件(application.yml/properties)中,端口、数据库连接等参数可通过环境变量注入(避免硬编码)

  • 排除不必要的依赖(减小 Jar 包体积,提升镜像构建速度)

示例配置(application.yml,通过环境变量注入端口和数据库地址):

server:
  port: ${SERVER_PORT:8080}  # 默认8080,可通过环境变量覆盖
spring:
  datasource:
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:test}?useSSL=false&serverTimezone=Asia/Shanghai
    username: ${DB_USER:root}
    password: ${DB_PASS:root}

二、镜像构建:生产级 Dockerfile 编写与优化

2.1 编写生产级 Dockerfile

在 SpringBoot 项目根目录创建 Dockerfile(注意首字母大写),采用多阶段构建(减小镜像体积,避免冗余依赖):

# 第一阶段:构建阶段(使用 Maven 镜像编译项目,仅用于生成 Jar 包)
FROM maven:3.8.8-openjdk-17 AS builder
# 设置工作目录
WORKDIR /app
# 复制项目 pom.xml 文件(先复制 pom.xml,利用 Docker 缓存机制,提升后续构建速度)
COPY pom.xml .
# 复制项目源码
COPY src ./src
# 编译打包(跳过测试,生产环境构建建议跳过)
RUN mvn clean package -Dmaven.test.skip=true

# 第二阶段:运行阶段(使用轻量级 OpenJDK 镜像,减小最终镜像体积)
FROM openjdk:17-jdk-slim
# 设置时区(生产环境必须配置,避免时间相关问题)
ENV TZ=Asia/Shanghai
# 创建非 root 用户(生产环境禁止使用 root 运行容器,提升安全性)
RUN addgroup --system appgroup && adduser --system appuser --ingroup appgroup
# 设置工作目录
WORKDIR /app
# 从构建阶段复制 Jar 包到当前镜像(注意 Jar 包名称需与项目实际一致)
COPY --from=builder /app/target/*.jar app.jar
# 切换为非 root 用户
USER appuser
# 启动命令(指定 JVM 优化参数,生产环境必备)
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]

关键说明:

  • 多阶段构建:第一阶段使用 Maven 镜像编译,第二阶段仅保留运行所需的 JDK 和 Jar 包,最终镜像体积可从数百 MB 减小到 200MB 左右

  • 非 root 用户运行:避免容器内进程拥有过高权限,降低安全风险

  • JVM 参数优化:-Xms512m(初始堆内存)、-Xmx1024m(最大堆内存),根据服务器内存调整

  • 时区配置:解决容器内时间与主机不一致的问题,避免日志、业务时间错乱

2.2 镜像构建命令与验证

将 SpringBoot 项目的 Dockerfile 和 Jar 包(若未使用多阶段构建,需提前将 Jar 包上传到服务器)上传到服务器的同一目录,执行以下命令构建镜像:

# 构建镜像,-t 指定镜像名称:版本号(建议版本号语义化,如 v1.0.0)
docker build -t springboot-demo:v1.0.0 .

# 验证镜像是否构建成功
docker images | grep springboot-demo
# 输出类似:springboot-demo   v1.0.0   xxxxxxxx   2 minutes ago   215MB

2.3 镜像优化技巧(生产环境必看)

  • 使用 .dockerignore 文件:排除不需要复制到镜像的文件(如 .git、target/*、logs 等),减少构建上下文大小,提升构建速度。示例 .dockerignore.git .gitignore target/* logs *.md

  • 选择轻量级基础镜像:优先使用openjdk:xx-jdk-slim 而非完整版 openjdk:xx-jdk,或更轻量的 alpine 版本(注意 alpine 版本可能存在字体、依赖问题,生产环境需测试验证)

  • 合并 RUN 命令:使用 && 合并多个 RUN 指令,减少镜像分层(每一个 RUN 指令都会创建一个镜像层,分层过多会增加镜像体积)

三、容器编排:Docker Compose 生产级部署

生产环境中,SpringBoot 项目通常需要依赖数据库、Redis 等中间件,使用 Docker Compose 可实现多容器的统一编排、启动、停止,简化部署流程。

3.1 安装 Docker Compose

# 下载 Docker Compose(适用于 Linux x86_64 架构)
curl -L "https://github.com/docker/compose/releases/download/v2.23.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 赋予执行权限
chmod +x /usr/local/bin/docker-compose

# 验证安装成功
docker-compose --version
# 输出类似:Docker Compose version v2.23.3

3.2 编写 docker-compose.yml

在项目目录创建 docker-compose.yml 文件,包含 SpringBoot 服务、MySQL 服务(示例依赖),配置持久化、网络、环境变量等生产级特性:

version: '3.8'  # Compose 文件版本,与 Docker 版本兼容(参考官方文档)
services:
  # SpringBoot 服务
  springboot-app:
    image: springboot-demo:v1.0.0  # 镜像名称:版本号,与构建时一致
    container_name: springboot-app  # 容器名称,便于管理
    restart: always  # 生产环境必备:容器异常退出时自动重启
    ports:
      - "8080:8080"  # 端口映射:主机端口:容器端口(生产环境建议避免使用默认端口,如 8080 可改为 80)
    environment:
      - SERVER_PORT=8080  # 覆盖应用端口
      - DB_HOST=mysql  # 数据库主机名(与下方 MySQL 服务名一致,Docker 内部可通过服务名访问)
      - DB_PORT=3306
      - DB_NAME=demo_db
      - DB_USER=demo_user
      - DB_PASS=Demo@123456  # 生产环境密码建议通过环境变量注入,避免硬编码
    volumes:
      - ./logs:/app/logs  # 日志持久化:主机目录./logs 挂载到容器 /app/logs(便于查看日志)
      - ./config:/app/config  # 配置文件挂载(生产环境可通过挂载修改配置,无需重新构建镜像)
    networks:
      - app-network  # 加入自定义网络,与其他服务隔离
    depends_on:
      - mysql  # 依赖 MySQL 服务,确保 MySQL 先启动

  # MySQL 服务(生产环境建议使用主从架构,此处为单节点示例)
  mysql:
    image: mysql:8.0.33
    container_name: mysql
    restart: always
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=Root@123456
      - MYSQL_DATABASE=demo_db  # 初始化数据库名称
      - MYSQL_USER=demo_user  # 初始化用户
      - MYSQL_PASSWORD=Demo@123456
    volumes:
      - mysql-data:/var/lib/mysql  # 数据持久化:避免容器删除后数据丢失
      - ./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql  # 初始化 SQL 脚本(创建表、插入初始数据)
    networks:
      - app-network
    command: --default-authentication-plugin=mysql_native_password  # 解决 MySQL 8.0 密码认证问题

# 自定义网络(桥接模式,隔离不同服务)
networks:
  app-network:
    driver: bridge

# 数据卷(持久化数据)
volumes:
  mysql-data:

3.3 服务启停与状态查看

# 启动所有服务(后台运行,-d 参数)
docker-compose up -d

# 查看服务状态
docker-compose ps
# 输出类似:
#       Name                     Command               State           Ports
# --------------------------------------------------------------------------------
# mysql            docker-entrypoint.sh --def ...   Up      0.0.0.0:3306->3306/tcp
# springboot-app   java -Xms512m -Xmx1024m -ja ...   Up      0.0.0.0:8080->8080/tcp

# 查看 SpringBoot 服务日志(实时日志,-f 参数)
docker-compose logs -f springboot-app

# 停止所有服务(保留容器和数据)
docker-compose stop

# 停止并删除容器、网络(数据卷不会删除)
docker-compose down

# 停止并删除容器、网络、数据卷(谨慎使用,会丢失持久化数据)
docker-compose down -v

3.4 生产环境额外配置

  • 配置 Docker Compose 开机自启: # 创建系统服务文件 vi /etc/systemd/system/docker-compose-app.service # 文件内容(注意修改 WorkingDirectory 为 docker-compose.yml 所在目录) [Unit] Description=Docker Compose App Service Requires=docker.service After=docker.service [Service] Type=simple WorkingDirectory=/usr/local/springboot-demo ExecStart=/usr/local/bin/docker-compose up -d ExecStop=/usr/local/bin/docker-compose down Restart=always [Install] WantedBy=multi-user.target # 启用并启动服务 systemctl enable docker-compose-app systemctl start docker-compose-app # 验证服务状态 systemctl status docker-compose-app

  • 日志轮转:生产环境日志会持续增长,需配置日志轮转(修改 /etc/logrotate.d/docker-compose-app),避免磁盘占满

四、问题排查与踩坑记录

4.1 典型问题及解决方案

问题 1:端口冲突(容器启动失败,提示 port is already allocated)

现象:执行 docker-compose up 时,提示 Error starting userland proxy: listen tcp4 0.0.0.0:8080: bind: address already in use

原因:主机 8080 端口已被其他进程占用

解决方案:

# 1. 查找占用端口的进程
netstat -tuln | grep 8080  # 或 lsof -i:8080
# 输出类似:tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1234/java

# 2. 若进程无用,停止进程
kill -9 1234  # 1234 为进程 ID

# 3. 若进程有用,修改 SpringBoot 服务的端口映射(修改 docker-compose.yml)
ports:
  - "8081:8080"  # 主机端口改为 8081,容器端口保持 8080

问题 2:权限不足(日志无法写入、配置文件无法读取)

现象:SpringBoot 服务启动后,日志文件未生成,或提示 Permission denied 无法读取配置文件

原因:Docker 挂载目录时,主机目录的权限不足,容器内非 root 用户无法读写

解决方案:

# 1. 查看主机挂载目录的权限
ls -ld ./logs
# 输出类似:drwxr-xr-x 2 root root 4096 Nov  1 10:00 ./logs(root 用户拥有权限)

# 2. 修改目录权限,允许其他用户读写(生产环境建议更精细的权限控制,而非 777)
chmod 777 -R ./logs ./config

# 3. (推荐)修改目录所有者为容器内的 appuser(需先知道 appuser 的 UID)
# 查看容器内 appuser 的 UID(进入容器执行)
docker exec -it springboot-app id appuser
# 输出类似:uid=1001(appuser) gid=1001(appgroup) groups=1001(appgroup)

# 4. 主机修改目录所有者
chown -R 1001:1001 ./logs ./config

问题 3:镜像构建失败(Maven 依赖下载超时)

现象:执行 docker build 时,Maven 下载依赖缓慢或超时,提示 Failed to transfer file...

原因:默认使用 Maven 中央仓库,国内网络访问缓慢

解决方案:在 pom.xml 中配置阿里云 Maven 镜像:

<repositories>
  <repository>
    <id>aliyunmaven</id>
    <url>https://maven.aliyun.com/repository/public</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </repository>
</repositories>
<pluginRepositories>
  <pluginRepository>
    <id>aliyunmaven</id>
    <url>https://maven.aliyun.com/repository/public</url>
    <releases>
      <enabled>true</enabled>
    </releases>
    <snapshots>
      <enabled>false</enabled>
    </snapshots>
  </pluginRepository>
</pluginRepositories>

4.2 验证部署效果

部署完成后,需从以下几个维度验证效果(生产环境必做):

  1. 验证容器运行状态: docker-compose ps # 确保所有服务 State 为 Up

  2. 验证接口可用性: 假设 SpringBoot 项目有一个健康检查接口 /actuator/health,执行以下命令验证:curl http://localhost:8080/actuator/health # 输出类似:{"status":"UP"} 即接口正常截图说明:打开浏览器访问 http://服务器公网IP:8080/actuator/health,页面显示{"status":"UP"},说明服务正常运行。

  3. 验证数据持久化: 1. 向 MySQL 数据库插入一条测试数据(通过项目接口或直接连接 MySQL);2. 执行 docker-compose down 停止服务,再执行 docker-compose up -d 重启服务;3. 查询数据是否存在,若存在则数据持久化成功。截图说明:通过 Navicat 等工具连接服务器 MySQL(地址:服务器公网IP,端口:3306,用户:demo_user),查询测试数据是否存在。

五、总结与拓展

5.1 核心总结

本文提供了一套生产环境可用的 Docker 部署 SpringBoot 项目完整流程,核心要点:

  • 环境准备:优先选择稳定的操作系统,正确安装 Docker 并配置开机自启;

  • 镜像构建:采用多阶段构建减小镜像体积,使用非 root 用户提升安全性,通过 .dockerignore 优化构建流程;

  • 容器编排:使用 Docker Compose 管理多容器服务,配置持久化、自动重启、自定义网络等生产级特性;

  • 问题排查:重点关注端口冲突、权限不足、依赖下载等典型问题,掌握日志查看、进程查询等排查技巧。

5.2 拓展学习资源

后续可拓展学习:Docker 镜像仓库(Harbor)搭建、Docker 容器监控(Prometheus + Grafana)、Kubernetes 容器编排(适用于大规模集群部署)。

posted @ 2026-01-07 15:32  AI设计栈  阅读(3)  评论(0)    收藏  举报