云服务器运维与项目部署
13.8 自建数据库
Tip
使用云厂商的 RDS (Managed Database) 很贵,通常 $15/月起步。自己在 VPS 上装 MySQL 只要几块钱。但代价是:你需要自己负责备份和安全。
1. 为什么要学这个?
云平台 RDS 最低配也要 100元/月。你的小项目只有 10 个用户。 你想省钱,于是决定在 VPS 上用 Docker 起一个 MySQL。 这完全可行,但如果配置不当,你的数据可能会一夜归零。
2. 核心概念:持久化 (Persistence)
数据库最怕的是什么?丢数据。 在 Docker 里运行数据库,最核心的不是镜像,而是 Volume (数据卷)。
- 镜像坏了可以重拉。
- 容器删了可以重起。
- 但挂载的数据卷 (
/var/lib/mysql) 必须保存在宿主机的硬盘上。
3. 解决方案 (HOW)
3.1 使用 Docker Compose 部署 (推荐)
version: '3'
services:
mysql:
image: mysql:8.0
restart: always # 挂了自动重启
environment:
MYSQL_ROOT_PASSWORD: toughpassword # 强密码
MYSQL_DATABASE: mydb
ports:
- "127.0.0.1:3306:3306" # 关键:只监听本地,不暴露公网
volumes:
- ./mysql_data:/var/lib/mysql # 关键:数据持久化
注意 ports 里的 127.0.0.1。这意味着只有服务器自己能连,外网连不上。安全感拉满。
3.2 定时备份 (Backup)
光有持久化不够,万一硬盘坏了呢? 使用简单的 Shell 脚本备份:
# 每天凌晨 3 点导出 SQL
0 3 * * * docker exec mysql_container mysqldump -u root -p'pass' mydb > /backup/db_$(date +\%F).sql
进阶:把这个 SQL 文件上传到 AWS S3 / 阿里云 OSS。
3.3 部署架构图
graph TD
App["Web 应用"] -->|"Step 1: 内网连接"| DB["数据库容器 (MySQL)"]
DB --"Step 2: 写入"--> Volume["宿主机硬盘 (./data)"]
Cron["定时任务"] --"Step 3: 导出 SQL"--> Backup["备份文件 (.sql)"]
Backup --"Step 4: 上传"--> S3["云存储 (S3)"]
style DB fill:#c8e6c9,stroke:#2e7d32
style Volume fill:#e1bee7,stroke:#8e24aa
style S3 fill:#fff9c4,stroke:#fbc02d
4. 避坑指南
| ❌ 不要这样做 | ✅ 应该这样做 | 为什么 |
|---|---|---|
| 绑定 0.0.0.0 | 绑定 127.0.0.1 | 绑定 0.0.0.0 意味着谁都能试你的密码。除非必须远程连接,否则仅监听本地。 |
| 内存限制 | 考虑 SQLite | MySQL 8.0 至少需要 1GB 内存。如果是 512MB 的小鸡,建议用 SQLite 或 MySQL 5.7,否则无限 OOM (Out of Memory)。 |
| 无自动重启 | restart: always | 忘了写 restart: always,服务器重启后,发现数据库没跟随启动,网站报 502。 |
5. 真实案例
Story
2017年,GitLab 删库事件
2017年,GitLab 运维人员误删了生产数据库。 他们试图恢复备份,发现:
- 备份脚本其实报错了,生成的都是 0KB 的空文件。
- 从来没有人去检查过备份是否有效。 最后他们不得不恢复到 6 小时前的快照,这也导致了大量用户数据丢失。
Vibe 心法:未经恢复测试的备份等同于没有备份。自建数据库虽然省钱,却将数据安全的重担压在了运维脚本上。定期进行备份还原演练,确信每一个 .sql 文件都是救命的技术债,而不是空洞的安慰剂。
6. 本章小结
- 省钱有代价:自建省钱,但你通过花费时间(运维)来支付了这笔钱。
- 安全第一:不要暴露 3306 端口。
- S3 备份:把鸡蛋(数据)放到另一个篮子(云存储)里。