原生数据库备份:使用 Velero 实现 MySQL(StatefulSet 部署)的数据备份

一、引言:为什么需要 Velero 备份 StatefulSet 部署的 MySQL?

在云原生架构中,MySQL 常通过 StatefulSet 部署以保证有状态特性(固定网络标识、持久化存储),但其数据备份面临两大核心挑战:

  1. 存储与配置同步备份:需同时备份 MySQL 的 StatefulSet 配置(如启动参数、环境变量)与 PV 中的数据,避免恢复时 “有配置无数据” 或 “有数据无配置”;
  1. 有状态应用一致性:StatefulSet 的 PV 与 Pod 强绑定(如 mysql-data-mysql-0 对应 mysql-0 Pod),普通备份工具难以识别这种关联关系。

Velero 作为云原生备份工具,支持K8s 资源 + PV 数据一体化备份,能自动关联 StatefulSet 与 PV 的依赖关系,且支持定时备份、跨集群恢复,是解决 StatefulSet 部署 MySQL 备份的最优方案之一。

二、前置条件:环境准备与工具安装

2.1 基础环境要求

  • K8s 集群(1.20+,支持 StatefulSet 与 PV/PVC);
  • MySQL 已通过 StatefulSet 部署(示例:Namespace 为 mysql-ns,StatefulSet 名称为 mysql,PV 挂载目录为 /var/lib/mysql);
  • 备份存储后端(本文以 MinIO 为例,也可使用 AWS S3、阿里云 OSS 等);
  • 工具:kubectl(集群管理)、velero(客户端)。

2.2 安装 Velero

步骤 1:下载 Velero 客户端

# 下载对应版本(本文用 v1.12.1)

wget https://github.com/vmware-tanzu/velero/releases/download/v1.12.1/velero-v1.12.1-linux-amd64.tar.gz

tar -zxvf velero-v1.12.1-linux-amd64.tar.gz

mv velero-v1.12.1-linux-amd64/velero /usr/local/bin/

# 验证安装

velero version

步骤 2:部署 Velero 到 K8s 集群(对接 MinIO)
  1. 准备 MinIO 密钥文件 credentials-velero:

[default]

aws_access_key_id = minioadmin # MinIO 访问密钥

aws_secret_access_key = minioadmin # MinIO 密钥

  1. 执行安装命令(指定 MinIO 地址与备份桶):

velero install \

--provider aws \

--plugins velero/velero-plugin-for-aws:v1.9.0 \

--bucket velero-mysql-backup # MinIO 中创建的备份桶名

--secret-file ./credentials-velero \

--use-volume-snapshots=false # 若用 restic 备份 PV,设为 false

--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio-service:9000 # MinIO 服务地址

--namespace velero \

--create-namespace

  1. 验证 Velero 部署状态:

kubectl get pods -n velero

# 预期输出:velero-xxxx-xxxx 状态为 Running

三、核心原理:Velero 备份 StatefulSet MySQL 的逻辑

Velero 备份 StatefulSet 部署的 MySQL 分为两大阶段,确保 “配置 + 数据” 完整:

  1. K8s 资源备份:自动抓取与 MySQL 相关的 StatefulSet、Service、ConfigMap、Secret、PVC 等资源,生成 YAML 配置文件;
  1. PV 数据备份:通过 restic 工具(需提前配置)备份 PVC 挂载的 /var/lib/mysql 目录数据,或通过 CSI 快照备份 PV(需集群支持 CSI)。

关键关联逻辑:Velero 通过 PVC 的 ownerReferences 字段识别其与 StatefulSet 的绑定关系,确保恢复时 PV 能重新关联到对应的 StatefulSet Pod。

四、实操步骤:实现 MySQL 数据备份与验证

4.1 准备工作:确认 MySQL 环境状态

  1. 查看 StatefulSet 与 Pod 状态:

kubectl get statefulset mysql -n mysql-ns

kubectl get pods -n mysql-ns -l app=mysql # 示例标签:app=mysql

# 预期输出:mysql-0(单节点)或 mysql-0、mysql-1(主从)状态为 Running

  1. 确认 PV/PVC 关联关系:

kubectl get pvc -n mysql-ns # 查看 MySQL 的 PVC(如 mysql-data-mysql-0)

kubectl get pv | grep mysql-data-mysql-0 # 确认 PVC 绑定的 PV

  1. (可选)添加 Restic 备份权限(若用 restic 备份 PV):

给 MySQL 的 ServiceAccount 授予 restic 备份权限:


# restic-permissions.yaml

apiVersion: rbac.authorization.k8s.io/v1

kind: Role

metadata:

name: velero-restic-role

namespace: mysql-ns

rules:

- apiGroups: [""]

resources: ["pods", "pods/exec"]

verbs: ["get", "list", "create"]

---

apiVersion: rbac.authorization.k8s.io/v1

kind: RoleBinding

metadata:

name: velero-restic-rolebinding

namespace: mysql-ns

subjects:

- kind: ServiceAccount

name: default # MySQL 使用的 ServiceAccount(默认是 default)

namespace: mysql-ns

roleRef:

kind: Role

name: velero-restic-role

apiGroup: rbac.authorization.k8s.io


kubectl apply -f restic-permissions.yaml

4.2 执行全量备份:备份 MySQL 配置与数据

命令格式:

velero create backup <备份名> \

--namespace mysql-ns \

--include-resources statefulsets,services,configmaps,secrets,persistentvolumeclaims \

--include-namespaces mysql-ns \

--volume-snapshot-locations <快照位置> # 若用 CSI 快照,需指定;restic 可省略

--labels app=mysql-backup # 给备份打标签,便于筛选

实际执行示例:

velero create backup mysql-backup-20240520 \

--namespace mysql-ns \

--include-resources statefulsets,services,configmaps,secrets,persistentvolumeclaims \

--include-namespaces mysql-ns \

--labels app=mysql-backup

4.3 备份状态验证

  1. 查看备份进度:

velero get backups

# 预期输出:mysql-backup-20240520 状态为 Completed(约1-5分钟,取决于数据量)

  1. 查看备份详情(确认资源与数据已备份):

velero describe backup mysql-backup-20240520

# 关键检查点:

# - "Included Resources":包含 statefulsets/mysql、pvc/mysql-data-mysql-0 等

# - "Restic Backups":若用 restic,显示 "Completed"(数据备份成功)

  1. 验证 MinIO 中是否存在备份文件:

登录 MinIO 控制台,进入 velero-mysql-backup 桶,可看到 backups/mysql-backup-20240520 目录,包含备份的配置文件与数据文件。

五、关键补充:恢复测试与一致性保障

5.1 模拟故障:删除 MySQL 资源与数据

为验证备份有效性,模拟故障场景(删除 MySQL 的 StatefulSet 与 PVC):


# 删除 StatefulSet

kubectl delete statefulset mysql -n mysql-ns

# 删除 PVC(PV 会随 PVC 删除,若 PV 回收策略为 Delete)

kubectl delete pvc mysql-data-mysql-0 -n mysql-ns

5.2 从备份恢复 MySQL


velero create restore mysql-restore-20240520 \

--from-backup mysql-backup-20240520 \

--namespace mysql-ns

恢复验证:
  1. 查看恢复进度:

velero get restores

# 预期输出:mysql-restore-20240520 状态为 Completed

  1. 验证 MySQL 服务恢复:

# 查看 StatefulSet 与 Pod 恢复情况

kubectl get statefulset mysql -n mysql-ns # 状态为 Ready

kubectl get pods -n mysql-ns # mysql-0 状态为 Running

# 登录 MySQL 验证数据完整性

kubectl exec -it mysql-0 -n mysql-ns -- mysql -uroot -p

# 执行 SQL 查看数据(如查询测试表)

mysql> use testdb;

mysql> select * from test_table; # 预期输出:数据与备份前一致

5.3 数据一致性保障:避免备份时数据脏写

Velero 本身不处理应用层数据一致性,需结合 MySQL 特性优化:

  1. 备份前执行数据 flush:通过 Velero 的 pre-backup hook 在备份前锁定 MySQL 表,避免写入:

# mysql-pre-backup-hook.yaml

apiVersion: velero.io/v1

kind: Backup

metadata:

name: mysql-backup-with-hook

namespace: velero

spec:

includedNamespaces:

- mysql-ns

includedResources:

- statefulsets

- services

- configmaps

- secrets

- persistentvolumeclaims

hooks:

resources:

- name: mysql-pre-backup-hook

includedNamespaces:

- mysql-ns

labelSelector:

matchLabels:

app: mysql

pre:

exec:

command:

- /bin/sh

- -c

- "mysql -uroot -p$MYSQL_ROOT_PASSWORD -e 'FLUSH TABLES WITH READ LOCK;'" # 锁定表

onError: Fail # 若命令失败,备份终止

  1. 使用 MySQL 主从备份:若为 MySQL 主从集群(StatefulSet 多节点),可仅备份从库,避免影响主库业务。

六、优化与故障处理

6.1 定时备份:配置 Velero Schedule

避免手动备份遗漏,创建每日凌晨 2 点的定时备份:


velero create schedule mysql-daily-backup \

--schedule "0 2 * * *" \

--include-resources statefulsets,services,configmaps,secrets,persistentvolumeclaims \

--include-namespaces mysql-ns \

--retention 7 # 备份保留7天(自动删除过期备份)

查看定时任务:


velero get schedules

6.2 常见故障排查

  1. 备份失败:Restic 备份超时
    • 原因:MySQL 数据量过大,restic 备份超时;
    • 解决:调整 Velero 备份超时时间(修改 velero Deployment 的 --backup-timeout 参数,默认 1 小时),或分批次备份大文件。
  1. 恢复后 MySQL 启动失败
    • 原因:PV 数据权限异常(如 /var/lib/mysql 目录属主不是 mysql 用户);
    • 解决:恢复后执行命令修复权限:

kubectl exec -it mysql-0 -n mysql-ns -- chown -R mysql:mysql /var/lib/mysql

kubectl delete pod mysql-0 -n mysql-ns # 重启 Pod

  1. MinIO 连接失败
    • 原因:Velero 配置的 MinIO 地址或密钥错误;
    • 解决:重新创建 Velero 备份位置:

velero backup-location create minio-new \

--provider aws \

--config region=minio,s3ForcePathStyle="true",s3Url=http://minio-service:9000 \

--secret-file ./credentials-velero

七、总结

使用 Velero 备份 StatefulSet 部署的 MySQL,核心优势在于 **“配置 + 数据一体化备份” 与 “有状态关联自动识别”**,通过本文的实操步骤,可实现:

  1. 全量 / 定时备份 MySQL 配置与 PV 数据;
  1. 快速恢复故障环境,验证数据完整性;
  1. 结合 hooks 保障备份数据一致性。

后续可进一步扩展:集成 Prometheus 监控 Velero 备份状态,配置告警(如备份失败时通知运维),或实现跨集群备份(如从测试集群备份到生产集群恢复)。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐