k8s 部署MySQL主从集群(一主两从)1.0

一、环境清单

1. 集群基础信息
项目 配置值
集群类型 单 Master + 3 Worker(1 主 3 从)
Kubernetes 版本 v1.23.0
容器运行时 Docker 26.1.4
网络插件 Calico v3.22
操作系统 CentOS 7.9
内核版本 3.10.0-1160.el7.x86_64
Pod 网络段 10.244.0.0/16(Calico 默认)
Service 网络段 10.96.0.0/12(K8s 默认)
CPU 4 核
内存 8G
2. 节点信息
机器名称 机器 IP 操作系统 角色 主要功能
k8s-master 10.132.47.60 Centos7.9 Master + NFS 服务器 集群控制面 + 提供 NFS 共享存储
k8s-node1 10.132.47.61 Centos7.9 Worker 运行应用 Pod + NFS 客户端
k8s-node2 10.132.47.62 Centos7.9 Worker 运行应用 Pod + NFS 客户端
k8s-node3 10.132.47.63 Centos7.9 Worker 运行应用 Pod + NFS 客户端
3. NFS 服务器配置(master 节点)
配置项 配置值
共享目录路径 /data/nfs/mysql
目录权限 777(读写执行)
目录所属用户 / 组 nfsnobody:nfsnobody
共享规则(/etc/exports) /data/nfs/mysql 10.132.47.0/24(rw,sync,no_root_squash,no_all_squash)
依赖服务 rpcbind、nfs-server(已开机自启)
服务状态 运行中
4. NFS 动态供应器配置
配置项 配置值
供应器名称 nfs-client-provisioner
部署命名空间 kube-system
服务账户名称 nfs-provisioner
集群角色名称 nfs-provisioner-runner
集群角色绑定名称 run-nfs-provisioner
供应器镜像 registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
供应器标识(PROVISIONER_NAME) k8s-sigs.io/nfs-subdir-external-provisioner
关联 NFS 服务器 IP 10.132.47.60
关联 NFS 共享目录 /data/nfs/mysql
运行副本数 1
容器挂载点 /persistentvolumes
核心权限 PV/PVC/StorageClass 操作、endpoints/leases leader 选举权限
5. StorageClass 配置
配置项 配置值
StorageClass 名称 nfs-storage
关联供应器 k8s-sigs.io/nfs-subdir-external-provisioner
回收策略 Delete(删除 PVC 时自动删除 PV)
允许扩容 是(allowVolumeExpansion: true)
绑定模式 Immediate(立即绑定)
额外参数 archiveOnDelete: "false"(删除 PVC 不归档数据)
状态 可用(Available)
6. PVC 配置(测试 / 业务用)
配置项 配置值
PVC 名称 mysql-data-pvc
所属命名空间 default
关联 StorageClass nfs-storage
访问模式 ReadWriteMany(RWX,多节点读写)
申请存储容量 5Gi
状态 待绑定 / 已绑定(根据实际部署结果更新)
用途 模拟 MySQL 持久化存储
7. PV 配置(动态创建)
配置项 配置值
PV 名称 自动生成(格式:pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
关联 PVC default/mysql-data-pvc
存储容量 5Gi(与 PVC 申请容量一致)
访问模式 ReadWriteMany(RWX)
回收策略 Delete(继承 StorageClass 配置)
存储后端 NFS(10.132.47.60:/data/nfs/mysql/[子目录])
动态创建触发条件 PVC 创建后自动生成

二、验证相关服务

bash 复制代码
# 1. 确认 NFS 动态供应器运行正常
kubectl get pods -n kube-system | grep nfs-client-provisioner
#示例
[root@k8s-master nfs]# kubectl get pods -n kube-system | grep nfs-client-provisioner
nfs-client-provisioner-5bfb45b7b8-9gbbn    1/1     Running   0               33m
------------------------------------------------------------------------------------------------------------
# 2. 确认 StorageClass 存在
kubectl get sc | grep nfs-storage
#示例
[root@k8s-master nfs]# kubectl get sc | grep nfs-storage
nfs-storage   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           true                   44m
------------------------------------------------------------------------------------------------------------
# 3. 确认 NFS 服务器共享目录可访问(在任意节点执行)
showmount -e 10.132.47.60
#示例
[root@k8s-master nfs]# showmount -e 10.132.47.60
Export list for 10.132.47.60:
/data/nfs/mysql 10.132.47.60/24
------------------------------------------------------------------------------------------------------------

环境步骤参考我的文章:

1.k8s集群搭建:Centos7.9 安装K8S 1master3node-CSDN博客

2.NFS服务搭建:k8s 部署NFS和动态供应器-CSDN博客

三、创建命名空间

1. 创建命名空间 YAML

文件名:mysql-namespace.yaml

yaml 复制代码
apiVersion: v1
kind: Namespace
metadata:
  name: mysql-cluster  # 命名空间名称,明确标识集群用途
  labels:
    app: mysql  # 统一标签,便于资源管理

字段解释

  • apiVersion: v1:Namespace 属于 K8s 核心 API 组,版本为 v1
  • kind: Namespace:资源类型为命名空间,用于隔离不同应用的资源(避免与其他应用冲突)
  • metadata.name: mysql-cluster:命名空间名称,后续所有 MySQL 资源都部署在这里
  • labels.app: mysql:给命名空间打标签,方便用标签筛选资源
2. 部署与验证
bash 复制代码
# 部署命名空间
kubectl apply -f mysql-namespace.yaml

# 验证(看到 mysql-cluster 表示成功)
kubectl get namespaces | grep mysql-cluster
------------------------------------------------------------------------------------------------------------
#示例
[root@k8s-master mysql-1]# kubectl apply -f mysql-namespace.yaml
namespace/mysql-cluster created
[root@k8s-master mysql-1]# kubectl get namespaces | grep mysql-cluster
mysql-cluster          Active   5s

四、创建 Secret 存储敏感信息

为什么用 Secret?

生产环境中,密码、密钥等敏感信息不能明文写在 YAML 里(容易泄露),Secret 是 K8s 专门用于存储敏感数据的资源,会加密存储在 ETCD 中,使用时挂载到 Pod 或作为环境变量注入,更安全。

1. 创建 Secret YAML

文件名:mysql-secret.yaml

yaml 复制代码
apiVersion: v1
kind: Secret
metadata:
  name: mysql-secrets  # Secret 名称,后续引用
  namespace: mysql-cluster  # 与 MySQL 集群同命名空间
type: Opaque  # 通用类型,存储键值对(非 TLS 等特殊场景)
data:
  # 所有值必须是 Base64 编码(生产环境避免明文,这里提供编码方法)
  root-password: U2h5c2h5NTIxNTIxIQ==  # 原始值:Shyshy521521!(Base64 编码命令:echo -n "Shyshy521521!" | base64)
  repl-password: U2h5c2h5NTIxNTIxIQ==   # 复制用户密码(与 root 一致,简化管理)
  app-password: U2h5c2h5NTIxNTIxIQ==    # 业务用户密码(与 root 一致,简化管理)

字段解释

  • type: Opaque:Secret 的默认类型,适用于存储任意键值对(其他类型如 kubernetes.io/tls 用于存储证书)

  • data:存储敏感数据的字段,

    所有值必须经过 Base64 编码

    (避免明文泄露)

    • root-password:root 用户密码(MySQL 超级管理员)
    • repl-password:复制用户密码(主从复制时从库连接主库用)
    • app-password:业务用户密码(应用程序连接 MySQL 用)
2. 编码验证
bash 复制代码
# 解码验证(输出 Shyshy521521! 表示正确)
echo -n "U2h5c2h5NTIxNTIxIQ==" | base64 -d

#示例
[root@k8s-master mysql-1]# echo -n "U2h5c2h5NTIxNTIxIQ==" | base64 -d
Shyshy521521![root@k8s-master mysql-1]# 
3. 部署验证
bash 复制代码
# 部署 Secret
kubectl apply -f mysql-secret.yaml

# 验证(看到 mysql-secrets 表示成功)
kubectl get secrets -n mysql-cluster

# 查看 Secret 详情(验证数据存在,会显示编码后的值)
kubectl describe secret mysql-secrets -n mysql-cluster

------------------------------------------------------------------------------------------------------------
#示例
[root@k8s-master mysql-1]# vim mysql-secret.yaml
[root@k8s-master mysql-1]# kubectl apply -f mysql-secret.yaml
secret/mysql-secrets created

[root@k8s-master mysql-1]# kubectl get secrets -n mysql-cluster
NAME                  TYPE                                  DATA   AGE
default-token-6nt62   kubernetes.io/service-account-token   3      4m30s
mysql-secrets         Opaque                                3      4s

[root@k8s-master mysql-1]# kubectl describe secret mysql-secrets -n mysql-cluster
Name:         mysql-secrets
Namespace:    mysql-cluster
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
repl-password:  13 bytes
root-password:  13 bytes
app-password:   13 bytes

五、创建ConfigMap 存储 MySQL 配置

为什么用 ConfigMap?

MySQL 配置(如主从复制参数、字符集、连接数等)如果硬编码到镜像中,修改时需要重新构建镜像,非常麻烦。ConfigMap 是 K8s 用于存储配置文件的资源,可动态挂载到 Pod 中,修改配置后只需重启 Pod 即可生效,无需改镜像

1. 创建 ConfigMap YAML

文件名:mysql-configmap.yaml

yaml 复制代码
# 指定Kubernetes API版本,v1是核心API版本,ConfigMap属于此版本下的资源
apiVersion: v1
# 声明资源类型为ConfigMap,用于存储非加密的配置数据,供Pod挂载使用
kind: ConfigMap
# 资源的元数据信息
metadata:
  # ConfigMap的名称,在所属命名空间内唯一,后续Pod可通过此名称引用配置
  name: mysql-config
  # 指定所属命名空间为mysql-cluster,限制配置的作用域,仅该命名空间内的资源可访问
  namespace: mysql-cluster
# ConfigMap的核心数据部分,存储键值对形式的配置内容
data:
  # 定义MySQL主节点的配置文件,键为master.cnf,值为具体配置内容(|表示保留换行符的多行文本)
  master.cnf: |
    # [mysqld]表示配置片段适用于MySQL服务器进程
    [mysqld]
    # 设置MySQL服务器的默认字符集为utf8mb4,支持包括emoji在内的所有Unicode字符
    character-set-server=utf8mb4
    # 设置服务器的默认排序规则为utf8mb4_unicode_ci,基于Unicode的排序规则,更符合多语言需求
    collation-server=utf8mb4_unicode_ci
    # 最大连接数限制为1000,防止过多连接导致服务器资源耗尽
    max_connections=1000
    # 禁用DNS反向解析,加快连接建立速度(避免连接时解析客户端主机名的耗时)
    skip-name-resolve
    # 设置默认存储引擎为InnoDB,支持事务、行级锁等高级特性
    default-storage-engine=InnoDB
    # 主节点的唯一标识ID,在主从集群中必须唯一,用于区分不同节点
    server-id=1
    # 启用二进制日志,日志文件前缀为mysql-bin,用于主从复制(记录所有数据修改操作)
    log-bin=mysql-bin
    # 二进制日志格式为ROW(行级模式),记录数据行的变更详情,复制准确性最高
    binlog-format=ROW
    # 允许从节点将复制的日志再写入自身的二进制日志(用于级联复制,如主->从->从架构)
    log-slave-updates=1
    # 二进制日志自动过期时间为7天,自动清理旧日志,避免磁盘空间耗尽
    expire-logs-days=7
    # InnoDB事务日志刷新策略:每次事务提交时立即将日志写入磁盘并刷新,确保数据持久性(ACID中的D)
    innodb_flush_log_at_trx_commit=1
    # 二进制日志同步策略:每次事务提交时立即将binlog同步到磁盘,防止服务器崩溃导致binlog丢失
    sync_binlog=1

  # 定义MySQL从节点的配置文件,键为slave.cnf,值为具体配置内容
  slave.cnf: |
    [mysqld]
    # 与主节点一致,确保字符集兼容
    character-set-server=utf8mb4
    # 与主节点一致,确保排序规则兼容
    collation-server=utf8mb4_unicode_ci
    # 从节点最大连接数同样限制为1000
    max_connections=1000
    # 同主节点,禁用DNS解析加速连接
    skip-name-resolve
    # 默认存储引擎与主节点一致,确保数据格式兼容
    default-storage-engine=InnoDB
    # 从节点的唯一标识ID,必须与主节点及其他从节点不同
    server-id=2
    # 从节点同样启用二进制日志(如果需要作为其他节点的主节点,如级联复制)
    log-bin=mysql-bin
    # 二进制日志格式与主节点一致,确保复制兼容性
    binlog-format=ROW
    # 二进制日志过期时间与主节点一致
    expire-logs-days=7
    # 同主节点,确保从节点数据持久性
    innodb_flush_log_at_trx_commit=1
    # 同主节点,确保从节点binlog安全性
    sync_binlog=1
    # 定义中继日志文件前缀为mysql-relay-bin,用于存储从主节点复制过来的日志(从节点特有)
    relay-log=mysql-relay-bin
    # 同主节点,允许从节点将复制的日志写入自身binlog,支持级联复制
    log-slave-updates=1
    # 设置从节点为只读模式,防止直接修改从节点数据(普通用户无法写入)
    read-only=1
    # 强化只读模式,即使是超级用户也无法写入(进一步保证从节点数据与主节点一致)
    #super-read-only=1

新:

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
  namespace: mysql-cluster
data:
  master.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    max_connections=1000
    skip-name-resolve
    default-storage-engine=InnoDB
    server-id=1
    log-bin=mysql-bin
    binlog-format=ROW
    log-slave-updates=1
    expire-logs-days=7
    innodb_flush_log_at_trx_commit=1
    sync_binlog=1
  slave.cnf: |
    [mysqld]
    character-set-server=utf8mb4
    collation-server=utf8mb4_unicode_ci
    max_connections=1000
    skip-name-resolve
    default-storage-engine=InnoDB
    server-id=2
    log-bin=mysql-bin
    binlog-format=ROW
    expire-logs-days=7
    innodb_flush_log_at_trx_commit=1
    sync_binlog=1
    relay-log=mysql-relay-bin
    log-slave-updates=1
    read-only=1
    #super-read-only=1

字段解释(重点)

  • data:存储配置文件的核心字段,key 是配置文件名(master.cnf/slave.cnf),value 是配置文件内容
  • 主库关键配置:
    • server-id=1:集群内唯一,主库必须是唯一值(从库不能重复)
    • log-bin=mysql-bin:启用二进制日志(主从复制的基础,没有日志就无法同步)
    • binlog-format=ROW:生产推荐模式,复制时只记录数据行变化,避免 SQL 模式不一致导致的同步失败
  • 从库关键配置:
    • server-id=2:第二个从库需改为 3(后续部署时修改)
    • relay-log=mysql-relay-bin:中继日志,从库先下载主库的二进制日志到中继日志,再执行中继日志中的 SQL 同步数据
    • read-only=1 + super-read-only=1:从库只读,防止业务误写(生产必开)
2. 部署与验证
bash 复制代码
# 部署 ConfigMap
kubectl apply -f mysql-configmap.yaml
------------------------------------------------------------------------------------------------------------
# 验证(看到 mysql-config 表示成功)
kubectl get configmap -n mysql-cluster

#示例
[root@k8s-master mysql-1]# kubectl get configmap -n mysql-cluster
NAME               DATA   AGE
kube-root-ca.crt   1      11m
mysql-config       2      6s
------------------------------------------------------------------------------------------------------------
# 用 jsonpath 读取(若方式1能看到,方式2即使输出空也不影响,部署后Pod能正常挂载)
kubectl get configmap mysql-config -n mysql-cluster -o json | jq '.data.master.cnf'
kubectl get configmap mysql-config -n mysql-cluster -o json | jq '.data.slave.cnf'

#示例
[root@k8s-master mysql-1]# kubectl get configmap mysql-config -n mysql-cluster -o json | jq '.data.master.cnf'
null
[root@k8s-master mysql-1]# kubectl get configmap mysql-config -n mysql-cluster -o json | jq '.data.slave.cnf'
null
------------------------------------------------------------------------------------------------------------
# 直接查看 ConfigMap 详情(最直观)
kubectl describe configmap mysql-config -n mysql-cluster
#示例
[root@k8s-master mysql-1]# kubectl describe configmap mysql-config -n mysql-cluster
Name:         mysql-config
Namespace:    mysql-cluster
Labels:       <none>
Annotations:  <none>

Data
====
master.cnf:
----
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=1000
skip-name-resolve
default-storage-engine=InnoDB
server-id=1
log-bin=mysql-bin
binlog-format=ROW
log-slave-updates=1
expire-logs-days=7
innodb_flush_log_at_trx_commit=1
sync_binlog=1

slave.cnf:
----
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=1000
skip-name-resolve
default-storage-engine=InnoDB
server-id=2
log-bin=mysql-bin
binlog-format=ROW
expire-logs-days=7
innodb_flush_log_at_trx_commit=1
sync_binlog=1
relay-log=mysql-relay-bin
log-slave-updates=1
read-only=1
super-read-only=1


BinaryData
====

Events:  <none>

六、创建 PVC

核心逻辑

主库和从库的数据需要独立持久化(避免相互覆盖),因此创建 3 个 PVC(1 主 + 2 从),每个 PVC 对应一个 NFS 动态生成的 PV,数据存储在 NFS 服务器的 /data/nfs/mysql 目录下。

1. 创建主库 PVC YAML

文件名:mysql-master-pvc.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-master-pvc  # PVC 名称,主库专用
  namespace: mysql-cluster  # 与集群同命名空间
spec:
  accessModes:
    - ReadWriteMany  # NFS 支持多节点读写(RWX),适合主从复制场景(从库无需写数据,但配置兼容)
  resources:
    requests:
      storage: 10Gi  # 主库申请 10GB 存储(根据业务数据量调整,生产建议至少 50GB)
  storageClassName: nfs-storage  # 关联现有 NFS 动态存储类(自动创建 PV)
2. 创建从库 1 PVC YAML

文件名:mysql-slave1-pvc.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-slave1-pvc  # 从库 1 PVC 名称
  namespace: mysql-cluster
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi  # 从库存储与主库一致(同步主库数据,需同等空间)
  storageClassName: nfs-storage
3. 创建从库 2 PVC YAML

文件名:mysql-slave2-pvc.yaml

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-slave2-pvc  # 从库 2 PVC 名称
  namespace: mysql-cluster
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  storageClassName: nfs-storage
字段解释
  • accessModes: ReadWriteMany:NFS 支持的多节点读写模式(RWX),虽然从库是只读,但配置统一,后续若主从切换无需修改
  • resources.requests.storage: 10Gi:申请的存储容量,主从保持一致(从库需要存储主库同步的所有数据)
  • storageClassName: nfs-storage:指定使用现有 NFS 动态存储类,K8s 会自动创建对应的 PV,无需手动创建
4. 部署与验证
bash 复制代码
# 部署 3 个 PVC
kubectl apply -f mysql-master-pvc.yaml
kubectl apply -f mysql-slave1-pvc.yaml
kubectl apply -f mysql-slave2-pvc.yaml
------------------------------------------------------------------------------------------------------------
# 验证 PVC 状态(所有 PVC 状态为 Bound 表示成功,PV 已自动创建)
kubectl get pvc -n mysql-cluster
# 预期输出:
# NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
# mysql-master-pvc  Bound    pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   10Gi       RWX            nfs-storage    1m
# mysql-slave1-pvc  Bound    pvc-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy   10Gi       RWX            nfs-storage    1m
# mysql-slave2-pvc  Bound    pvc-zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz   10Gi       RWX            nfs-storage    1m
#我这里配置的2G
[root@k8s-master mysql-1]# kubectl get pvc -n mysql-cluster
NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-master-pvc   Bound    pvc-56c8378e-b644-4abc-8f99-f2d038fa08c1   2Gi        RWX            nfs-storage    19s
mysql-slave1-pvc   Bound    pvc-f5818768-07a5-4eac-b12c-da2881626151   2Gi        RWX            nfs-storage    13s
mysql-slave2-pvc   Bound    pvc-c095f935-a265-4827-b777-65a121d2d9c0   2Gi        RWX            nfs-storage    7s
------------------------------------------------------------------------------------------------------------

# 验证 PV 自动创建(3 个 PV 与 PVC 一一对应)
kubectl get pv | grep nfs-storage

#示例
[root@k8s-master mysql-1]# kubectl get pv | grep nfs-storage
pvc-56c8378e-b644-4abc-8f99-f2d038fa08c1   2Gi        RWX            Delete           Bound    mysql-cluster/mysql-master-pvc   nfs-storage             62s
pvc-c095f935-a265-4827-b777-65a121d2d9c0   2Gi        RWX            Delete           Bound    mysql-cluster/mysql-slave2-pvc   nfs-storage             50s
pvc-f5818768-07a5-4eac-b12c-da2881626151   2Gi        RWX            Delete           Bound    mysql-cluster/mysql-slave1-pvc   nfs-storage             56s

七、部署主库 Service

1. 创建主库 Service YAML(mysql-master-service.yaml
复制代码
apiVersion: v1
kind: Service
metadata:
  name: mysql-master-svc  # 主库 Service 名称,从库连接时要用
  namespace: mysql-cluster  # 必须和主库在同一个命名空间
  labels:
    app: mysql
    role: master
spec:
  selector:
    app: mysql
    role: master  # 筛选主库 Pod(通过标签匹配,和主库 Deployment 的标签一致)
  ports:
  - port: 3306  # Service 内部端口(从库连接时用这个端口)
    targetPort: 3306  # 映射到主库 Pod 的 3306 端口(MySQL 容器的端口)
    nodePort: 30036  # 外部访问端口(可选,用于外部客户端连接主库)
  type: NodePort  # 类型:NodePort,既支持集群内访问(从库用),也支持外部访问
2. 部署主库 Service
复制代码
# 执行部署命令
kubectl apply -f mysql-master-service.yaml

# 验证 Service 是否部署成功(看到以下输出表示正常)
kubectl get svc -n mysql-cluster | grep mysql-master-svc
# 预期输出:
# mysql-master-svc    NodePort    10.96.xxx.xxx   <none>        3306:30036/TCP   10s

八、部署MySQL

1. 部署MySQL主库
1.1 主库 Deployment YAML(mysql-master-deployment.yaml
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-master  # 主库 Deployment 名称,唯一标识
  namespace: mysql-cluster  # 与集群资源同命名空间
  labels:
    app: mysql
    role: master  # 标签:标识应用和角色(主库),便于 Service 筛选和管理
spec:
  replicas: 1  # 主库单副本(多副本会导致数据不一致,主从架构常规配置)
  selector:
    matchLabels:
      app: mysql
      role: master  # 选择器:只管理带该标签的 Pod(避免误操作其他资源)
  template:
    metadata:
      labels:
        app: mysql
        role: master  # Pod 标签:与选择器一致,让 Deployment 能识别并管理
    spec:
      containers:
      - name: mysql-master  # 容器名称,便于日志查看和区分
        image: mysql:8.0.32  # 兼容 CentOS 7.9 的镜像(规避 x86-64-v2 指令集报错)
        imagePullPolicy: IfNotPresent  # 优先使用本地镜像,无则远程拉取(加速部署)
        ports:
        - containerPort: 3306  # MySQL 容器默认监听端口(必须与 Service 映射一致)
        env:
        # 1. root 密码(从 Secret 读取,生产级安全,避免明文泄露)
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets  # 关联之前创建的 Secret 名称
              key: root-password   # Secret 中存储 root 密码的键
        # 2. 初始化创建业务数据库(应用启动前提前建库,无需手动操作)
        - name: MYSQL_DATABASE
          value: appdb  # 业务数据库名称(可按需修改,如 shopdb、userdb)
        # 3. 初始化创建业务用户(应用用普通用户连接,限制权限,降低风险)
        - name: MYSQL_USER
          value: appuser  # 业务用户名
        # 4. 业务用户密码(从 Secret 读取,避免明文)
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: app-password
        # 5. MySQL 8.0 认证插件(兼容旧客户端,避免连接失败)
        - name: MYSQL_AUTHENTICATION_PLUGIN
          value: mysql_native_password
        # 容器健康检查(确保 MySQL 正常运行,异常自动重启)
        livenessProbe:
          tcpSocket:
            port: 3306  # 存活探针:检测 3306 端口是否通(判断容器是否活着)
          initialDelaySeconds: 60  # 启动后延迟 60 秒检测(给 MySQL 初始化时间)
          periodSeconds: 10  # 每 10 秒检测一次
          timeoutSeconds: 5  # 检测超时时间 5 秒
        readinessProbe:
          exec:
            # 就绪探针:执行 mysqladmin ping 命令(判断容器是否能提供服务)
            command: ["mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$(MYSQL_ROOT_PASSWORD)"]
          initialDelaySeconds: 30  # 启动后延迟 30 秒检测
          periodSeconds: 5  # 每 5 秒检测一次
          timeoutSeconds: 3  # 超时 3 秒
        # 资源限制(避免 MySQL 占用过多资源,影响其他应用)
        resources:
          requests:  # 最小资源需求(调度时保证分配)
            cpu: 500m  # 0.5 核 CPU
            memory: 1Gi  # 1GB 内存
          limits:  # 最大资源限制(防止资源滥用)
            cpu: 1000m  # 1 核 CPU
            memory: 2Gi  # 2GB 内存
        # 挂载配置文件和持久化存储
        volumeMounts:
        # 1. 挂载主库配置文件(从 ConfigMap 读取)
        - name: master-config
          mountPath: /etc/mysql/conf.d/master.cnf  # MySQL 自动加载此目录下的 .cnf 文件
          subPath: master.cnf  # 只挂载 master.cnf,避免覆盖目录内其他文件
        # 2. 挂载持久化存储(数据目录)
        - name: master-data
          mountPath: /var/lib/mysql  # MySQL 数据默认存储路径(必须挂载,否则数据丢失)
          subPath: mysql  # 在 PV 中创建 mysql 子目录,隔离其他数据
      # 定义 volumes(关联 PVC 和 ConfigMap)
      volumes:
      # 1. 主库配置文件卷(关联 ConfigMap)
      - name: master-config
        configMap:
          name: mysql-config  # 关联之前创建的 ConfigMap
          items:
          - key: master.cnf  # ConfigMap 中的配置文件名
            path: master.cnf  # 挂载到容器内的文件名(保持一致)
      # 2. 主库持久化存储卷(关联 PVC)
      - name: master-data
        persistentVolumeClaim:
          claimName: mysql-master-pvc  # 关联之前创建的主库 PVC
1.2 YAML 关键字段详细解释
字段路径 字段值 核心作用
metadata.labels app: mysql, role: master 给资源打标签,后续 Service 可通过标签筛选主库 Pod,也便于批量管理(如筛选所有 MySQL 资源)
spec.replicas: 1 主库单副本 主从架构中主库只能有一个 "写入源",多副本会导致数据冲突(生产高可用可配合主从切换工具,此处先单副本)
image: mysql:8.0.32 兼容 CentOS 7.9 之前报错是因为 MySQL 8.0.33+ 依赖 x86-64-v2 指令集,CentOS 7.9 内核不支持,此版本完美兼容
env.MYSQL_AUTHENTICATION_PLUGIN mysql_native_password MySQL 8.0 默认用 caching_sha2_password,部分旧客户端(如 Python2 驱动)不兼容,此配置兼容所有客户端
livenessProbe TCP 检测 3306 端口 存活探针:如果端口不通,说明容器 "死了",K8s 会自动重启容器(比如 MySQL 崩溃时)
readinessProbe mysqladmin ping 命令 就绪探针:不仅要端口通,还要能执行命令,确保 MySQL 已初始化完成并能提供服务(避免启动中就接收流量)
resources 请求 0.5 核 / 1G,限制 1 核 / 2G 资源调度的关键:- requests:告诉 K8s 这个 Pod 至少需要多少资源,调度时会分配到有足够资源的节点- limits:防止 MySQL 异常时占用过多资源(比如死循环吃满 CPU)
volumeMounts[0] 挂载 master.cnf 到 /etc/mysql/conf.d/ MySQL 启动时会自动加载 /etc/mysql/conf.d/ 目录下的所有 .cnf 文件,无需手动指定配置文件路径
volumeMounts[1] 挂载 /var/lib/mysql 到 PVC 这是数据持久化的核心!MySQL 的所有数据(表、日志等)都存在这个目录,挂载 PVC 后,即使 Pod 被删除,数据也会保存在 NFS 服务器上
volumes 关联 ConfigMap 和 PVC 告诉 K8s 容器挂载的 "文件" 和 "存储" 来自哪里,是连接 Pod 与外部资源的桥梁
1.3 部署主库并验证
bash 复制代码
# 1. 部署主库 Deployment
kubectl apply -f mysql-master-deployment.yaml

------------------------------------------------------------------------------------------------------------
# 2. 查看主库 Pod 状态(需要等 1-2 分钟,MySQL 初始化需要时间)
kubectl get pods -n mysql-cluster -l app=mysql,role=master

# 预期输出(STATUS 为 Running,READY 为 1/1 表示成功):
[root@k8s-master mysql-1]# kubectl get pod -n mysql-cluster mysql-master-79db8746fd-k9b4p --show-labels 
NAME                            READY   STATUS    RESTARTS   AGE    LABELS
mysql-master-79db8746fd-k9b4p   1/1     Running   0          101s   app=mysql,pod-template-hash=79db8746fd,role=master

[root@k8s-master mysql-1]# kubectl get pod -n mysql-cluster mysql-master-79db8746fd-k9b4p -o wide 
NAME                            READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
mysql-master-79db8746fd-k9b4p   1/1     Running   0          62s   10.244.169.156   k8s-node2   <none>           <none>
[root@k8s-master mysql-1]# kubectl get pods -n mysql-cluster -l app=mysql,role=master
NAME                            READY   STATUS    RESTARTS   AGE
mysql-master-79db8746fd-k9b4p   1/1     Running   0          83s
------------------------------------------------------------------------------------------------------------
# 3. 若状态异常(Pending/Error/CrashLoopBackOff),查看日志排查
# 替换 <pod-name> 为实际 Pod 名称
kubectl logs -n mysql-cluster <pod-name> --tail=100
------------------------------------------------------------------------------------------------------------
# 4. 验证主库配置是否生效(进入 Pod 查看 MySQL 配置)
kubectl exec -it -n mysql-cluster <pod-name> -- /bin/bash
# 登录 MySQL
mysql -u root -pShyshy521521!
# 查看主库关键配置(确认 server-id 和 log-bin 已启用)
show variables like 'server_id';  # 输出:1(与 ConfigMap 一致)
show variables like 'log_bin';    # 输出:ON(二进制日志已启用,主从复制基础)
exit && exit  # 退出 MySQL 和容器

#示例
[root@k8s-master mysql-1]# kubectl exec -it -n mysql-cluster mysql-master-79db8746fd-k9b4p -- /bin/bash
bash-4.4# mysql -u root -pShyshy521521!
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 62
Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 1     |
+---------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.01 sec)

mysql> exit && exit
    -> ^C
mysql> exit
Bye
bash-4.4# exit
exit
2. 配置主库复制权限(主从复制核心)

主从复制的原理是:从库通过「复制用户」连接主库,读取主库的二进制日志,同步数据。因此需要在主库创建复制用户并授权。

2.1 进入主库 Pod 并登录 MySQL
bash 复制代码
# 1. 查看主库 Pod 名称
kubectl get pods -n mysql-cluster -l app=mysql,role=master
# 2. 进入 Pod(替换 <pod-name> 为实际名称)
kubectl exec -it -n mysql-cluster <pod-name> -- /bin/bash
# 3. 用 root 登录 MySQL(密码:Shyshy521521!)
mysql -u root -pShyshy521521!
2.2 创建复制用户并授权
bash 复制代码
-- 1. 创建复制用户(repluser:复制用户名,%:允许所有 IP 连接,生产可限制为从库 IP)
CREATE USER 'repluser'@'%' IDENTIFIED BY 'Shyshy521521!';

-- 2. 授予复制权限(replication slave 是主从复制必需的权限,仅允许同步数据,无其他权限)
GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'%';

-- 3. 刷新权限(使授权立即生效)
FLUSH PRIVILEGES;

-- 4. 验证用户和权限(可选,确认配置正确)
SELECT user, host FROM mysql.user WHERE user = 'repluser';  # 能看到 repluser 用户
SHOW GRANTS FOR 'repluser'@'%';  # 能看到 replication slave 权限
------------------------------------------------------------------------------------------------------------
#示例
[root@k8s-master mysql-1]# kubectl exec -it -n mysql-cluster mysql-master-79db8746fd-k9b4p -- /bin/bash
bash-4.4# mysql -u root -pShyshy521521!
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 97
Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE USER 'repluser'@'%' IDENTIFIED BY 'Shyshy521521!';
Query OK, 0 rows affected (0.01 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'%';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.27 sec)

mysql> SELECT user, host FROM mysql.user WHERE user = 'repluser';
+----------+------+
| user     | host |
+----------+------+
| repluser | %    |
+----------+------+
1 row in set (0.00 sec)

mysql> SHOW GRANTS FOR 'repluser'@'%';
+--------------------------------------------------+
| Grants for repluser@%                            |
+--------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `repluser`@`%` |
+--------------------------------------------------+
1 row in set (0.00 sec)
2.3 锁定主库并记录二进制日志状态
mysql 复制代码
-- 1. 锁定主库(防止创建用户后有新数据写入,导致从库同步起点不一致)
FLUSH TABLES WITH READ LOCK;

-- 2. 查看主库状态(记录 File 和 Position 的值,从库配置时必须用!)
SHOW MASTER STATUS;

------------------------------------------------------------------------------------------------------------
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 |      864 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
  • File:主库当前二进制日志文件名(如 mysql-bin.000001
  • Position:日志文件中的偏移量(如 156
  • 注意:不要关闭当前终端,保持锁定状态,等两个从库都配置完成后再解锁!
3. 部署第一个从库(Slave1)

从库负责读取数据,与主库配置差异主要在 server-id 和只读配置,部署流程与主库类似。

3.1 从库 1 Deployment YAML(mysql-slave1-deployment.yaml
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-slave1  # 从库 1 名称,唯一标识
  namespace: mysql-cluster
  labels:
    app: mysql
    role: slave
    slave-id: "1"  # 关键修复:数字加引号,转为字符串类型(K8s 标签值必须是字符串)
spec:
  replicas: 1  # 从库单副本
  selector:
    matchLabels:
      app: mysql
      role: slave
      slave-id: "1"  # 选择器标签同步改为字符串
  template:
    metadata:
      labels:
        app: mysql
        role: slave
        slave-id: "1"  # Pod 标签同步改为字符串
    spec:
      containers:
      - name: mysql-slave1  # 容器名称
        image: mysql:8.0.32  # 与主库相同镜像,保证版本兼容
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3306
        env:
        # 1. root 密码(与主库一致,从 Secret 读取)
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets
              key: root-password
        # 2. 认证插件(与主库一致,保证兼容性)
        - name: MYSQL_AUTHENTICATION_PLUGIN
          value: mysql_native_password
        # 健康检查(与主库一致,确保从库正常运行)
        livenessProbe:
          tcpSocket:
            port: 3306
          initialDelaySeconds: 60
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            command: ["mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$(MYSQL_ROOT_PASSWORD)"]
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 3
        # 资源限制(与主库一致,保证性能)
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 1000m
            memory: 2Gi
        # 挂载配置文件和存储
        volumeMounts:
        # 1. 挂载从库配置文件(从 ConfigMap 读取 slave.cnf)
        - name: slave-config
          mountPath: /etc/mysql/conf.d/slave.cnf
          subPath: slave.cnf
        # 2. 挂载从库持久化存储
        - name: slave1-data
          mountPath: /var/lib/mysql
          subPath: mysql
      # 定义 volumes
      volumes:
      # 1. 从库配置文件卷(关联 ConfigMap 的 slave.cnf)
      - name: slave-config
        configMap:
          name: mysql-config
          items:
          - key: slave.cnf
            path: slave.cnf
      # 2. 从库存储卷(关联 slave1 的 PVC)
      - name: slave1-data
        persistentVolumeClaim:
          claimName: mysql-slave1-pvc
3.2 从库 YAML 与主库的核心差异解释
差异点 主库配置 从库配置 原因
metadata.labels role: master role: slave, slave-id: "1" 区分主从角色,同时用 slave-id 区分两个从库
volumeMounts[0] 挂载 master.cnf 挂载 slave.cnf 从库需要只读、中继日志等特有配置
volumes[1] 关联 mysql-master-pvc 关联 mysql-slave1-pvc 从库数据独立存储,避免与主库 / 其他从库冲突
env MYSQL_DATABASEMYSQL_USER 从库会同步主库的数据库和用户,无需单独初始化
3.3 部署从库 1 并验证
bash 复制代码
# 1. 部署从库 1
kubectl apply -f mysql-slave1-deployment.yaml
------------------------------------------------------------------------------------------------------------
# 2. 查看从库 1 Pod 状态
kubectl get pods -n mysql-cluster -l app=mysql,slave-id=1
# 预期输出:
[root@k8s-master mysql-1]# kubectl get pods -n mysql-cluster -l app=mysql,slave-id=1
NAME                            READY   STATUS    RESTARTS      AGE
mysql-slave1-557ffc7cfc-km4gc   1/1     Running   1 (93s ago)   103s

------------------------------------------------------------------------------------------------------------
# 3. 验证从库配置(进入 Pod)
kubectl exec -it -n mysql-cluster <slave1-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!
# 查看从库关键配置
show variables like 'server_id';  # 输出:2(与 ConfigMap 一致)
show variables like 'read_only';  # 输出:ON(从库只读配置生效)
show variables like 'relay_log';  # 输出:mysql-relay-bin(中继日志已启用)
exit && exit

#验证
[root@k8s-master mysql-1]# kubectl exec -it -n mysql-cluster mysql-slave1-86cdb9f5f6-tfk8x -- /bin/bash
bash-4.4# mysql -uroot -pShyshy521521!
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id     | 2     |
+---------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'read_only';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| read_only     | ON    |
+---------------+-------+
1 row in set (0.01 sec)

mysql> show variables like 'relay_log';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| relay_log     | mysql-relay-bin |
+---------------+-----------------+
1 row in set (0.00 sec)
4. 部署第二个从库(Slave2)

与 Slave1 配置基本一致,仅需修改 slave-id 和关联的 PVC,避免冲突。

4.1 从库 2 Deployment YAML(mysql-slave2-deployment.yaml
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-slave2  # 从库 2 名称,唯一标识
  namespace: mysql-cluster
  labels:
    app: mysql
    role: slave
    slave-id: "2"  # 修复:数字加双引号,转为字符串(K8s 标签值必须是字符串)
spec:
  replicas: 1  # 从库单副本
  selector:
    matchLabels:
      app: mysql
      role: slave
      slave-id: "2"  # 选择器标签同步改为字符串
  template:
    metadata:
      labels:
        app: mysql
        role: slave
        slave-id: "2"  # Pod 标签同步改为字符串
    spec:
      containers:
      - name: mysql-slave2  # 容器名称,与从库 1 区分
        image: mysql:8.0.32  # 兼容 CentOS 7.9 的镜像,与主库版本一致
        imagePullPolicy: IfNotPresent  # 优先使用本地镜像,加速部署
        ports:
        - containerPort: 3306  # MySQL 容器默认端口
        env:
        # 1. root 密码:从 Secret 读取,生产级安全(避免明文)
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secrets  # 关联之前创建的 Secret
              key: root-password   # Secret 中存储 root 密码的键
        # 2. 认证插件:与主库一致,兼容所有客户端
        - name: MYSQL_AUTHENTICATION_PLUGIN
          value: mysql_native_password
        # 存活探针:检测容器是否运行,异常自动重启
        livenessProbe:
          tcpSocket:
            port: 3306  # 检测 3306 端口连通性
          initialDelaySeconds: 60  # 启动后延迟 60 秒检测(给 MySQL 初始化时间)
          periodSeconds: 10  # 每 10 秒检测一次
          timeoutSeconds: 5  # 检测超时 5 秒
        # 就绪探针:检测容器是否能提供服务,避免启动中接收流量
        readinessProbe:
          exec:
            # 执行 mysqladmin ping 命令,验证 MySQL 可用
            command: ["mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$(MYSQL_ROOT_PASSWORD)"]
          initialDelaySeconds: 30  # 启动后延迟 30 秒检测
          periodSeconds: 5  # 每 5 秒检测一次
          timeoutSeconds: 3  # 检测超时 3 秒
        # 资源限制:避免 MySQL 占用过多资源,影响其他应用
        resources:
          requests:  # 最小资源需求(调度时保证分配)
            cpu: 500m  # 0.5 核 CPU
            memory: 1Gi  # 1GB 内存
          limits:  # 最大资源限制(防止资源滥用)
            cpu: 1000m  # 1 核 CPU
            memory: 2Gi  # 2GB 内存
        # 挂载配置文件和持久化存储
        volumeMounts:
        # 1. 挂载从库配置文件:从 ConfigMap 读取 slave.cnf
        - name: slave-config
          mountPath: /etc/mysql/conf.d/slave.cnf  # MySQL 自动加载此目录下的 .cnf 文件
          subPath: slave.cnf  # 只挂载 slave.cnf,避免覆盖目录内其他文件
        # 2. 挂载持久化存储:数据目录(核心,保证数据不丢失)
        - name: slave2-data
          mountPath: /var/lib/mysql  # MySQL 数据默认存储路径
          subPath: mysql  # 在 PV 中创建 mysql 子目录,隔离数据
      # 定义 volumes:关联 ConfigMap 和 PVC
      volumes:
      # 1. 从库配置文件卷:关联 mysql-config ConfigMap
      - name: slave-config
        configMap:
          name: mysql-config  # 关联之前创建的 ConfigMap
          items:
          - key: slave.cnf  # ConfigMap 中的配置文件名
            path: slave.cnf  # 挂载到容器内的文件名(保持一致)
      # 2. 从库存储卷:关联 slave2 的 PVC(独立存储,避免与其他节点冲突)
      - name: slave2-data
        persistentVolumeClaim:
          claimName: mysql-slave2-pvc  # 关联之前创建的 slave2 PVC
4.2 部署从库 2 并验证
复制代码
# 1. 部署从库 2
kubectl apply -f mysql-slave2-deployment.yaml

# 2. 查看从库 2 状态
kubectl get pods -n mysql-cluster -l app=mysql,slave-id=2
# 预期输出:
[root@k8s-master mysql-1]# kubectl get pods -n mysql-cluster -l app=mysql,slave-id=2
NAME                            READY   STATUS    RESTARTS      AGE
mysql-slave2-58fd746d86-knmf9   1/1     Running   1 (52s ago)   61s


# 3. 验证从库 2 配置(可选,与 Slave1 验证步骤一致)
kubectl exec -it -n mysql-cluster <slave2-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!
show variables like 'server_id';  # 输出:2(后续手动修改为 3,避免与 Slave1 冲突)
exit && exit
5. 配置主从复制(核心步骤)

两个从库都部署完成后,开始配置与主库的复制关系,让从库同步主库数据。

5.1 配置从库 1 同步主库
复制代码
# 1. 进入 Slave1 Pod
kubectl exec -it -n mysql-cluster <slave1-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!

# 2. 停止从库复制进程(首次配置可忽略,防止已有复制进程干扰)
STOP SLAVE;

# 3. 配置主库信息(替换以下参数为步骤 2.3 记录的主库状态)
CHANGE MASTER TO
MASTER_HOST='mysql-master-svc.mysql-cluster.svc.cluster.local',  # 主库 Service 名称(集群内 DNS 地址,自动解析主库 IP)
MASTER_PORT=3306,  # 主库端口
MASTER_USER='repluser',  # 复制用户
MASTER_PASSWORD='Shyshy521521!',  # 复制用户密码
MASTER_LOG_FILE='mysql-bin.000003',  # 步骤 2.3 记录的 File 值
MASTER_LOG_POS=864;  # 步骤 2.3 记录的 Position 值

# 4. 启动从库复制进程
START SLAVE;

# 5. 查看从库复制状态(关键!验证是否成功)
SHOW SLAVE STATUS\G;
关键验证指标(SHOW SLAVE STATUS\G 输出)
  • Slave_IO_Running: Yes(IO 线程运行正常:从库成功连接主库并下载二进制日志)
  • Slave_SQL_Running: Yes(SQL 线程运行正常:从库成功执行中继日志中的 SQL)
  • 若两个都是 Yes,表示从库 1 复制配置成功!
  • 若为 No,查看 Last_IO_ErrorLast_SQL_Error 字段,根据错误信息排查(常见错误:主库 IP 错误、复制用户密码错误、日志文件 / 位置错误)。
5.2 配置从库 2 同步主库(与 Slave1 步骤一致)
复制代码
# 1. 进入 Slave2 Pod
kubectl exec -it -n mysql-cluster <slave2-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!

# 2. 配置主库信息(参数与 Slave1 一致)
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='mysql-master-svc.mysql-cluster.svc.cluster.local',
MASTER_PORT=3306,
MASTER_USER='repluser',
MASTER_PASSWORD='Shyshy521521!',
MASTER_LOG_FILE='mysql-bin.000001',  # 与主库记录的一致
MASTER_LOG_POS=156;  # 与主库记录的一致

# 3. 启动复制并验证
START SLAVE;
SHOW SLAVE STATUS\G;
验证:两个从库的 Slave_IO_RunningSlave_SQL_Running 都为 Yes
5.3 解锁主库(所有从库配置完成后)

回到步骤 2.3 锁定主库的终端,执行以下命令解锁(允许主库写入数据):

复制代码
UNLOCK TABLES;  # 解锁主库,允许新数据写入
exit && exit  # 退出 MySQL 和容器
6. 部署主库 Service(外部可访问)

主库需要被外部应用访问(写入数据),用 NodePort 类型暴露服务(适合测试 / 小型生产环境)。

6.1 主库 Service YAML(mysql-master-service.yaml
复制代码
apiVersion: v1
kind: Service
metadata:
  name: mysql-master-svc  # 主库服务名称
  namespace: mysql-cluster
  labels:
    app: mysql
    role: master
spec:
  selector:
    app: mysql
    role: master  # 筛选主库 Pod(通过标签匹配)
  ports:
  - port: 3306  # Service 内部端口(集群内其他应用访问用)
    targetPort: 3306  # 映射到 Pod 的 3306 端口(MySQL 容器端口)
    nodePort: 30036  # 外部访问端口(范围 30000-32767,确保未被占用)
  type: NodePort  # 服务类型:NodePort(外部通过 节点IP:nodePort 访问)
  sessionAffinity: ClientIP  # 会话亲和性:同一客户端始终访问同一个 Pod(主库单副本,保证连接稳定)
6.2 YAML 字段解释
  • spec.selector:通过标签找到主库 Pod,确保流量转发到主库。
  • port: 3306:集群内应用访问主库的端口(如从库同步时用的 mysql-master-svc.mysql-cluster.svc:3306)。
  • nodePort: 30036:外部访问端口,比如本地电脑用 10.132.47.60:30036 连接主库。
  • type: NodePort:K8s 会在所有节点上开放 30036 端口,外部通过任意节点 IP + 该端口即可访问主库。
6.3 部署 Service 并验证外部访问
复制代码
# 1. 部署主库 Service
kubectl apply -f mysql-master-service.yaml

# 2. 查看 Service 状态
kubectl get svc -n mysql-cluster -l app=mysql,role=master
# 预期输出:
# NAME                TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
# mysql-master-svc    NodePort   10.96.xxx.xxx   <none>        3306:30036/TCP   1m

# 3. 开放防火墙端口(所有节点执行,否则外部无法访问)
firewall-cmd --zone=public --add-port=30036/tcp --permanent
firewall-cmd --reload

# 4. 外部访问验证(在集群外的电脑执行,如本地 Windows/Mac)
mysql -h 10.132.47.60 -P 30036 -u root -pShyshy521521!
# 若连接成功,进入 MySQL 命令行,说明外部访问生效!

九、验证主从复制集群可用性(最终测试)

通过在主库写入数据,验证两个从库是否自动同步,确认集群正常工作。

1. 主库写入测试数据
复制代码
# 1. 外部连接主库(或进入主库 Pod)
mysql -h 10.132.47.60 -P 30036 -u root -pShyshy521521!

# 2. 切换到业务库 appdb
use appdb;

# 3. 创建测试表并插入数据
CREATE TABLE test_sync (
  id INT PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(20) NOT NULL,
  create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO test_sync (name) VALUES ('主库测试数据1'), ('主库测试数据2');

# 4. 查看数据(主库应显示 2 条数据)
SELECT * FROM test_sync;
2. 从库 1 验证同步数据
bash 复制代码
# 1. 进入 Slave1 Pod
kubectl exec -it -n mysql-cluster <slave1-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!

# 2. 切换到 appdb 库(应自动同步主库的库和表)
use appdb;

# 3. 查看测试表数据(应与主库一致,显示 2 条数据)
SELECT * FROM test_sync;
3. 从库 2 验证同步数据
bash 复制代码
# 1. 进入 Slave2 Pod
kubectl exec -it -n mysql-cluster <slave2-pod-name> -- /bin/bash
mysql -u root -pShyshy521521!

# 2. 切换到 appdb 库
use appdb;

# 3. 查看测试表数据(应与主库一致)
SELECT * FROM test_sync;
4. 验证从库只读(生产关键)

在从库 1 尝试写入数据,验证只读配置生效:

bash 复制代码
# 在 Slave1 的 MySQL 命令行执行
INSERT INTO test_sync (name) VALUES ('从库写入测试');
# 预期报错:ERROR 1290 (HY000): The MySQL server is running with the --read-only option so it cannot execute this statement
相关推荐
ζั͡山 ั͡有扶苏 ั͡✾2 小时前
完善EKF可观测性体系:基于ElastAlert2构建k8s智能钉钉日志告警系统
容器·kubernetes·钉钉·kibana·filebeat·日志监控
i小杨2 小时前
Docker 相关使用收录
docker·容器·eureka
猪在黑魔纹里2 小时前
docker run hello-world失败、报错
linux·docker·容器
陈陈CHENCHEN2 小时前
【Kubernetes】K8s 集群 Ingress 入口规则
kubernetes
一枚正在学习的小白2 小时前
k8s的包管理工具(5)--读取文件内容
云原生·容器·kubernetes
就叫飞六吧2 小时前
MySQL不停机迁移完全指南
数据库·mysql
❀͜͡傀儡师3 小时前
docker一键部署PDF免费工具箱stirling-PDF
docker·容器·pdf
q***42053 小时前
在Spring Boot项目中使用MySQL数据库
数据库·spring boot·mysql
zz-zjx4 小时前
docker进阶---docker底层实践2025
运维·docker·容器