主题
MySQL 高可用集群部署文档
环境:RKE2 v1.35.6(6 节点)|内部 Harbor
192.168.122.156:30000|NFS192.168.122.1:/mnt/xfs/rancher/mysql组件:MySQL 8.4.5 主从(1主2从)+ ProxySQL 2.7.3 读写分离(2副本)+ CronJob 每日备份 更新:2026-08-01
1. 架构
┌──────────────────────────────┐
应用 ───────► │ ProxySQL ×2(读写分离入口) │
│ mysql-proxysql.mysql:3306 │
└──────┬───────────┬───────────┘
写(HG10) │ │ 读(HG20)
▼ ▼
┌────────────┐ ┌──────────────────┐
│ Primary ×1 │→│ Secondary ×2 │ MySQL 8.4.5 异步复制
└────────────┘ └──────────────────┘
│
▼
NFS 192.168.122.1:/mnt/xfs/rancher/mysql(StorageClass: nfs-mysql)
备份: CronJob 每天 02:00(北京) mysqldump --single-transaction → NFS,保留 7 天| 组件 | 副本 | 高可用措施 |
|---|---|---|
| mysql-primary | 1 | 主从架构写节点天然单点,故障时手动提升从库(见操作文档) |
| mysql-secondary | 2 | 跨节点反亲和,读流量 Service 负载均衡 |
| mysql-proxysql | 2 | 跨节点反亲和 + PDB(minAvailable=1) |
| mysql-nfs-provisioner | 1 | 仅供给 PVC 时工作,短暂故障不影响运行 |
| mysql-backup | CronJob | 0 18 * * * UTC = 北京 02:00,保留 7 天 |
2. 镜像与 Chart(全部来自内部 Harbor)
国内环境无法直连 docker.io,所有物料经国内源(daocloud)同步至内部 Harbor:
| 内容 | 内部地址 | 来源 |
|---|---|---|
| MySQL 镜像 | mysql/mysql:8.4.5-debian-12-r0 | docker.m.daocloud.io/bitnamilegacy/mysql |
| ProxySQL 镜像 | mysql/proxysql:2.7.3 | docker.m.daocloud.io/proxysql/proxysql |
| MySQL chart | oci://…/charts/mysql:12.3.5 | oci://docker.m.daocloud.io/bitnamicharts/mysql |
| NFS provisioner chart | oci://…/charts/nfs-subdir-external-provisioner:4.0.18 | Harbor 已有 |
| NFS provisioner 镜像 | sig-storage/nfs-subdir-external-provisioner:v4.0.2 | Harbor 已有 |
节点已配置 registry mirror(
*→ Harbor),公开项目可匿名拉取,无需 imagePullSecret。
3. 前置准备
3.1 NFS 服务器导出(192.168.122.1)
bash
mkdir -p /mnt/xfs/rancher/mysql
echo '/mnt/xfs/rancher/mysql *(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports
exportfs -ra
showmount -e localhost # 确认 /mnt/xfs/rancher/mysql 在导出列表3.2 创建 Harbor 项目并同步物料
bash
# 创建公开项目 mysql(一次即可)
curl -u 'admin:xxx' -X POST 'http://192.168.122.156:30000/api/v2.0/projects' \
-H 'Content-Type: application/json' -d '{"project_name":"mysql","public":true}'
# 镜像 + chart 一键同步(需本机 skopeo/helm,凭据从环境变量传入)
export HARBOR_USER=admin HARBOR_PASS='xxx'
./deploy.sh sync4. 一键部署
交付目录 mysql/ 内容:
mysql/
├── deploy.sh # 一键部署脚本(all|sync|check)
├── mysql-values.yaml # bitnami mysql chart 参数(主从、存储、探针)
├── nfs-provisioner-values.yaml # 专用 StorageClass nfs-mysql 参数
├── proxysql.yaml # ProxySQL 读写分离(Secret/Deployment×2/Service/PDB)
├── backup.yaml # 备份 PVC + CronJob(保留 7 天)
├── .secrets.env # 全部密码(勿提交公共仓库)
└── README.md / 部署文档.md / 操作文档.mdbash
export KUBECONFIG=~/.kube/config-122.31
cd mysql/
./deploy.sh # 全量部署 + 验证脚本执行序列:前置检查(NFS 导出)→ 命名空间 → NFS provisioner → MySQL 主从 → ProxySQL + 备份 → 状态验证。 全部为 helm upgrade --install / kubectl apply,可重复执行。
手动分步部署(等价命令)
bash
export KUBECONFIG=~/.kube/config-122.31
kubectl create ns mysql
helm install mysql-nfs-provisioner \
oci://192.168.122.156:30000/charts/nfs-subdir-external-provisioner \
--version 4.0.18 --plain-http -n mysql -f nfs-provisioner-values.yaml
helm install mysql oci://192.168.122.156:30000/charts/mysql \
--version 12.3.5 --plain-http -n mysql -f mysql-values.yaml
kubectl apply -f proxysql.yaml -f backup.yaml5. 部署后验证
bash
kubectl -n mysql get pods -o wide # 6 个 Pod 全部 1/1 Running,分布在不同节点
# 主从复制:双从 IO/SQL 线程 Yes、延迟 0
kubectl -n mysql exec mysql-secondary-0 -c mysql -- mysql -uroot -p"$PW" \
-e "SHOW REPLICA STATUS\G" | grep -E 'IO_Running|SQL_Running|Seconds_Behind'
# 读写分离:经 ProxySQL 写入落主库;SELECT 落在 read_only=1 的从库
kubectl -n mysql exec mysql-primary-0 -c mysql -- \
mysql -h mysql-proxysql -uappuser -p"$APP_PW" appdb \
-e 'SELECT @@server_id, @@read_only;'
# 备份:手动触发一次
kubectl -n mysql create job --from=cronjob/mysql-backup mysql-backup-manual-$(date +%s)6. 关键设计决策与踩坑记录
- 独立 StorageClass
nfs-mysql:集群默认nfsSC 指向/mnt/xfs/rancher/uat1, 为满足/mnt/xfs/rancher/mysql路径要求,单独部署第二个 provisioner 实例。 - InnoDB redo log 损坏(MY-012960):NFS 上 InnoDB 首次初始化需 1~2 分钟, 默认 livenessProbe 会在初始化中途杀死 Pod,留下损坏的 redo log,此后无限 CrashLoop。 修复:宽松 startupProbe(90×10s=15 分钟预算)+ 清空数据重建。切勿缩短探针。
- bitnami 镜像下线:docker.io/bitnami 版本化 tag 已下线,改用
bitnamilegacy/mysql(chart 12.3.5 默认 tag8.4.5-debian-12-r0在 legacy 仓库中存在), chart 需加global.security.allowInsecureImages: true跳过镜像校验。 - ProxySQL admin 仅允许 localhost:管理接口 6032 不接受远程连接(ProxySQL 安全设计), 管理操作需在 pod 内执行。
- MySQL 选 8.4 LTS 而非 9.x Innovation:生产环境优先 LTS。
7. 应用接入
mysql-proxysql.mysql.svc.cluster.local:3306 统一入口(自动读写分离)
账号 appuser / 密码见 .secrets.env / 默认库 appdb