必须用StatefulSet而非Deployment,因其提供稳定Pod名(如mysql-0)、固定DNS(mysql-0.mysql.ns.svc.cluster.local)、序号映射server-id、PVC独立绑定及Headless Service支持,保障MySQL主从复制、GTID同步与auto_increment错开等核心需求。

为什么必须用StatefulSet,而不是Deployment
Deployment生成的Pod名带随机哈希(如mysql-7d8f9b4c6-xyz12),重启后DNS记录失效,而MySQL主从复制依赖稳定主机名做CHANGE MASTER TO和GTID自动定位。StatefulSet配合Headless Service才能提供固定DNS:mysql-0.mysql.namespace.svc.cluster.local。漏掉这点,从库连不上主库、GTID同步卡死、START SLAVE报错ERROR 3021 (HY000)是常态。
server-id必须唯一且稳定,不能硬编码
MySQL 8.0要求双主或主从间server-id全局唯一,且不能随Pod重建变化。StatefulSet的序号(mysql-0→0)是天然稳定标识,应直接映射:
- 在ConfigMap的
my.cnf中禁用server-id=1这类静态值 - 改用环境变量注入:
server_id=${POD_INDEX}(注意:实际值建议从1开始,即mysql-0对应POD_INDEX=1) - 通过initContainer从
hostname解析序号并写入配置,或用启动脚本传参给mysqld - 若用Helm,可用
{{ .Index | add 1 }}动态生成;纯YAML则需为每个Pod单独定义env
auto_increment必须显式错开,否则主键冲突静默丢数据
MySQL 8.0默认auto_increment_increment=1,双主写入时极易主键冲突。该配置必须写进[mysqld]段,不能只靠SQL设置(Pod重建后会丢失):
-
mysql-0:配置auto_increment_offset=1、auto_increment_increment=2 -
mysql-1:配置auto_increment_offset=2、auto_increment_increment=2 - 验证方式:进容器执行
SELECT @@auto_increment_offset, @@auto_increment_increment;,确保两节点值严格互补 - 漏配会导致
INSERT不报错,但在另一主上因主键冲突被跳过,最终数据不一致却无告警
Headless Service + PVC模板是StatefulSet可靠运行的底座
仅靠StatefulSet声明还不够,必须配套两个关键组件:
- Headless Service(
clusterIP: None):提供mysql-0.mysql这类可解析域名,这是主从之间互相发现的基础 - VolumeClaimTemplate:为每个Pod生成独立PVC(如
data-mysql-0),绑定ReadWriteOnce存储类(如Ceph RBD、Longhorn或云厂商块存储),避免多Pod挂同一PV导致数据损坏 - 不要复用单个PVC给多个Pod,也不要省略
serviceName字段——它必须与Headless Service名称完全一致,否则StatefulSet无法绑定网络标识
最容易被忽略的是server-id与Pod序号的映射逻辑和auto_increment参数的持久化位置。配置写在ConfigMap里但没通过环境变量或initContainer注入,或者把自增参数放在SQL初始化脚本而非my.cnf,都会在Pod重建后立刻失效。


















