当前位置: 首页 > news >正文

K8S部署MySQL主从复制实现高可用数据库

K8S部署MySQL主从复制实现高可用数据库

一、创建MySQL

1.编写YAML文件
#mysql.yamlapiVersion:v1kind:Servicemetadata:name:mysqllabels:app:mysqlspec:ports:-port:3306targetPort:3306selector:app:mysqlclusterIP:None# Headless---apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlnamespace:defaultspec:serviceName:mysqlreplicas:2#2个pod(mysql-0主库、mysql-1从库)selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0args:-mysqld---server-id=1# 主库固定ID---log-bin=mysql-bin# 开启binlog日志,主从复制核心依赖---binlog-format=ROW# 禁用域名解析,加快连接、减少报错---skip-name-resolveenv:-name:MYSQL_ROOT_PASSWORDvalue:"hyz123!@#"# 环境变量:设置MySQL root密码ports:-containerPort:3306volumeMounts:-name:mysql-datamountPath:/var/lib/mysql# 自动给每个 Pod 创建独立 PVCvolumeClaimTemplates:-metadata:name:mysql-dataspec:accessModes:["ReadWriteOnce"]# 读写单次挂载模式resources:requests:storage:5Gi# 每个节点分配5Gi存储空间
2.创建StatefulSet
kubectl apply-fmysql.yaml
3.验证是否创建成功
kubectl get pods kubectl get pvc kubectl get svc

  • 可以看到Pod名字是固定名字,不是随机字符串!
  • PVC状态处于Bound状态
  • Service的ClusterIPNode
4.验证数据库是否能登录
kubectlexec-itmysql-0 -- mysql-uroot-p'hyz123!@#'

二、搭建主从复制

1.进入主库 mysql-0
kubectlexec-itmysql-0 -- mysql-uroot-p'hyz123!@#'
2.创建复制账号
CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl@123456'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES; SHOW MASTER STATUS;

执行完看到类似结果,记下来 2 个值

  • File :mysql-bin.000001

  • Position: 1171

SHOW MASTER STATUS; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 1171 | | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
3.进入从库mysql-1
kubectlexec-itmysql-1 -- mysql-uroot-p'hyz123!@#'
4.建立主从复制关系
STOP SLAVE; CHANGE MASTER TO MASTER_HOST='mysql-0.mysql.default.svc.cluster.local', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@123456', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=1171; GET_MASTER_PUBLIC_KEY=1; START SLAVE;

参数说明:

  • MASTER_HOST='mysql-0.mysql.default.svc.cluster.local'
    指定主库的主机名或IP地址,在Kubernetes环境中通常使用服务名作为主机名
  • MASTER_PORT=3306
    指定主库MySQL服务的端口号(默认3306)
  • MASTER_USER='repl'
    指定用于复制的专用用户名(应为具有REPLICATION SLAVE权限的账号)
  • MASTER_PASSWORD='Repl@123456'
    指定复制账号的密码(注意:密码中特殊字符需正确转义)
  • MASTER_LOG_FILE='mysql-bin.000001'
    指定主库当前二进制日志文件名,必须与主库SHOW MASTER STATUS输出一致
  • MASTER_LOG_POS=1171
    指定主库二进制日志的起始位置,必须与主库SHOW MASTER STATUS输出一致
  • GET_MASTER_PUBLIC_KEY=1
    启用SSL加密连接,使从库获取主库的公钥用于安全通信(若主库配置了SSL)
5.验证状态
SHOW SLAVE STATUS\G

成功标准✅ :

#你必须看到这两个都是YES Slave_IO_Running: Yes Slave_SQL_Running: Yes

6.配置从库只读,不允许写入数据
SET GLOBAL read_only = ON; SET GLOBAL super_read_only = ON;

三、测试

1.主库创建数据库,看从库有没有同步

①进入主库执行

create database test_final;

②进入从库执行

show databases;

2.测试从库只读功能

①主库mysql-0 执行

--选库 use test_final; -- 建表 CREATE TABLE IF NOT EXISTS user ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20) NOT NULL ); -- 插入4条数据 INSERT INTO user(name) VALUES('zhangsan'),('lisi'),('wangwu'),('test'); -- 查询看结果 SELECT * FROM user;

②然后去 从库 mysql-1 执行

use test_final; SELECT * FROM user;

可以正常查询到数据

尝试写入数据

insert into user(name) values('test123');

返回结果:从库无法写入,只有只读权限

ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement

四、进阶

1.配置抽离:ConfigMap/Secret

现在 MySQL 密码是直接写死在 YAML 里的,非常不安全!

env:-name:MYSQL_ROOT_PASSWORDvalue:"hyz123!@#"# 环境变量:设置MySQL root密码

我们今天改成K8s 生产标准用法

  • 密码 → Secret

  • 配置 → ConfigMap

①创建MySQL密码Secret
kubectl create secret generic mysql-secret\--from-literal=root-password=hyz123!@#

查看是否创建成功:

kubectl get secret

看到mysql-secret就成功 ✅

②修改YAML文件
# ==============================# MySQL 无头 Service# ==============================apiVersion:v1kind:Servicemetadata:name:mysqllabels:app:mysqlspec:ports:-port:3306targetPort:3306selector:app:mysqlclusterIP:None# 无头服务:不分配ClusterIP,直接暴露Pod IP,适用于有状态应用# ==============================# MySQL 配置文件(ConfigMap)# 作用:存放 my.cnf 配置,不写在容器里# ==============================apiVersion:v1kind:ConfigMapmetadata:name:mysql-configdata:my.cnf:|[mysqld] log-bin=mysql-bin # 启用二进制日志,用于主从复制和数据恢复 binlog-format=ROW # 设置二进制日志格式为行模式,更安全精确 skip-name-resolve # 跳过DNS解析,提高连接速度和稳定性# ==============================# MySQL StatefulSet# 密码从 Secret 取# 配置从 ConfigMap 取# ==============================apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlnamespace:defaultspec:serviceName:mysql# 关联上面定义的Service,用于Pod网络标识replicas:2# 部署2个MySQL实例,实现主从架构selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0# 使用MySQL 8.0官方镜像# 从 ConfigMap 加载配置volumeMounts:-name:mysql-configmountPath:/etc/mysql/conf.d/my.cnf# 将ConfigMap挂载为配置文件subPath:my.cnf# 只挂载特定文件,避免覆盖整个目录-name:mysql-datamountPath:/var/lib/mysql# 挂载数据卷,持久化MySQL数据# 环境变量:密码从 Secret 取(不硬编码)env:-name:MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name:mysql-secret# 从名为mysql-secret的Secret获取key:root-password# 获取root-password键的值ports:-containerPort:3306# 暴露MySQL默认端口# 挂载 ConfigMapvolumes:-name:mysql-configconfigMap:name:mysql-config# 引用上面定义的ConfigMap# 自动独立PVCvolumeClaimTemplates:-metadata:name:mysql-data# 与volumeMounts中定义的名称一致spec:accessModes:["ReadWriteOnce"]# 单节点读写访问模式resources:requests:storage:5Gi# 每个实例分配5GB存储空间
③滚动更新MySQL
kubectl apply-fmysql.yaml
④验证是否生效
kubectl get pods

mysql-0mysql-1都 Running 就成功了 ✅

2.配置健康检查(探针)
①K8s 三种探针对比
探针类型核心作用检测失败处理典型场景关键配置要点
LivenessProbe检测容器是否卡死/僵死/进程挂掉直接重启PodMySQL卡死、Java假死、进程崩溃但未退出需设置合理initialDelaySeconds避免误杀
ReadinessProbe检测容器是否完全启动并能提供服务停止转发流量,不重启MySQL启动慢、Java加载资源中、服务未就绪failureThreshold需高于启动时间
StartupProbe专为启动超慢服务设计的临时探针启动阶段失败会重启,启动完成后失效大内存Java应用、数据库初始化、冷启动耗时服务必须配合livenessProbe使用,设置足够timeout
②修改YAML文件

MySQL 官方容器标配:mysqladmin ping(就是指用 root 用户 + 密码,执行mysqladmin ping能通→健康,不通→不健康)

# 无头ServiceapiVersion:v1kind:Servicemetadata:name:mysqllabels:app:mysqlspec:ports:-port:3306targetPort:3306selector:app:mysqlclusterIP:None---# 配置存放:ConfigMapapiVersion:v1kind:ConfigMapmetadata:name:mysql-configdata:my.cnf:|[mysqld] server-id=1 log-bin=mysql-bin binlog-format=ROW skip-name-resolve---# MySQL 有状态服务 + 健康探针apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlnamespace:defaultspec:serviceName:mysqlreplicas:2selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0ports:-containerPort:3306# 密码从Secret读取,不硬编码env:-name:MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name:mysql-secretkey:root-password# 挂载配置文件 + 数据卷volumeMounts:-name:mysql-configmountPath:/etc/mysql/conf.d/-name:mysql-datamountPath:/var/lib/mysql# ========== 存活探针:检测MySQL是否卡死 ==========livenessProbe:exec:command:#mysqladmin ping-mysqladmin--uroot--p$(MYSQL_ROOT_PASSWORD)-pinginitialDelaySeconds:30# 容器启动30秒后开始检测periodSeconds:10# 每10秒检测一次timeoutSeconds:5# 单次检测超时5秒failureThreshold:3# 失败3次就重启Pod# ========== 就绪探针:检测MySQL是否可正常连接 ==========readinessProbe:exec:command:#mysqladmin ping-mysqladmin--uroot--p$(MYSQL_ROOT_PASSWORD)-pinginitialDelaySeconds:15# 启动15秒后开始periodSeconds:5# 每5秒检测timeoutSeconds:3failureThreshold:2volumes:-name:mysql-configconfigMap:name:mysql-configvolumeClaimTemplates:-metadata:name:mysql-dataspec:accessModes:["ReadWriteOnce"]resources:requests:storage:5Gi
③部署生效
kubectl apply-fmysql.yaml

等待 Pod 重建完成:

kubectl get pods-w
④验证探针是否生效

查看 Pod 详细信息(看探针配置)

kubectl describe pod mysql-0

看到livenessreadiness代表配置已经注入!

⑤制造人为故障测试探针

我们删除主库的mysqld.sock文件,让数据库连接失败

kubectlexecmysql-0 --rm-rf/var/run/mysqld/mysqld.sock

另开一个终端,观察探针 + 自愈的全过程

kubectl get pod-w

这说明我们配置探针!这就是生产级健康检查的真正威力:服务异常 → 探针自动发现 → 自动重启恢复 → 全程无需人工干预

3.配置容器资源限制( CPU / 内存)

为什么要加资源限制?

  • requests(请求):告诉 K8s “我至少需要多少资源”,用于调度和保证基础性能。
  • limits(限制):防止 MySQL/Java 把整个节点的 CPU、内存吃爆,影响其他服务。
①修改YAML文件
# 无头 Service:给 StatefulSet 提供稳定域名apiVersion:v1kind:Servicemetadata:name:mysqllabels:app:mysqlspec:ports:-port:3306targetPort:3306selector:app:mysqlclusterIP:None---# ConfigMap:存放非敏感配置apiVersion:v1kind:ConfigMapmetadata:name:mysql-configdata:my.cnf:|[mysqld] server-id=1 log-bin=mysql-bin binlog-format=ROW skip-name-resolve---# StatefulSet:MySQL 有状态服务 + 资源限制 + 探针apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlnamespace:defaultspec:serviceName:mysqlreplicas:2selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0ports:-containerPort:3306# 资源限制:防止吃爆服务器resources:requests:cpu:"100m"# 至少 0.1 核 CPUmemory:"256Mi"# 至少 256MB 内存limits:cpu:"500m"# 最多 0.5 核 CPUmemory:"512Mi"# 最多 512MB 内存# 密码从 Secret 安全读取env:-name:MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name:mysql-secretkey:root-password# 挂载配置文件 + 数据卷volumeMounts:-name:mysql-configmountPath:/etc/mysql/conf.d/-name:mysql-datamountPath:/var/lib/mysql# 存活探针:服务挂了自动重启livenessProbe:exec:command:-mysqladmin--uroot--p$(MYSQL_ROOT_PASSWORD)-pinginitialDelaySeconds:30periodSeconds:10timeoutSeconds:5failureThreshold:3# 就绪探针:没准备好就不给流量readinessProbe:exec:command:-mysqladmin--uroot--p$(MYSQL_ROOT_PASSWORD)-pinginitialDelaySeconds:15periodSeconds:5timeoutSeconds:3failureThreshold:2volumes:-name:mysql-configconfigMap:name:mysql-configvolumeClaimTemplates:-metadata:name:mysql-dataspec:accessModes:["ReadWriteOnce"]resources:requests:storage:5Gi
②部署生效
kubectl apply-fmysql.yaml

然后等 Pod 重建完成:

kubectl get pods-w
③验证资源限制是否生效
kubectl describe pod mysql-0

这里可以看到资源控制已经生效了,防止服务把服务器吃爆!

4.MySQL主从手动故障切换

场景模拟:

  • 原主库:原主库 mysql-0 彻底挂掉(宕机、断网、损坏、无法修复、连不上)
  • 原从库:mysql-1→ 升级为新主库
①登录从库(即将升为新主库)
kubectlexec-itmysql-1 -- mysql-uroot-p
②停止从库复制(关键)

MySQL8.0 必须关两个:

SET GLOBAL read_only = OFF; SET GLOBAL super_read_only = OFF;
③清除复制信息,独立成一台全新主库
RESET MASTER;

作用:清空旧主库的 binlog 位点、复制账号信息,彻底和旧主切割。

④确认当前新主库状态
SHOW MASTER STATUS;

此时mysql-1已经是完全独立可写的新主库

⑤业务层切换

把所有项目、配置、连接串,比如Java项目delopment.yamlapplication.properties

  • 旧地址(废弃):mysql-0.mysql.default.svc
  • 新地址(使用):mysql-1.mysql.default.svc

application.properties示例(主库挂了,必须强制写死新主库:):

delopment.yaml示例(主库挂了,必须强制写死新主库:):

改完重新发布一下 Java 服务,就切换完了!

⑥旧主库恢复完毕后,设置成新从库

后期mysql-0修好、启动正常后,不能直接当主库用,要改成新从库:

⑦登录旧主库
kubectlexec-itmysql-0 -- mysql-uroot-p'hyz123!@#'
⑧清空旧复制配置
STOP SLAVE; RESET MASTER;
⑨查看新主库mysql-1的 binlog 点位

去 mysql-1 执行:

SHOW MASTER STATUS;

拿到:FilePosition

⑩旧主库反向指向新主库
CHANGE MASTER TO MASTER_HOST='mysql-1.mysql.default.svc.cluster.local', MASTER_USER='slave', MASTER_PASSWORD='hyz123!@#', MASTER_LOG_FILE='mysql-bin.000012', MASTER_LOG_POS=157, GET_MASTER_PUBLIC_KEY=1;

开启同步+只读

START SLAVE; SET GLOBAL read_only = ON; SET GLOBAL super_read_only = ON;

至此:

  • 新主:mysql-1

  • 新从:mysql-0

    主从架构反向重建完成。

五、总结

通过以上配置,MySQL 现在拥有了企业生产级标准!

功能模块具体实现作用说明
有状态服务部署StatefulSet + Headless Service为 MySQL 提供稳定的网络标识和有序部署,是数据库这类有状态应用的标准部署方式。
配置解耦ConfigMap将 my.cnf 等配置文件从镜像中剥离,方便统一管理和修改,无需重新构建镜像。
敏感数据安全Secret安全存储 MySQL root 密码,避免明文泄露,通过环境变量注入容器。
高可用主从复制一主一从架构实现数据备份和读写分离,提升数据库的可用性和读性能。
从库只读保护read_only=ON 配置防止主从数据不一致,保证从库数据安全。
自动故障自愈LivenessProbe(存活探针)使用mysqladmin ping检测服务是否卡死 / 崩溃,失败则自动重启容器,实现故障自愈。
流量保护ReadinessProbe(就绪探针)使用mysqladmin ping检测服务是否准备就绪,失败则标记为未就绪,不接收业务流量。
资源隔离与控制resources.requests/limits限制 MySQL 的 CPU / 内存使用上限,防止单个服务吃爆服务器资源,保障集群稳定。
主从故障手动切换手动提升从库为新主库 + 业务流量切换当原主库故障时,将从库提升为新主库,修改业务连接地址,快速恢复写入能力,实现业务持续可用。
http://www.jsqmd.com/news/712458/

相关文章:

  • 持久内存编程实战:从PMem原理到键值存储应用开发
  • 批量调用AI工具,指纹浏览器能实现自动化操作吗?
  • 比迪丽LoRA模型数据库集成案例:构建用户绘画历史与风格偏好系统
  • 2025-2026年深圳除甲醛公司推荐:五大口碑服务评测对比顶尖办公室装修眼干头痛案例 - 品牌推荐
  • FedU-Net:联邦学习隐私保护脑肿瘤 MRI 分割
  • YOLO26 艺术品识别:公共艺术展导览系统
  • Typora快捷键设置教程
  • Hugging Face模型本地化部署:LM Studio集成指南
  • 使用TGI在Hugging Face Spaces部署OLMo-7B大模型
  • 3个实用技巧:使用Playwright Stealth绕过网站自动化检测
  • 2025-2026年上海厂房出租出售公司评测:五家口碑服务推荐评价知名制造业搬迁时效紧注意事项 - 品牌推荐
  • 算法训练营Day15|反转字符串
  • Python人脸识别医院考勤系统【毕业设计答辩文档】
  • AI生成图像纹理分析与质量提升实践
  • 2026年发电机组回收技术解析与合规厂家推荐指南:静音发电机出租、发电机保养、发电机维修、发电机销售、工地发电机组租赁选择指南 - 优质品牌商家
  • 基于Simulink的异物检测(FOD)与活体保护(LPD)逻辑仿真
  • Integuru:AI应用开发的统一网关与稳定性治理平台
  • 第38篇:使用Google Colab进行免费AI开发——云端GPU实战指南(操作教程)
  • 【LeetCode: 跳跃游戏】贪心算法
  • 从代码编写者到AI工程师:掌握LLM开发技术栈的实战指南
  • AgentCPM-Report实战案例:Pixel Epic助力初创企业3天完成融资BP撰写
  • Qwen3-4B-Thinking在法务助理场景的应用:合同审查要点生成案例
  • WASM替代Docker?Python 3.15轻量化部署实测对比:体积压缩92%,冷启耗时<87ms,你还在用传统容器吗?
  • BrainExplore框架:fMRI与AI结合的大脑视觉表征研究
  • 破解冠心病之谜:多种生物标志物与多因子检测技术的整合应用
  • 3步快速上手Revelation光影包:打造电影级Minecraft画面的完整指南
  • 3个简单步骤:用GHelper手动风扇控制告别ROG笔记本噪音困扰
  • macOS--brewhome安装镜像
  • 01基于 Jakarta EE开发 : Servlet + Thymeleaf图书管理系统
  • Go语言Slice切片底层原理深度解析