🚀 从本地到云端:我如何用 Docker 部署 Spring Boot + MySQL 项目的全过程实录
嘿,各位在代码世界里构筑梦想的伙伴们!👋
将我们在本地精心打造的 Java 项目,部署到远程的 Linux 服务器上,是每一位后端开发者都会面临的“最后一公里”。传统的方式(直接在服务器上运行 jar
包和安装数据库)虽然可行,但却面临着环境不一致、依赖管理混乱、迁移困难等诸多问题。
今天,我想和大家完整地分享一次我亲身经历的、使用 Docker 将一个 Spring Boot 项目 (productQualification.jar
) 及其依赖的 MySQL (My Structured Query Language) 数据库,完整地部署到远程 Ubuntu 服务器的全过程。
这不仅仅是一份操作指南,更是一次从“传统部署”迈向“现代化 DevOps (Development and Operations, 开发运维一体化)”的思维转变之旅。我们将看到,如何通过几个简单的 docker
命令,轻松地“一键启动”整个应用栈。
序章:两大“战场”介绍
我们的故事发生在两个“战场”:
- 开发电脑 (Mac): 这是我的源代码所在地,我在这里编写代码、修改配置、打包项目。
- 虚拟机服务器 (Ubuntu): IP (Internet Protocol, 互联网协议) 地址为
192.168.31.73
,这是我们项目的最终“归宿”。
第一幕:云端奠基 - 部署 MySQL 数据库容器
在部署我们的应用之前,首先要为它准备好“粮仓”——数据库。我们将使用 Docker 来运行一个 MySQL 5.6 的容器。
1. SSH (Secure Shell, 安全外壳协议) 登录服务器
我首先登录到我的 Ubuntu 服务器 192.168.31.73
。
2. 创建专属的“对话通道” - Docker 网络
为了让应用和数据库能够方便地相互“对话”,我为它们创建了一个专属的虚拟网络:
$ docker network create my-app-net
1a186067f7c8d0...
- 关键点: 在这个网络里的容器,可以通过容器名直接通信,无需关心 IP 地址。
3. “点火,发射!” - 启动 MySQL 容器
接下来是最激动人心的一步,用一条命令启动我们的数据库服务:
$ docker run -d \
--name mysql-db \
-p 3306:3306 \
-v /home/dgq/mysql-data:/var/lib/mysql \
--network my-app-net \
-e MYSQL_ROOT_PASSWORD=your_strong_password \
-e MYSQL_DATABASE=product_qualification \
mysql:5.6
这条命令就像发射火箭的指令,每一项参数都有其精确的含义:
-d
: 后台运行。--name mysql-db
: 命名容器为mysql-db
。这是我们应用连接数据库的“地址”。-p 3306:3306
: 将服务器的3306
端口映射到容器的3306
端口。-v ...
: 数据持久化!将服务器的/home/dgq/mysql-data
目录挂载到容器内部,确保数据库数据不会因容器删除而丢失。--network my-app-net
: 将容器加入我们创建的网络。-e ...
: 设置环境变量,初始化root
密码和数据库名。mysql:5.6
: 指定使用的镜像。
执行 docker ps
后,我看到 mysql-db
容器正在稳定运行,数据库地基已成功打下!
第二幕:本地备战 - 修改配置、编写图纸、打包上传
现在,轮到我们的主角——productQualification.jar
登场了。在部署前,我们需要完成三件关键事情:修改配置、编写“建筑图纸”(Dockerfile
)、打包并上传。
1. 修改数据库连接配置
我打开了项目的 application-test.yml
文件,将 datasource.url
中的主机名修改为我们刚刚启动的 MySQL 容器的名称 mysql-db
。
spring:
datasource:
# url: jdbc:mysql://localhost:3306/productQualification # 本地开发配置
url: jdbc:mysql://mysql-db:3306/product_qualification # Docker 环境配置
username: root
password: your_strong_password
- 关键点:
mysql-db
这个名字,现在就是数据库的“域名”。
2. 编写“建筑图纸” - Dockerfile
详解
Dockerfile
是一个文本文件,它包含了一系列指令,告诉 Docker 如何一步步地构建我们的应用镜像。我在 api
模块的根目录下创建了这个文件。
Dockerfile
:
# ----------------------------------
# 阶段 1: 选择基础环境
# ----------------------------------
# 使用一个官方的、包含 Java 8 运行环境(JRE)的基础镜像。
# eclipse-temurin:8-jre-jammy 是一个轻量、稳定且受良好支持的选择。
FROM eclipse-temurin:8-jre-jammy
# ----------------------------------
# 阶段 2: 准备工作区
# ----------------------------------
# 在容器内部创建一个名为 /app 的工作目录。
# 后续的所有命令都将在这个目录下执行。
WORKDIR /app
# ----------------------------------
# 阶段 3: 复制应用程序
# ----------------------------------
# 将我们打包好的 jar 包,从构建上下文(我们上传文件的目录)
# 复制到容器的 /app 目录中,并重命名为 app.jar,方便后续引用。
COPY productQualification.jar app.jar
# ----------------------------------
# 阶段 4: 声明端口
# ----------------------------------
# 告诉 Docker,这个容器在运行时,将会监听 8087 端口。
# 这本身不会自动映射端口,但它是一个重要的元数据声明。
EXPOSE 8087
# ----------------------------------
# 阶段 5: 定义启动命令
# ----------------------------------
# 这是容器启动时要执行的默认命令。
# 它等同于在终端里运行:java -jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
这份“图纸”清晰地定义了我们应用“集装箱”的每一个构建步骤,确保了无论在哪里构建,环境都是完全一致的。
3. 重新打包并“星际传送”
修改配置和创建 Dockerfile
后,我在项目根目录下运行 mvn clean package
重新打包,然后使用 scp
(Secure Copy) 命令,将最新的 productQualification.jar
和 Dockerfile
一起传送到了远程的 Ubuntu 服务器。
第三幕:云端施工 - 构建镜像、运行容器
回到 Ubuntu 服务器,开始最后的施工。
1. 构建应用的“集装箱” - docker build
我进入刚刚上传文件的目录,执行 docker build
命令:
$ cd /home/dgq/my-java-app
$ docker build -t product-qualification-app .
[+] Building 20.5s (8/8) FINISHED
...
当看到 FINISHED
时,我知道,我的应用已经被成功打包成了一个名为 product-qualification-app
的 Docker 镜像。
2. 应用升空 - docker run
最后一步,就是启动我们的应用容器,并将它也加入到 my-app-net
网络中。
docker run -d \
--name product-qualification-container \
-p 8087:8087 \
--network my-app-net \
--restart always \
product-qualification-app
终端返回了一长串容器 ID (Identifier),2a61ed61...
,宣告我们的应用已成功“升空”!
最终章:确认成功 - 聆听应用的“心跳”
容器启动了,但它是否真的在健康运行?我立刻使用 docker logs
命令,来查看应用的“心跳”——启动日志。
$ docker logs -f product-qualification-container
终端开始实时滚动输出 Spring Boot 的启动日志:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
...
:: Spring Boot :: (v2.1.1.RELEASE)
... INFO ... : The following profiles are active: test
... INFO ... : {dataSource-1} inited
Hibernate: create table admin ...
Hibernate: create table admin_mini_program ...
...
... INFO ... : Started ApiApplication in 18.543 seconds ...
----------------------------------------------------------
Application 'api' is running! ...
----------------------------------------------------------
当看到 Started ApiApplication...
这行日志时,我的心终于放下了。
{dataSource-1} inited
: Druid 数据源初始化成功。Hibernate: create table ...
: Hibernate 正在执行ddl-auto: update
,自动创建数据库表。这证明应用已经成功连接到了mysql-db
容器!
结论与反思
这次部署的成功,完美地展示了 Docker 带来的巨大优势:
- 环境隔离: 我不需要在我的 Ubuntu 服务器上手动安装 Java 8 或 MySQL。所有依赖都被各自打包在了独立的容器里。
- 服务发现: 通过 Docker 的自定义网络,我的应用仅通过一个简单的名称
mysql-db
就找到了数据库,无需关心复杂的 IP 地址。 - 部署标准化: 整个流程——上传、构建、运行——是完全标准化的,可以在任何安装了 Docker 的服务器上轻松复现。
- 易于管理: 通过
docker ps
,docker logs
等简单的命令,我可以轻松地管理和监控我的整个应用栈。
从本地的一堆源代码,到一个在云端稳定运行的、由多个容器组成的完整服务,Docker 为我们铺平了这条通往现代化部署的康庄大道。
Happy Dockering! 🐳✨
总结与图表分析 📊
📝 Docker 部署流程总结表
阶段 | 核心动作 | 关键命令 / 配置 | 目标 |
---|---|---|---|
1️⃣ 网络准备 | 创建 Docker 网络 | docker network create my-app-net | 为容器间通信建立桥梁 |
2️⃣ 部署数据库 | 运行 MySQL 容器 | docker run --name mysql-db ... | 启动并持久化数据库服务 |
3️⃣ 应用配置 | 修改 Spring Boot 配置 | url: jdbc:mysql://mysql-db:3306/... | 让应用能通过容器名找到数据库 |
4️⃣ 打包上传 | 重新打包并上传文件 | mvn package , scp | 将最新的应用代码和Dockerfile传到服务器 |
5️⃣ 构建镜像 | 编写 Dockerfile 并构建 | COPY app.jar , docker build -t ... | 将应用和其环境打包成一个标准单元 |
6️⃣ 启动应用 | 运行应用容器 | docker run --network my-app-net ... | 启动应用并连接到数据库网络 |
7️⃣ 验证 | 查看日志和访问 | docker logs , curl | 确认整个应用栈工作正常 |
🗺️ 流程图:从本地开发到服务器部署
🔄 时序图:应用容器如何连接到数据库容器
🚦 状态图:从代码到运行中服务的状态
🏛️ 类图:部署涉及的核心概念
🔗 实体关系图:最终部署架构
🧠 思维导图 (Markdown Format)
- 使用 Docker 部署 Spring Boot + MySQL 项目
- 🎯 目标
- 在远程 Ubuntu 服务器上,容器化部署整个应用栈
- 1️⃣ 准备数据库 (
mysql-db
容器)- 网络:
docker network create my-app-net
-> 为容器通信创建桥梁 - 数据持久化: 在宿主机创建目录
mkdir /home/dgq/mysql-data
- 启动:
docker run -d --name mysql-db -p 3306:3306 -v ... --network ... -e ... mysql:5.6
- 关键:
--name
用于服务发现,-v
用于持久化,--network
用于连接
- 关键:
- 网络:
- 2️⃣ 准备应用程序 (本地电脑)
- 修改配置:
- 文件:
application.yml
- 核心:
spring.datasource.url
的主机名改为mysql-db
- 文件:
- 打包:
mvn package
-> 生成包含新配置的productQualification.jar
- 创建
Dockerfile
:FROM eclipse-temurin:8-jre-jammy
COPY productQualification.jar app.jar
EXPOSE 8087
ENTRYPOINT ["java", "-jar", "app.jar"]
- 上传: 使用
scp
(Secure Copy, 安全拷贝) 将jar
包和Dockerfile
上传到服务器
- 修改配置:
- 3️⃣ 部署应用程序 (服务器)
- 构建镜像:
docker build -t product-qualification-app .
-> 根据Dockerfile
创建镜像 - 启动容器:
docker run -d --name ... -p 8087:8087 --network my-app-net ... product-qualification-app
- 关键:
--network my-app-net
确保应用能找到mysql-db
- 关键:
- 构建镜像:
- 4️⃣ 验证
- 检查容器:
docker ps
-> 确认mysql-db
和应用容器都在Up
状态 - 检查日志:
docker logs -f <应用容器名>
-> 查看 Spring Boot 启动日志,确认数据库连接成功 - 访问应用: 浏览器访问
http://服务器IP:8087
- 检查容器:
- 🎯 目标