如何使用Helm在K8S上配置StatefulSet和PVC部署MySQL主从集群?
- 内容介绍
- 文章标签
- 相关推荐
本文共计955个文字,预计阅读时间需要4分钟。
直接说结论:
为什么必须用 StatefulSet 而不是 Deployment
MySQL 主从依赖稳定的网络标识(如 mysql-0.mysql-service)、有序启停、以及每个实例独占持久卷。Deployment 无法保证 Pod 名称固定、无法按序创建、也无法为每个副本绑定唯一 PVC —— 这会导致:
-
mysql-1启动时连不上mysql-0(DNS 解析失败或地址漂移) - 两个从库挂载同一份 PVC,造成数据损坏
- 滚动更新时主库被杀,复制链断裂且无法自动恢复
Bitnami Chart 中 architecture: "replication" 模式会自动启用 StatefulSet,但前提是 primary.replicaCount 和 secondary.replicaCount 都设为 1(非 0),且 storageClass 支持动态供给或已预置对应数量的 PV。
StatefulSet 下 PVC 的正确配置方式
主从 Pod 各需独立 PVC,不能共用 storageClass 的同一个 volumeClaimTemplate 名称(否则会被当成同一份存储)。关键点:
- 主库 PVC 名由
primary.persistence.storageClass+primary.persistence.size决定,模板名固定为data - 从库 PVC 名由
secondary.persistence.storageClass决定 —— 必须和主库不同,否则调度器可能复用同一 PV - 若用 NFS,建议主库用
nfs-mysql-primary,从库用nfs-mysql-secondary,并分别创建对应 StorageClass - 不要设置
primary.persistence.existingClaim或secondary.persistence.existingClaim,否则 StatefulSet 无法自动绑定
示例片段(values.yaml):
architecture: "replication" primary: replicaCount: 1 persistence: storageClass: "nfs-mysql-primary" size: "10Gi" secondary: replicaCount: 1 persistence: storageClass: "nfs-mysql-secondary" # 必须与 primary 不同 size: "10Gi"
常见 PVC 绑定失败的错误现象和排查项
部署后 kubectl get pvc 显示 Pending,或 Pod 处于 ContainerCreating 状态卡住:
-
Warning FailedBinding 3m42s persistentvolume-controller no persistent volumes available for this claim and no storage class is set→ 检查storageClass名称拼写,确认kubectl get sc存在且provisioner正常运行 -
Warning FailedScheduling 2m11s default-scheduler 0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims→ NFS provisioner Pod 是否 Running?RBAC 权限是否完整? - Pod 日志出现
Can't start server: Bind on TCP/IP port: Address already in use→ PVC 挂载了旧数据,残留 mysqld 进程未清理,需手动 exec 进入删掉/bitnami/mysql/data下 pid 文件
注意:StatefulSet 的 PVC 是按序创建的(mysql-0 先于 mysql-1),如果主库 PVC 未就绪,从库 Pod 根本不会开始调度 —— 这是设计使然,不是 bug。
连接与验证主从状态的关键命令
别依赖 mysql -h mysql-0.mysql-service 就认为主从通了,得进 MySQL Shell 查复制拓扑:
- 进主库 Pod:
kubectl exec -it mysql-0 -n mysql-dev -- bash - 连 X Protocol:
mysqlsh --mysqlx -u root -h mysql-0.mysql-service -P 33060 - 获取副本集:
var rs = dba.getReplicaSet()(首次创建用dba.createReplicaSet("dev")) - 检查状态:
rs.status()→ 输出中"instanceRole"必须一个是"PRIMARY"、另一个是"SECONDARY",且"status": "ONLINE"
最容易被忽略的一点:rs.addInstance() 添加从库时,必须用 root@mysql-1.mysql-service:3306(带域名),不能用 localhost 或 IP —— 否则复制用户权限无法匹配,后续 SHOW SLAVE STATUS 会显示 IO_Running: No。
本文共计955个文字,预计阅读时间需要4分钟。
直接说结论:
为什么必须用 StatefulSet 而不是 Deployment
MySQL 主从依赖稳定的网络标识(如 mysql-0.mysql-service)、有序启停、以及每个实例独占持久卷。Deployment 无法保证 Pod 名称固定、无法按序创建、也无法为每个副本绑定唯一 PVC —— 这会导致:
-
mysql-1启动时连不上mysql-0(DNS 解析失败或地址漂移) - 两个从库挂载同一份 PVC,造成数据损坏
- 滚动更新时主库被杀,复制链断裂且无法自动恢复
Bitnami Chart 中 architecture: "replication" 模式会自动启用 StatefulSet,但前提是 primary.replicaCount 和 secondary.replicaCount 都设为 1(非 0),且 storageClass 支持动态供给或已预置对应数量的 PV。
StatefulSet 下 PVC 的正确配置方式
主从 Pod 各需独立 PVC,不能共用 storageClass 的同一个 volumeClaimTemplate 名称(否则会被当成同一份存储)。关键点:
- 主库 PVC 名由
primary.persistence.storageClass+primary.persistence.size决定,模板名固定为data - 从库 PVC 名由
secondary.persistence.storageClass决定 —— 必须和主库不同,否则调度器可能复用同一 PV - 若用 NFS,建议主库用
nfs-mysql-primary,从库用nfs-mysql-secondary,并分别创建对应 StorageClass - 不要设置
primary.persistence.existingClaim或secondary.persistence.existingClaim,否则 StatefulSet 无法自动绑定
示例片段(values.yaml):
architecture: "replication" primary: replicaCount: 1 persistence: storageClass: "nfs-mysql-primary" size: "10Gi" secondary: replicaCount: 1 persistence: storageClass: "nfs-mysql-secondary" # 必须与 primary 不同 size: "10Gi"
常见 PVC 绑定失败的错误现象和排查项
部署后 kubectl get pvc 显示 Pending,或 Pod 处于 ContainerCreating 状态卡住:
-
Warning FailedBinding 3m42s persistentvolume-controller no persistent volumes available for this claim and no storage class is set→ 检查storageClass名称拼写,确认kubectl get sc存在且provisioner正常运行 -
Warning FailedScheduling 2m11s default-scheduler 0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims→ NFS provisioner Pod 是否 Running?RBAC 权限是否完整? - Pod 日志出现
Can't start server: Bind on TCP/IP port: Address already in use→ PVC 挂载了旧数据,残留 mysqld 进程未清理,需手动 exec 进入删掉/bitnami/mysql/data下 pid 文件
注意:StatefulSet 的 PVC 是按序创建的(mysql-0 先于 mysql-1),如果主库 PVC 未就绪,从库 Pod 根本不会开始调度 —— 这是设计使然,不是 bug。
连接与验证主从状态的关键命令
别依赖 mysql -h mysql-0.mysql-service 就认为主从通了,得进 MySQL Shell 查复制拓扑:
- 进主库 Pod:
kubectl exec -it mysql-0 -n mysql-dev -- bash - 连 X Protocol:
mysqlsh --mysqlx -u root -h mysql-0.mysql-service -P 33060 - 获取副本集:
var rs = dba.getReplicaSet()(首次创建用dba.createReplicaSet("dev")) - 检查状态:
rs.status()→ 输出中"instanceRole"必须一个是"PRIMARY"、另一个是"SECONDARY",且"status": "ONLINE"
最容易被忽略的一点:rs.addInstance() 添加从库时,必须用 root@mysql-1.mysql-service:3306(带域名),不能用 localhost 或 IP —— 否则复制用户权限无法匹配,后续 SHOW SLAVE STATUS 会显示 IO_Running: No。

