必须用Headless Service配合StatefulSet,因其提供稳定DNS解析(如mysql-0.mysql.svc.cluster.local),使每个Pod可独立寻址;若用ClusterIP会负载均衡导致从库连错实例,且Service名称须与StatefulSet的serviceName严格一致。

StatefulSet 是唯一能可靠支撑 MySQL 主从集群的控制器,用 Deployment 或 ReplicaSet 部署 MySQL 一定会在 Pod 重建后丢数据、断复制、连错实例——这不是配置问题,是模型不匹配。
为什么必须用 Headless Service 配合 StatefulSet
StatefulSet 的每个 Pod(如 mysql-0)需要被独立寻址,而普通 ClusterIP Service 会做负载均衡,把所有请求随机转发到任意后端 Pod,导致从库无法稳定连接主库。
-
Headless Service必须设置clusterIP: None,这样 CoreDNS 才会为每个 Pod 解析出独立的 A 记录,比如mysql-0.mysql.default.svc.cluster.local -
Service的metadata.name必须和 StatefulSet 的serviceName字段完全一致(大小写、连字符都不能错) - 常见错误现象:
mysql-0启动后反复CrashLoopBackOff,日志里出现Can't find hostname mysql-0或getaddrinfo failed,90% 是因为 Service 没设成 headless,或 DNS 域名拼错 - 验证方法:
kubectl exec -it mysql-0 -- nslookup mysql-0.mysql.default.svc.cluster.local,应返回唯一 IP;若返回多个 IP 或报 NXDOMAIN,说明 DNS 未生效
如何让 mysql-0 固定为主库、其余为从库
StatefulSet 本身不处理主从逻辑,必须靠启动脚本或初始化容器根据 $HOSTNAME(即 mysql-0、mysql-1)做条件判断。
- 主库(
mysql-0)必须启用log-bin和固定server-id=1;从库需用不同server-id(例如用$(hostname | sed 's/mysql-//')生成) - 从库启动前必须等待主库
mysqld就绪:仅靠readinessProbe不够,建议在 entrypoint 脚本中用mysqladmin ping -h mysql-0.mysql.default.svc.cluster.local轮询,超时退出 - GTID 模式下,从库首次同步前需执行
SET GLOBAL gtid_purged = ''(前提是主库已RESET MASTER或已知 purged 集合),否则START SLAVE会失败 - 主库崩溃重建后,新
mysql-0的 binlog position 和 GTID 已重置,旧从库直接CHANGE MASTER TO会报Could not find first log file name in binary log index file;需人工介入重置复制或使用备份恢复
PVC 绑定失败导致 Pod 卡在 Pending 怎么办
云厂商的默认 StorageClass(如 AWS EBS、Azure Disk、阿里云 cloud_efficiency)通常绑定到单可用区(AZ),而 StatefulSet 的 Pod 可能被调度到任意节点——如果 mysql-1 被调度到和 mysql-0 不同的 AZ,且 PVC 已绑定到前者所在 AZ 的磁盘,则挂载失败,Pod 卡在 Pending。
- 解决方案一:改用跨 AZ 存储,如 NFS、Ceph、阿里云 NAS、腾讯云 CFS;它们支持多节点并发挂载,PVC 不受 AZ 限制
- 解决方案二:强制调度到同一 AZ,在 StatefulSet 的
spec.template.spec中加nodeAffinity,指定topologyKey: topology.kubernetes.io/zone并约束到某一个 AZ(牺牲了高可用性) - 解决方案三:使用支持拓扑感知的 StorageClass(如 CSI 驱动的
volumeBindingMode: WaitForFirstConsumer),让 PVC 绑定延迟到 Pod 调度完成之后,再动态选择匹配的 PV - 排查命令:
kubectl describe pvc data-mysql-1查看 Events;若出现WaitForFirstConsumer但没 Pod,或no persistent volumes available for this claim,基本可定位为拓扑不匹配
最易被忽略的一点:MySQL 主从切换不是自动的。StatefulSet 只保证 mysql-0 这个名字永远指向主库,但它不会在 mysql-0 崩溃时自动把 mysql-1 提升为主库——这需要额外的 Operator 或外部故障检测+手动干预。别指望 Kubernetes 自己做 failover。


















