必须用StatefulSet部署MySQL,因其提供固定Pod名(如mysql-0)、独立PVC、稳定DNS和有序启停;Deployment会导致多Pod共享存储、身份混乱、主从错乱和数据丢失。

别直接照搬教程跑 Deployment,MySQL 在 Kubernetes 上一重启就丢数据、主从同步断、读写混乱——这些不是配置错了,是选型错了。
必须用 StatefulSet,不能用 Deployment
Deployment 的 Pod 是无状态的,名字随机(比如 mysql-7f8d9b4c6-xv2kq),重启后可能挂载到别人的 PVC 上;而 MySQL 要求每个实例有固定身份、固定存储、固定网络标识。StatefulSet 保证 Pod 名字始终是 mysql-0、mysql-1,且每个 Pod 绑定自己专属的 PersistentVolumeClaim。
常见错误现象:
- Pod 重建后连上的是别人的数据目录,启动失败或数据错乱
- 主从复制中
server-id冲突(多个 Pod 用了同一个 ID) - Service DNS 解析出多个 IP,但应用直连
mysql-0.mysql才能确保连到主库
实操建议:
- 在
StatefulSet的template.spec.initContainers中动态生成server-id,例如server-id = 100 + $ordinal - 用
serviceName: mysql字段让 StatefulSet 管理 Headless Service,避免 DNS 轮询干扰 - 不要复用同一个 PVC 模板,每个副本必须声明独立的
volumeClaimTemplates
PersistentVolume 不能用本地目录硬绑定
把宿主机 /data/mysql 直接作为 PV,在测试环境看似能跑通,但一旦节点宕机或调度器把 Pod 调到别的节点,数据就不可达。Kubernetes 不会自动把数据“搬”过去。
使用场景限制很明确:仅限单节点 Minikube 或 k3s 临时验证,生产环境必须用支持动态供给(Dynamic Provisioning)的存储后端。
实操建议:
- 优先选用
StorageClass驱动的方案,如longhorn(边缘)、nfs-client(测试)、ceph-csi(生产) - 设置
reclaimPolicy: Retain,防止误删 PVC 导致数据被清空 - 检查 PV 的
nodeAffinity和volumeBindingMode: WaitForFirstConsumer是否匹配,否则 PVC 会卡在Pending
主从配置不能靠镜像内置,得靠 ConfigMap + 启动脚本分离
把 log-bin、super-read-only、server-id 全写死在 Dockerfile 里,会导致所有 Pod 配置一样,主从关系根本建不起来。
为什么这样做:
- 镜像应该只负责运行时环境,配置必须可变、可审计、可灰度
- StatefulSet 的每个 Pod 序号(
$HOSTNAME后缀)是唯一稳定标识,适合做差异化配置依据 - initContainer 中用
hostname解析序号比环境变量更可靠(环境变量在 Pod 重建时可能未注入)
实操建议:
- 用两个 ConfigMap 分别存
master.cnf和slave.cnf,挂载进容器的/etc/mysql/conf.d/ - initContainer 中用正则提取
mysql-2的2,生成对应server-id.cnf - 主库 Pod(
mysql-0)跳过CHANGE MASTER TO,从库 Pod 启动时才执行该命令
mysqld_exporter 要和 MySQL 实例一对一部署
一个 mysqld_exporter 去连多个 MySQL Pod,指标会混在一起,Prometheus 抓取时无法区分 master 还是 slave 的延迟、QPS、连接数。
性能与兼容性影响:
- Exporter 本身轻量,但若共用一个 Pod,MySQL 故障时 exporter 也会跟着挂,监控中断
- 不同 Pod 的
server-id、复制状态、慢查询日志路径都不同,必须隔离采集上下文
实操建议:
- 把
mysqld_exporter作为 sidecar 容器和 MySQL 放进同一个 Pod,共享 localhost 网络 - ServiceMonitor 中用
targetLabels: [statefulset.kubernetes.io/pod-name]区分实例 - 避免用 hostNetwork 模式暴露 exporter 端口,容易端口冲突
最易被忽略的一点:MySQL 的 max_connections 和 innodb_buffer_pool_size 必须按 Pod 的 request/limit 设置,而不是按宿主机内存硬编码。容器内 /proc/meminfo 返回的是 cgroup 限制值,不主动适配会导致 OOM Kill 或缓存严重不足。


















