必须配clusterIP: None的Headless Service以提供稳定DNS(如mysql-0.mysql-headless.default.svc.cluster.local),并设publishNotReadyAddresses: true确保未就绪Pod可解析;volumeClaimTemplates.name须与volumeMounts.name一致;StorageClass需真实存在且支持ReadWriteOnce;server_id须动态生成保证全局唯一;Service selector必须与StatefulSet pod labels完全匹配。

StatefulSet 部署 MySQL 必须配 clusterIP: None 的 Headless Service,否则 Pod 无法获得稳定 DNS 名(如 mysql-0.mysql-headless.default.svc.cluster.local),后续主从发现、MGR 自举、PVC 绑定都会失败。
Headless Service 必须设 publishNotReadyAddresses: true
StatefulSet 启动时,Pod 会按序就绪(mysql-0 → mysql-1 → mysql-2),但从节点启动后要立即连接主节点做复制初始化,而此时主节点可能还没完成 MySQL 初始化(mysqld 进程未 ready)。若不开启该字段,DNS 解析会跳过未就绪 Pod,导致从节点 nslookup mysql-0.mysql-headless 失败或返回空。
-
publishNotReadyAddresses: true允许 kube-dns/coredns 返回所有 Pod 的 A 记录,无论其Ready状态 - 配合 initContainer 中的等待逻辑(如
until nslookup mysql-0.mysql-headless; do sleep 2; done)才真正可靠 - 省略该配置是主从同步卡在“找不到主节点”的最常见原因
volumeClaimTemplates 的 name 必须匹配 volumeMounts.name
StatefulSet 通过 volumeClaimTemplates 自动生成 PVC,但命名规则固定:<template-name>-<statefulset-name>-<ordinal>。如果挂载名不一致,容器启动直接报错 MountVolume.SetUp failed for volume "xxx": claim not found。
- 模板中
metadata.name: mysql-data→ 实际生成 PVC 名为mysql-data-mysql-0 - 容器内
volumeMounts.name必须写成mysql-data,不能写成data或mysql-pv - StorageClass 名必须真实存在且支持
ReadWriteOnce(如standard、nfs-client),否则 PVC 卡在Pending
MySQL server_id 必须全局唯一,不能硬编码
所有 Pod 共用同一份 ConfigMap 时,server_id 若写死为 1,会导致 GTID 冲突、MGR 加入失败、主从 IO 线程报错 Got fatal error 1236。
- 推荐方式:用环境变量注入,在容器启动脚本里动态生成,例如
server_id=$(( $(hostname | sed 's/mysql-//') + 1 )) - ConfigMap 中避免直接写死
server_id=1;若用my.cnf模板,需配合envsubst或 initContainer 渲染 - 使用
$${HOSTNAME##*-}是 Kubernetes ConfigMap 的变量占位语法,仅在容器内被envsubst解析,不是 Shell 原生语法
最容易被忽略的是:Headless Service 的 selector 必须和 StatefulSet 的 template.spec.labels 完全一致,一个字段不匹配,DNS 就不会注册对应 Pod 的记录——这时候 mysql-0.mysql-headless 解析不到 IP,所有依赖它的工作都静默失败。


















