一次看似普通的服务器迁移,背后其实涉及:
- Docker 容器化
- MySQL 数据持久化
- Nginx HTTPS 代理
- 服务解耦
- 运维恢复能力
- 故障排查体系
这不仅是一次迁移,更是一次完整的工程化升级。
最近,将个人博客系统从旧云服务器迁移到了新的云环境。
迁移原因很简单:
原服务器生命周期结束,需要完成整体环境迁移。
但这次并不只是简单的数据复制。
而是借这个机会,对整个系统进行了:
容器化 + 工程化 + 服务解耦
最终目标:
最初博客系统结构:
SpringBoot + MySQL + Nginx
部署方式:
虽然系统能够正常运行。
但随着时间推移,问题逐渐暴露。
例如:
都强依赖当前服务器。
导致:
迁移成本极高
所有服务运行在宿主机:
Nginx
MySQL
SpringBoot
带来的问题:
数据库直接部署在宿主机。
缺乏:
一旦误操作:
恢复成本极高
这次迁移核心目标之一:
全部容器化。
最终采用:
Docker + Nginx + SpringBoot + MySQL
架构。
| 能力 | 提升 |
|---|---|
| 环境一致性 | 开发/测试/生产统一 |
| 服务隔离 | 避免环境污染 |
| 可迁移性 | 极大提升 |
| 部署效率 | 明显提升 |
| 运维成本 | 明显降低 |
| 服务管理 | 更标准化 |
数据库迁移,是整个过程中最容易出问题的一部分。
最开始直接使用:
mysqldump
导出数据库。
结果直接报错:
Lost connection to MySQL server during query
本质原因:
大表导出过程中连接超时。
默认 mysqldump 会一次性读取大量数据。
公网环境下:
都可能导致:
导出中断
最终采用:
mysqldump --single-transaction --quick
作用:
保证导出期间事务一致性
避免锁表。
适用于:
InnoDB
作用:
边读边写
避免一次性加载全部数据。
降低:
导出成功后。
开始导入 SQL。
结果再次报错:
SQL [1064]
第一反应:
SQL 语法错误
但实际上并不是。
mysqldump 导出的 SQL 文件中包含:
/*!40101 SET NAMES utf8 */;
这种:
MySQL 条件注释语法
普通 SQL 执行模式无法正确解析。
改用:
执行 SQL Script
而不是:
执行单条 SQL
问题解决。
在清理 Docker 环境时。
执行了:
docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)
结果:
MySQL 容器被直接删除。
第一反应:
数据库没了
但后面检查数据目录后发现:
.ibd
.frm
文件依旧存在。
这说明:
数据实际上并没有丢。
原因在于:
之前已经做了:
-v /data/mysql:/var/lib/mysql
宿主机目录挂载。
这次事故后。
真正理解了一件事:
Container 是临时的
Data 才是核心资产
也就是说:
| 内容 | 生命周期 |
|---|---|
| Container | 可随时删除 |
| Image | 可重新构建 |
| Data Volume | 必须持久化 |
因为:
容器不是数据库
容器只是:
运行环境
真正的数据:
必须独立存在。
否则:
删除容器 = 删除数据
这是生产环境里非常危险的设计。
重新启动 MySQL:
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=****** \
-v /data/mysql:/var/lib/mysql \
mysql:5.7
启动后:
SHOW DATABASES;
数据全部恢复。
数据库恢复后。
开始重新构建 HTTPS 链路。
Client
↓
HTTPS
↓
Nginx
↓
SpringBoot
↓
MySQL
核心配置:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/nginx/ssl/server.pem;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://blog-service:8081;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
HTTPS 配置完成后。
浏览器返回:
504 Gateway Time-out
最开始怀疑:
但后面排查发现:
实际是后端服务没有正常响应。
Nginx 工作链路:
Client
↓
Nginx
↓
proxy_pass
↓
SpringBoot
当前状态:
但:
SpringBoot 无法正常返回响应
于是:
Nginx 超时
最终返回:
504
继续排查 SpringBoot 日志。
最终发现:
数据库当时尚未恢复完成。
SpringBoot 启动阶段:
数据库连接失败
导致应用阻塞。
因此:
Nginx 无法拿到后端响应
迁移完成后。
整体结构:
Cloud Server
↓
Docker Engine
↓
Nginx Container
↓
SpringBoot Container
↓
MySQL Container
| 能力 | 状态 |
|---|---|
| HTTPS | 已完成 |
| Docker 化 | 已完成 |
| 数据持久化 | 已完成 |
| 服务解耦 | 已完成 |
| 容器隔离 | 已完成 |
| 可迁移性 | 已提升 |
| 恢复能力 | 已提升 |
其实最大的收获。
并不是:
而是:
开始真正理解一个完整系统是如何运行的。
以前更多是:
知道怎么部署
现在逐渐变成:
知道为什么这样设计
这次迁移后。
开始真正意识到:
一个系统真正重要的。
不是:
“能运行”
而是:
“可恢复”
“可迁移”
“可维护”
“可扩展”
表面上。
这只是一次:
服务器迁移
但实际上:
是一次完整的工程化升级。
从:
项目能跑
逐渐转向:
系统可维护
很多时候。
真正让人成长的。
并不是:
教程
而是:
凌晨两点发现数据库容器被删之后,
还能冷静恢复系统的那一刻。