Vibe Tutorial
云服务器运维与项目部署

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 运维人员误删了生产数据库。 他们试图恢复备份,发现:

  1. 备份脚本其实报错了,生成的都是 0KB 的空文件。
  2. 从来没有人去检查过备份是否有效。 最后他们不得不恢复到 6 小时前的快照,这也导致了大量用户数据丢失。

Vibe 心法:未经恢复测试的备份等同于没有备份。自建数据库虽然省钱,却将数据安全的重担压在了运维脚本上。定期进行备份还原演练,确信每一个 .sql 文件都是救命的技术债,而不是空洞的安慰剂。


6. 本章小结

  1. 省钱有代价:自建省钱,但你通过花费时间(运维)来支付了这笔钱。
  2. 安全第一:不要暴露 3306 端口。
  3. S3 备份:把鸡蛋(数据)放到另一个篮子(云存储)里。