原创

个人博客工程化迁移实战:Docker 化、数据持久化与 HTTPS 架构落地


从传统部署到容器化架构:一次个人博客系统的工程化迁移实践

一次看似普通的服务器迁移,背后其实涉及:

  • Docker 容器化
  • MySQL 数据持久化
  • Nginx HTTPS 代理
  • 服务解耦
  • 运维恢复能力
  • 故障排查体系

这不仅是一次迁移,更是一次完整的工程化升级。


一、迁移背景

最近,将个人博客系统从旧云服务器迁移到了新的云环境。

迁移原因很简单:

原服务器生命周期结束,需要完成整体环境迁移。

但这次并不只是简单的数据复制。

而是借这个机会,对整个系统进行了:

容器化 + 工程化 + 服务解耦

最终目标:

  • 降低迁移成本
  • 提升系统可恢复能力
  • 提升部署一致性
  • 建立完整的运行环境
  • 减少环境依赖问题

二、旧架构存在的问题

最初博客系统结构:

SpringBoot + MySQL + Nginx

部署方式:

  • Jar 包直接后台运行
  • MySQL 裸机安装
  • Nginx 本地反向代理
  • 手工维护配置文件

虽然系统能够正常运行。

但随着时间推移,问题逐渐暴露。


1. 环境依赖严重

例如:

  • Java 版本
  • MySQL 版本
  • Nginx 配置
  • 系统环境变量

都强依赖当前服务器。

导致:

迁移成本极高

2. 服务缺乏隔离

所有服务运行在宿主机:

Nginx
MySQL
SpringBoot

带来的问题:

  • 配置污染
  • 端口冲突
  • 环境耦合
  • 运维复杂

3. 数据安全风险高

数据库直接部署在宿主机。

缺乏:

  • 数据卷管理
  • 容器持久化
  • 标准化备份流程

一旦误操作:

恢复成本极高

三、为什么选择 Docker

这次迁移核心目标之一:

全部容器化。

最终采用:

Docker + Nginx + SpringBoot + MySQL

架构。


Docker 带来的核心收益

能力 提升
环境一致性 开发/测试/生产统一
服务隔离 避免环境污染
可迁移性 极大提升
部署效率 明显提升
运维成本 明显降低
服务管理 更标准化

四、数据库迁移过程

数据库迁移,是整个过程中最容易出问题的一部分。


五、第一次踩坑:mysqldump 导出失败

最开始直接使用:

mysqldump

导出数据库。

结果直接报错:

Lost connection to MySQL server during query

问题本质

本质原因:

大表导出过程中连接超时。

默认 mysqldump 会一次性读取大量数据。

公网环境下:

  • 网络波动
  • 查询时间过长
  • 服务端超时

都可能导致:

导出中断

解决方案

最终采用:

mysqldump --single-transaction --quick

参数分析

1. --single-transaction

作用:

保证导出期间事务一致性

避免锁表。

适用于:

InnoDB

2. --quick

作用:

边读边写

避免一次性加载全部数据。

降低:

  • 内存占用
  • 网络超时风险

六、SQL 导入再次踩坑

导出成功后。

开始导入 SQL。

结果再次报错:

SQL [1064]

第一反应:

SQL 语法错误

但实际上并不是。


真正原因

mysqldump 导出的 SQL 文件中包含:

/*!40101 SET NAMES utf8 */;

这种:

MySQL 条件注释语法

普通 SQL 执行模式无法正确解析。


最终解决方案

改用:

执行 SQL Script

而不是:

执行单条 SQL

问题解决。


七、最危险的一次事故:误删 MySQL 容器

在清理 Docker 环境时。

执行了:

docker rm -f $(docker ps -aq)
docker rmi -f $(docker images -aq)

结果:

MySQL 容器被直接删除。


当时最大的误判

第一反应:

数据库没了

但后面检查数据目录后发现:

.ibd
.frm

文件依旧存在。

这说明:

数据实际上并没有丢。


八、真正理解 Docker 数据持久化

原因在于:

之前已经做了:

-v /data/mysql:/var/lib/mysql

宿主机目录挂载。


九、Docker 最核心的理念之一

这次事故后。

真正理解了一件事:

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;

数据全部恢复。


十一、Nginx + HTTPS 架构

数据库恢复后。

开始重新构建 HTTPS 链路。


整体结构

Client
    ↓
HTTPS
    ↓
Nginx
    ↓
SpringBoot
    ↓
MySQL

十二、Nginx 反向代理配置

核心配置:

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;
    }
}

十三、为什么会出现 504 Gateway Time-out

HTTPS 配置完成后。

浏览器返回:

504 Gateway Time-out

第一反应

最开始怀疑:

  • SSL 证书错误
  • DNS 问题
  • 防火墙问题
  • Nginx 配置错误

但后面排查发现:

实际是后端服务没有正常响应。


十四、504 的本质

Nginx 工作链路:

Client
    ↓
Nginx
    ↓
proxy_pass
    ↓
SpringBoot

当前状态:

  • Nginx 正常
  • HTTPS 正常
  • DNS 正常

但:

SpringBoot 无法正常返回响应

于是:

Nginx 超时

最终返回:

504

十五、根因定位

继续排查 SpringBoot 日志。

最终发现:

数据库当时尚未恢复完成。

SpringBoot 启动阶段:

数据库连接失败

导致应用阻塞。

因此:

Nginx 无法拿到后端响应

十六、最终架构

迁移完成后。

整体结构:

Cloud Server
    ↓
Docker Engine
    ↓
Nginx Container
    ↓
SpringBoot Container
    ↓
MySQL Container

十七、当前系统能力

能力 状态
HTTPS 已完成
Docker 化 已完成
数据持久化 已完成
服务解耦 已完成
容器隔离 已完成
可迁移性 已提升
恢复能力 已提升

十八、这次迁移最大的收获

其实最大的收获。

并不是:

  • Docker 命令
  • Nginx 配置
  • HTTPS
  • MySQL

而是:

开始真正理解一个完整系统是如何运行的。

以前更多是:

知道怎么部署

现在逐渐变成:

知道为什么这样设计

十九、真正的工程化思维

这次迁移后。

开始真正意识到:

一个系统真正重要的。

不是:

“能运行”

而是:

“可恢复”
“可迁移”
“可维护”
“可扩展”

二十、总结

表面上。

这只是一次:

服务器迁移

但实际上:

是一次完整的工程化升级。

从:

项目能跑

逐渐转向:

系统可维护

很多时候。

真正让人成长的。

并不是:

教程

而是:

凌晨两点发现数据库容器被删之后,
还能冷静恢复系统的那一刻。
总结