根本原因是operator未等待旧pod彻底退出就启动新pod,导致pv锁冲突、mysql.sock争抢及gtid position不连续;需确保podmanagementpolicy为orderedready、partition合理、各pod独享pvc、prestop执行mysqladmin shutdown,并启用gtid及exec型readinessprobe。

MySQL在Kubernetes中滚动升级失败,根本原因不是镜像或配置改错了,而是Operator没等旧Pod彻底退出就拉起新Pod,导致PV锁冲突、mysql.sock争抢、GTID position不连续——这些都会让Pod反复重启或主从中断。
StatefulSet的partition和podManagementPolicy必须对齐
MySQL依赖有序启动和关闭,不能用并行策略。如果podManagementPolicy是Parallel,Operator可能同时启mysql-1和mysql-2,破坏主从链路;若updateStrategy.rollingUpdate.partition设得过大(比如设为0),会一次性重建全部Pod,触发存储层并发写冲突。
-
podManagementPolicy必须为OrderedReady,确保mysql-0成为主库后再启动mysql-1 -
partition建议从最大序号开始降级:3副本集群设为2,表示只升级mysql-2,保留mysql-0和mysql-1继续服务 - 修改后需
kubectl apply -f mysql-cr.yaml触发reconcile,不能只改ConfigMap
每个Pod必须有独立PVC,且PV不能共用mysql.sock路径
共享volumeClaimTemplates名称但没加{{.Index}}模板变量,会导致多个Pod挂载同一PVC;NFS或HostPath类存储又缺乏POSIX文件锁语义,mysqld启动时抢/var/lib/mysql/mysql.sock就会报Failed to acquire lock。
- 检查PVC列表:
kubectl get pvc | grep mysql,确认每个Pod对应唯一PVC(如data-mysql-0、data-mysql-1) - 容器内
mysql.sock路径应设为/tmp/mysql.sock这类临时路径,避免落盘争抢 - PV的
reclaimPolicy建议为Retain,防止升级误删数据
preStop必须执行mysqladmin shutdown,不能只靠SIGTERM
默认情况下,Kubernetes发SIGTERM后等待30秒(terminationGracePeriodSeconds)就强制KILL,但mysqld可能还在刷redo log或同步binlog,直接杀进程会导致实例无法干净退出,下次启动卡在recover阶段。
- 在容器
lifecycle.preStop.exec.command里加:["sh", "-c", "mysqladmin shutdown -u root -p$MYSQL_ROOT_PASSWORD -S /tmp/mysql.sock || true"] - 同时把
terminationGracePeriodSeconds调到60秒以上,给shutdown留出缓冲 - 升级前手动验证:
kubectl exec -it mysql-0 -- mysqladmin ping -u root -p$MYSQL_ROOT_PASSWORD能通,再试shutdown
GTID必须开启,且Operator版本要支持自动主角色选举
滚动升级期间主库Pod被重建,如果Operator仍按CR里静态写的spec.replication.primary: mysql-0去连,而新mysql-0的Executed_Gtid_Set为空或不连续,START SLAVE就会失败,Seconds_Behind_Master: NULL就是典型表现。
- CR中启用
spec.replication.gtid: true,并确保所有容器启动参数含--gtid-mode=ON --enforce-gtid-consistency=true - Operator版本低于v0.17.0大概率不支持主节点动态漂移,必须升级;检查日志是否有
reconciling primary role for mysql-1 - 紧急时可用
kubectl patch临时指定新主,但只是绕过问题,不是解决根源
最容易被忽略的是:Operator判断Pod“就绪”只看readinessProbe成功和Phase=Running,但MySQL真正可服务还要等mysqld完成crash recovery、GTID初始化、复制通道建立——这些都没法靠一个HTTP探针覆盖。必须把readinessProbe换成exec类型,执行mysqladmin ping并校验Slave_IO_Running和Slave_SQL_Running状态。











