Docker部署SpringBoot项目(图文详解)——从零到上线保姆级教程
在传统部署方式中,我们需要在服务器上安装JDK、配置环境变量、手动上传jar包、编写启动脚本……流程繁琐且容易出错。对比项传统部署Docker部署环境一致性❌ 开发/测试/生产环境不一致✅ 镜像保证完全一致部署速度慢(手动配置)快(一键启动)资源隔离❌ 进程级别✅ 容器级别隔离扩缩容困难简单(docker-compose scale)回滚复杂秒级回滚(切换镜像版本)本文将手把手带你完成Docker
📋 文章目录
- 前言
- 环境准备
- 创建SpringBoot项目
- 项目打包
- Docker安装(CentOS)
- 编写Dockerfile
- 构建Docker镜像
- 运行Docker容器
- Docker Compose编排(进阶)
- 常见问题与排坑
- 总结
一、前言
在传统部署方式中,我们需要在服务器上安装JDK、配置环境变量、手动上传jar包、编写启动脚本……流程繁琐且容易出错。
Docker的优势:
| 对比项 | 传统部署 | Docker部署 |
|---|---|---|
| 环境一致性 | ❌ 开发/测试/生产环境不一致 | ✅ 镜像保证完全一致 |
| 部署速度 | 慢(手动配置) | 快(一键启动) |
| 资源隔离 | ❌ 进程级别 | ✅ 容器级别隔离 |
| 扩缩容 | 困难 | 简单(docker-compose scale) |
| 回滚 | 复杂 | 秒级回滚(切换镜像版本) |
本文将手把手带你完成Docker部署SpringBoot项目的全流程。
二、环境准备
开发环境:
├── JDK 17(或 JDK 8/11 均可)
├── Maven 3.8+
├── Spring Boot 3.2.x(或 2.7.x)
├── IDEA 2023+
└── Docker 24+
服务器环境:
├── CentOS 7.9 / Ubuntu 22.04
├── Docker 24+
└── 开放端口:8080
三、创建SpringBoot项目
3.1 使用Spring Initializr创建项目
IDEA → New Project → Spring Initializr
Group: com.example
Artifact: docker-demo
Java: 17
依赖选择: Spring Web
3.2 编写一个测试接口
package com.example.dockerdemo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HelloController {
@GetMapping("/hello")
public Map<String, Object> hello() {
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "Docker部署SpringBoot成功!");
result.put("time", LocalDateTime.now().toString());
return result;
}
@GetMapping("/health")
public String health() {
return "UP";
}
}
3.3 配置 application.yml
server:
port: 8080
spring:
application:
name: docker-demo
# 日志配置
logging:
level:
root: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
3.4 本地验证
启动项目,访问 http://localhost:8080/hello
{
"code": 200,
"message": "Docker部署SpringBoot成功!",
"time": "2024-12-20T10:30:00"
}
✅ 本地运行正常,接下来准备打包。
四、项目打包
4.1 确认 pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>docker-demo</artifactId>
<version>1.0.0</version>
<!-- ⚠️ 必须是jar包方式 -->
<packaging>jar</packaging>
<name>docker-demo</name>
<properties>
<java.version>17</java.version>
</properties>
<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>
<!-- ⚠️ 指定最终jar包名称,方便Dockerfile引用 -->
<configuration>
<finalName>docker-demo</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.2 执行Maven打包
# 方式一:命令行打包
mvn clean package -DskipTests
# 方式二:IDEA中操作
# 右侧 Maven面板 → Lifecycle → clean → package
打包成功后,在 target/ 目录下生成:
target/
└── docker-demo.jar ← 这就是我们需要的文件
4.3 验证jar包
java -jar target/docker-demo.jar
✅ 确认jar包可以独立运行后,再进行Docker部署。
五、Docker安装(CentOS 7)
如果服务器已安装Docker,可跳过本节。
5.1 卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
5.2 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
5.3 设置阿里云镜像源
sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
5.4 安装Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io
5.5 启动Docker
# 启动
sudo systemctl start docker
# 开机自启
sudo systemctl enable docker
# 验证安装
docker --version
# Docker version 24.0.7, build afdd53b
5.6 配置镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
⚠️ 注意:2024年起国内部分镜像源已失效,请根据实际情况选择可用源,或使用代理。
5.7 验证Docker
docker run hello-world
出现 Hello from Docker! 即安装成功。
六、编写Dockerfile
6.1 项目结构
docker-demo/
├── src/
├── target/
│ └── docker-demo.jar
├── Dockerfile ← 新建
├── .dockerignore ← 新建
└── pom.xml
6.2 基础版Dockerfile
# ============================================
# 基础版 Dockerfile
# ============================================
# 基础镜像:使用OpenJDK 17(精简版)
FROM openjdk:17-jdk-slim
# 作者信息
LABEL maintainer="your-email@example.com"
LABEL description="SpringBoot Docker Demo"
LABEL version="1.0.0"
# 设置工作目录
WORKDIR /app
# 复制jar包到容器中
COPY target/docker-demo.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
6.3 ⭐ 生产级Dockerfile(推荐)
# ============================================
# 生产级 Dockerfile(推荐使用)
# ============================================
# -------- 第一阶段:构建阶段 --------
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /build
COPY pom.xml .
# 先下载依赖(利用Docker缓存层)
RUN mvn dependency:go-offline -B
COPY src ./src
RUN mvn clean package -DskipTests -B
# -------- 第二阶段:运行阶段 --------
FROM eclipse-temurin:17-jre-alpine
LABEL maintainer="your-email@example.com"
# 创建非root用户(安全最佳实践)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# 从构建阶段复制jar包
COPY --from=builder /build/target/docker-demo.jar app.jar
# 设置文件权限
RUN chown appuser:appgroup app.jar
# 切换到非root用户
USER appuser
# 暴露端口
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
# JVM优化参数
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError"
# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar app.jar"]
生产级Dockerfile的优势:
✅ 多阶段构建 → 镜像体积更小(从 600MB → 200MB)
✅ 非root用户 → 安全性更高
✅ 健康检查 → 自动监控容器状态
✅ JVM参数 → 内存可控,避免OOM
✅ 依赖缓存 → 加速重复构建
6.4 .dockerignore 文件
.git
.gitignore
.idea
*.iml
*.md
.DS_Store
target/*.jar.original
七、构建Docker镜像
7.1 上传文件到服务器
# 方式一:scp上传整个项目(使用生产级Dockerfile时)
scp -r ./docker-demo root@your-server-ip:/opt/
# 方式二:仅上传jar包和Dockerfile(使用基础版Dockerfile时)
scp target/docker-demo.jar root@your-server-ip:/opt/docker-demo/
scp Dockerfile root@your-server-ip:/opt/docker-demo/
7.2 构建镜像
cd /opt/docker-demo
# 构建镜像(注意最后有个点 ".")
docker build -t docker-demo:1.0.0 .
构建过程输出:
[+] Building 45.2s (12/12) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load .dockerignore 0.0s
=> [builder 1/5] FROM maven:3.9-eclipse-temurin-17 10.2s
=> [builder 2/5] WORKDIR /build 0.1s
=> [builder 3/5] COPY pom.xml . 0.1s
=> [builder 4/5] RUN mvn dependency:go-offline -B 20.5s
=> [builder 5/5] COPY src ./src 0.1s
=> [builder 6/6] RUN mvn clean package -DskipTests -B 8.3s
=> [stage-1 1/4] FROM eclipse-temurin:17-jre-alpine 3.2s
=> [stage-1 2/4] COPY --from=builder ... 0.1s
=> exporting to image 0.3s
=> => naming to docker.io/library/docker-demo:1.0.0 0.0s
✅ 构建成功!
7.3 查看镜像
docker images
# 输出:
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-demo 1.0.0 a1b2c3d4e5f6 30 seconds ago 198MB
💡 多阶段构建后镜像仅 198MB,而单阶段构建通常在 500-700MB。
八、运行Docker容器
8.1 基础运行
docker run -d \
--name docker-demo \
-p 8080:8080 \
docker-demo:1.0.0
参数说明:
-d 后台运行
--name 容器名称
-p 8080:8080 端口映射(宿主机端口:容器端口)
docker-demo:1.0.0 镜像名:标签
8.2 ⭐ 生产级运行命令
docker run -d \
--name docker-demo \
--restart=always \
-p 8080:8080 \
-v /opt/docker-demo/logs:/app/logs \
-v /etc/localtime:/etc/localtime:ro \
-e SPRING_PROFILES_ACTIVE=prod \
-e JAVA_OPTS="-Xms512m -Xmx1024m" \
--memory=1024m \
--cpus=1.0 \
docker-demo:1.0.0
参数详解:
--restart=always 容器异常退出自动重启
-v .../logs:/app/logs 日志目录挂载到宿主机(持久化)
-v /etc/localtime:... 同步宿主机时区(解决时间差8小时问题)
-e SPRING_PROFILES_ACTIVE 指定Spring运行环境
-e JAVA_OPTS 覆盖JVM参数
--memory=1024m 限制容器最大内存
--cpus=1.0 限制CPU使用
8.3 验证部署
# 1. 查看容器状态
docker ps
# 输出:
CONTAINER ID IMAGE STATUS PORTS NAMES
f7a8b9c0d1e2 docker-demo:1.0.0 Up 30 seconds 0.0.0.0:8080->8080/tcp docker-demo
# 2. 查看启动日志
docker logs -f docker-demo
# 输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.2.1)
2024-12-20 10:30:00 [main] INFO c.e.d.DockerDemoApplication - Started in 2.345 seconds
# 3. 测试接口
curl http://localhost:8080/hello
# 输出:
{"code":200,"message":"Docker部署SpringBoot成功!","time":"2024-12-20T10:30:15"}
# 4. 健康检查
docker inspect --format='{{.State.Health.Status}}' docker-demo
# 输出:healthy
✅ 部署成功! 外网访问:
http://服务器公网IP:8080/hello
九、Docker Compose编排(进阶)
实际项目通常需要 SpringBoot + MySQL + Redis 一起部署。
9.1 项目结构
docker-demo/
├── docker-compose.yml ← 编排文件
├── Dockerfile
├── src/
├── pom.xml
└── config/
└── mysql/
└── init.sql ← 数据库初始化脚本
9.2 docker-compose.yml
version: '3.8'
services:
# ==================== SpringBoot应用 ====================
app:
build:
context: .
dockerfile: Dockerfile
container_name: docker-demo-app
restart: always
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/demo_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=root123456
- SPRING_REDIS_HOST=redis
- SPRING_REDIS_PORT=6379
- SPRING_REDIS_PASSWORD=redis123456
- JAVA_OPTS=-Xms512m -Xmx1024m
volumes:
- ./logs:/app/logs
- /etc/localtime:/etc/localtime:ro
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
deploy:
resources:
limits:
memory: 1024M
cpus: '1.0'
# ==================== MySQL ====================
mysql:
image: mysql:8.0
container_name: docker-demo-mysql
restart: always
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=root123456
- MYSQL_DATABASE=demo_db
- MYSQL_CHARSET=utf8mb4
- TZ=Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./config/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql
command: --default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot123456"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
networks:
- app-network
# ==================== Redis ====================
redis:
image: redis:7-alpine
container_name: docker-demo-redis
restart: always
ports:
- "6379:6379"
command: redis-server --requirepass redis123456 --appendonly yes
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "redis123456", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# ==================== 数据卷 ====================
volumes:
mysql-data:
driver: local
redis-data:
driver: local
# ==================== 网络 ====================
networks:
app-network:
driver: bridge
9.3 数据库初始化脚本
-- config/mysql/init.sql
CREATE TABLE IF NOT EXISTS `user` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
INSERT INTO `user` (`username`, `email`) VALUES
('admin', 'admin@example.com'),
('test', 'test@example.com');
9.4 application-prod.yml
server:
port: 8080
spring:
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 20
minimum-idle: 5
data:
redis:
host: ${SPRING_REDIS_HOST}
port: ${SPRING_REDIS_PORT}
password: ${SPRING_REDIS_PASSWORD}
timeout: 5000ms
9.5 一键启动
# 构建并启动所有服务
docker-compose up -d --build
# 查看所有服务状态
docker-compose ps
# 输出:
NAME STATUS PORTS
docker-demo-app Up 30 seconds (healthy) 0.0.0.0:8080->8080/tcp
docker-demo-mysql Up 45 seconds (healthy) 0.0.0.0:3306->3306/tcp
docker-demo-redis Up 45 seconds (healthy) 0.0.0.0:6379->6379/tcp
# 查看应用日志
docker-compose logs -f app
# 停止所有服务
docker-compose down
# 停止并删除数据卷(⚠️ 会删除数据库数据)
docker-compose down -v
十、常见问题与排坑
❌ 问题1:容器启动后立即退出
# 查看退出日志
docker logs docker-demo
# 常见原因:
# 1. jar包损坏 → 重新打包
# 2. JDK版本不匹配 → 检查Dockerfile中的基础镜像版本
# 3. 端口被占用 → netstat -tlnp | grep 8080
❌ 问题2:时区差8小时
# 解决方案一:挂载宿主机时区
-v /etc/localtime:/etc/localtime:ro
# 解决方案二:设置环境变量
-e TZ=Asia/Shanghai
# 解决方案三:Dockerfile中设置
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
❌ 问题3:容器内无法连接MySQL/Redis
# 错误示例:使用localhost
spring.datasource.url=jdbc:mysql://localhost:3306/demo_db ❌
# 正确写法:使用服务名(docker-compose中定义的service名)
spring.datasource.url=jdbc:mysql://mysql:3306/demo_db ✅
# 或使用宿主机IP
spring.datasource.url=jdbc:mysql://172.17.0.1:3306/demo_db ✅
❌ 问题4:镜像体积过大
# 查看镜像大小
docker images
# 优化方案对比:
# openjdk:17 → 471MB ❌
# openjdk:17-jdk-slim → 409MB
# eclipse-temurin:17-jre-alpine → 198MB ✅(推荐)
# 使用多阶段构建进一步优化(见第六节生产级Dockerfile)
❌ 问题5:构建缓存失效导致速度慢
# 优化技巧:先复制pom.xml下载依赖,再复制源码
# 这样只要pom.xml不变,依赖层就会使用缓存
COPY pom.xml .
RUN mvn dependency:go-offline ← 这一层会被缓存
COPY src ./src
RUN mvn package ← 只有源码变化才重新构建
十一、常用Docker运维命令速查表
# ==================== 镜像操作 ====================
docker images # 查看所有镜像
docker build -t name:tag . # 构建镜像
docker rmi image_id # 删除镜像
docker image prune -a # 清理无用镜像
# ==================== 容器操作 ====================
docker ps # 查看运行中的容器
docker ps -a # 查看所有容器(含停止的)
docker start container_name # 启动容器
docker stop container_name # 停止容器
docker restart container_name # 重启容器
docker rm container_name # 删除容器
docker rm -f $(docker ps -aq) # ⚠️ 删除所有容器
# ==================== 日志与调试 ====================
docker logs -f container_name # 实时查看日志
docker logs --tail 100 container_name # 查看最后100行日志
docker exec -it container_name /bin/sh # 进入容器
docker stats # 查看资源占用
docker inspect container_name # 查看容器详情
# ==================== Docker Compose ====================
docker-compose up -d # 后台启动
docker-compose up -d --build # 重新构建并启动
docker-compose down # 停止并删除
docker-compose logs -f service_name # 查看某个服务日志
docker-compose restart service_name # 重启某个服务
docker-compose ps # 查看服务状态
十二、完整部署流程总结
┌─────────────────────────────────────────────────────┐
│ 本地开发环境 │
│ │
│ 1. 编写代码 → 2. 本地测试 → 3. mvn clean package │
│ │
└─────────────────┬───────────────────────────────────┘
│ 上传到服务器
▼
┌─────────────────────────────────────────────────────┐
│ 服务器环境 │
│ │
│ 4. 编写Dockerfile │
│ │ │
│ ▼ │
│ 5. docker build -t app:1.0.0 . │
│ │ │
│ ▼ │
│ 6. docker run -d -p 8080:8080 app:1.0.0 │
│ │ │
│ ▼ │
│ 7. 访问 http://IP:8080/hello ✅ │
│ │
└─────────────────────────────────────────────────────┘
写在最后
本文从零开始,完整介绍了Docker部署SpringBoot项目的全过程:
- ✅ 基础部署:Dockerfile + docker run
- ✅ 生产优化:多阶段构建、非root用户、健康检查、JVM调优
- ✅ 编排部署:Docker Compose管理 SpringBoot + MySQL + Redis
- ✅ 排坑指南:时区、网络、镜像体积等常见问题
📌 觉得有用的话,记得点赞👍收藏⭐关注🔔三连!有问题欢迎评论区交流!
推荐阅读:
- 《Nginx反向代理+Docker部署SpringBoot实现HTTPS》
- 《Jenkins+Docker实现SpringBoot自动化部署(CI/CD)》
- 《Docker部署微服务架构全流程实战》
- 《Kubernetes(K8s)部署SpringBoot进阶指南》
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)