MySQL Operator

一、概述

1.1 概述

Bitpoke MySQL Operator 是一个用于在 Kubernetes 上部署和管理高可用 MySQL 集群的 Kubernetes Operator。它基于 Percona Server 和 Openark 的 Orchestrator 实现异步 MySQL 主从复制。

  • GitHub 仓库:https://github.com/bitpoke/mysql-operator
  • 维护者:Bitpoke 公司
  • 目标用户:希望在 Kubernetes 上运行稳定、高可用、可扩展的 MySQL 集群的 DevOps 和开发者
  • 适用场景:WordPress 托管、云原生数据库部署、MySQL 高可用集群管理

主要目标

  • 在 Kubernetes 中轻松部署 MySQL 集群(每个服务一个集群模型)
  • 对 DevOps 友好(解决了监控、可用性、可扩展性和备份问题)
  • 开箱即用的备份(计划和按需)和时间点恢复
  • 支持集群内和跨集群克隆。

1.2 架构

mysql-operator组件图:

在这里插入图片描述

controller组件

在bitpoke/mysql-operator主要7个controller中,主要包括:

  • mysqlcluster-controller
    主要负责CRD资源实例mysqlcluster的管理,主要功能为mysql实例的管理

  • mysqldatabase-controller
    主要负责CRD资源实例mysqldatabase管理,主要功能为mysql的database的创建

  • mysqluser-controller
    主要负责CRD资源实例mysqluser管理,主要功能为mysql的user的创建

  • mysqlbackup-controller
    主要负责CRD资源mysqlbackup管理,主要功能通过xtrabackup工具对mysql进行备份操作

  • mysqlbackupcron-controller
    主要负责为mysql集群提供定时备份的功能,其内部通过定时拉起mysqlbackup的任务

  • node-controller
    主要负责对mysql实例进行管理,针对replica角色进行预处理

  • orchestrator-controller
    主要通过orchestrator组件,对mysql实例进行角色仲裁

CRD资源

  • mysqlcluster

  • mysqldatabase

  • mysqluser

  • mysqlbackup

二、部署

通过helm部署

2.1 添加bitpoke helm仓库

helm repo add bitpoke https://helm-charts.bitpoke.io

2.2 安装mysql operator

helm install \
  --namespace mysql-operator \
  --create-namespace \
  mysql-operator \
  bitpoke/mysql-operator

2.3 验证mysql operator的安装

检查指定命名空间的内容(minio-operator)以确保所有 pod 和服务都已成功启动。

root@k8s-master01:~# kubectl get all -n mysql-operator
NAME                   READY   STATUS    RESTARTS   AGE
pod/mysql-operator-0   2/2     Running   0          44s

NAME                               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)            AGE
service/mysql-operator             ClusterIP   10.244.25.45    <none>        80/TCP,9125/TCP    44s
service/mysql-operator-0-orc-svc   ClusterIP   10.244.18.222   <none>        80/TCP,10008/TCP   44s

NAME                              READY   AGE
statefulset.apps/mysql-operator   1/1     44s

三、部署MySQL集群

前言

在部署mysql集群之前,需要创建一个包含 ROOT_PASSWORD 键的 secret

root@k8s-master01:~/mysql# cat my-cluster-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  # root password is required to be specified
  ROOT_PASSWORD: UEBzc3cwcmQ=
  # a user name to be created, not required
  USER: dXNlcm5hbWU=
  # a password for user, not required
  PASSWORD: dXNlcnBhc3Nz
  # a name for database that will be created, not required
  DATABASE: dXNlcmRi

字段说明

字段名 是否必需 含义 Base64 解码值
ROOT_PASSWORD ✅ 是 MySQL root 用户密码 not-so-secure
USER ❌ 否 创建的普通用户 username
PASSWORD ❌ 否 普通用户的密码 userpass
DATABASE ❌ 否 自动创建的数据库名称 userdb

此 secret 包含用于连接集群的凭证信息,例如ROOT_PASSWORDUSERPASSWORDDATABASE。请注意,它们仅在集群引导时使用一旦集群初始化完成,更改 Secret 中的字段不会影响已经运行的 MySQL 实例。

3.1 部署集群

现在,要创建集群,您只需要一个定义它的简单 YAML 文件。创建一个名为的文件 my-cluster.yaml,并将以下 YAML 代码复制到其中:

root@k8s-master01:~/mysql# cat my-cluster.yaml
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  replicas: 2
  secretName: my-secret

官方示例文件:https://github.com/bitpoke/mysql-operator/blob/master/examples/example-cluster.yaml

请确保集群名称不要太长,否则集群将无法向 Orchestrator 注册。请参阅问题 #170 了解更多信息。

要部署集群,请运行以下命令,它将生成一个包含凭据和MySQLCluster资源的密钥到 Kubernetes 中。

$ kubectl apply -f my-cluster-secret.yaml
$ kubectl apply -f my-cluster.yaml

3.2 MysqlCluster 配置概述

字段名称 描述 例子 默认值
replicas 集群副本,部署多少个节点。 2 1(单个节点)
secretName 凭证密钥的名称。应与集群位于同一命名空间中。 my-secret is required
initBucketURL 集群初始化备份所用的 S3 URL s3://my-bucket/backup.xbackup.gz “”
initBucketSecretName 初始化时读取的 S3 凭证的秘密 backups-secret “”
backupSchedule 表示进行集群备份的时间和频率,以秒为单位的 cron 格式。 0 0 0 * * * “”
backupURL 放置备份的存储桶 URL。 gs://bucket/app “”
backupSecretName 包含用于连接存储提供商的凭据的secret的名称。 backups-secret “”
backupScheduleJobsHistoryLimit 要保留的备份数量。 10 inf
image 指定用于 MySQL 服务器容器的自定义 Docker 镜像。 percona:5.7-centos nil
mysqlConf MySQL 的键值配置将在下一部分中my.cnf设置mysqld max_allowed_packet: 128M {}
podSpec 这允许指定与 pod 相关的配置。(例如imagePullSecretslabels {}
volumeSpec 用于存储数据的 PVC、HostPath 或 EmptyDir 的规范。 (PVC 大小 = 1GB)
maxSlaveLatency 允许从属设备滞后直至其从读取服务中移除。(以秒为单位) 30 nil
queryLimits pt-kill 的参数用于确保某些查询运行限制。(例如空闲时间) idleTime: 60 nil
readOnly 将集群设置为只读状态的布尔值。 True False

3.3 持久卷配置

配置pvc示例2

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  secretName: my-secret
  volumeSpec:
    persistentVolumeClaim:
      storageClassName: nfs-client
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi

HostPath使用或EmptyDir作为数据卷源的示例是:

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  secretName: my-secret
  volumeSpec:
    hostPath:
      path: /path/to/host/dir/
    ## or use emptyDir
    # emptyDir: {}

默认情况下,operator会在集群上设置一些合理的默认值。这些配置可以 在这里找到 。此外,innodb-buffer-pool-size和 也是innodb-log-file-size根据请求的内存进行配置的,如本文 所述

指定的 MySQL 配置.spec.mysqlConf优先于默认值。

四、Orchestrator配置

MySQL Operator 使用 Orchestrator ,这是 GitHub 最初为 MySQL 复制拓扑管理和高可用性开发的工具。默认情况下,Orchestrator 与 Bitpoke MySQL Operator 一起部署。

访问Orchestrator

该服务<release-name>-mysql-operator公开 80 端口,因此您可以通过该端口与 Orchestrator Leader 通信。您可以将此服务端口转发到本地主机,或者使用负载均衡器类型的服务,或者启用 Ingress。

在这里插入图片描述

五、集群备份和恢复

备份存储在对象存储服务(如 S3 或 Google Cloud Storage)上。

为了能够存储备份,下面定义的 secretbackupSecretName必须具有存储这些备份的凭据。备份使用 Rclone上传 。secret 的内容用于在 docker-entrypoint.sh中生成 rclone.conf 文件 。

5.1 在s3上设置备份

您需要backupBucketURL为集群指定一个 URL(如)s3://BUCKET_NAME,以及一个密钥。

创建一个名为的文件example-backup-secret.yaml并将以下 YAML 代码复制到其中:

示例:
apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-backup-secret
type: Opaque
data:
  AWS_ACCESS_KEY_ID: #
  AWS_SECRET_ACCESS_KEY: #
  # Optional, the AWS region to connect
  # AWS_REGION: us-east1
  # Optional, specify the storage class
  # AWS_STORAGE_CLASS: STANDARD
  # Optional, canned ACL to use
  # AWS_ACL:
  # Optional, the S3 provider to use (default: AWS)
  # S3_PROVIDER: AWS
  # Optional, the S3 endpoint to use (for when you use a different S3_PROVIDER)
  # S3_ENDPOINT:

字段说明

所有字段的值都必须是 Base64 编码,因为这是 Kubernetes Secret 的要求。

字段名 是否必需 含义 示例值(Base64 解码后)
AWS_ACCESS_KEY_ID ✅ 是 AWS S3 访问密钥 ID your-access-key-id
AWS_SECRET_ACCESS_KEY ✅ 是 AWS S3 私有访问密钥 your-secret-access-key
AWS_REGION ❌ 否 AWS S3 区域 us-east-1
AWS_STORAGE_CLASS ❌ 否 存储类别(如 STANDARD、GLACIER) STANDARD
AWS_ACL ❌ 否 S3 对象的访问控制列表(ACL) private, public-read
S3_PROVIDER ❌ 否 使用的 S3 提供商,默认是 AWS AWS, MINIO
S3_ENDPOINT ❌ 否 自定义 S3 服务地址(用于非 AWS 场景) https://minio.example.com:9000

部署

$ kubectl apply -f example-backup-secret.yaml

5.2 配置minio存储备份

1)创建secret用于存储连接minio的凭据

这里s3地址用 svc的地址
echo  -n "http://minio.minio-server.svc.cluster.local:80" | base64
# -n:表示不添加末尾换行符(非常重要,否则换行符也会被编码)
echo -n "minio" | base64
echo -n "P@ssw0rd" | base64
root@k8s-master01:~/mysql# cat my-cluster-backup-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-cluster-backup-secret
type: Opaque
data:
  AWS_ACCESS_KEY_ID: bWluaW8=  # minio
  AWS_SECRET_ACCESS_KEY: UEBzc3cwcmQ= # P@ssw0rd
  S3_ENDPOINT: aHR0cDovL21pbmlvLm1pbmlvLXNlcnZlci5zdmMuY2x1c3Rlci5sb2NhbDo4MA==
  # http://minio.minio-server.svc.cluster.local:80
  S3_PROVIDER: TWluaW8=  # Minio

2)创建备份

root@k8s-master01:~/mysql# cat my-cluster-backup.yaml
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlBackup
metadata:
  name: my-cluster-backup
spec:
  clusterName: my-cluster

3)在mysqlcluster中配置

root@k8s-master01:~/mysql# cat my-cluster.yaml
apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  replicas: 2
  secretName: my-secret
  backupSecretName: my-cluster-backup-secret   #指定secret名字
  backupURL: s3://mysql/

4)部署

root@k8s-master01:~/mysql# kubectl apply -f my-cluster-secret.yaml
secret/my-secret created
root@k8s-master01:~/mysql# kubectl apply -f my-cluster-backup-secret.yaml
secret/my-cluster-backup-secret created
root@k8s-master01:~/mysql# kubectl apply -f my-cluster.yaml
mysqlcluster.mysql.presslabs.org/my-cluster created

5)查看mysql集群部署详情

root@k8s-master01:~# kubectl get all
NAME                                          READY   STATUS    RESTARTS         AGE
pod/my-cluster-mysql-0                        4/4     Running   2 (6m25s ago)    6m50s
pod/my-cluster-mysql-1                        4/4     Running   0                6m4s

service/my-cluster-mysql            ClusterIP   10.244.55.180   <none>        3306/TCP            6m50s
service/my-cluster-mysql-master     ClusterIP   10.244.3.7      <none>        3306/TCP,8080/TCP   6m50s
service/my-cluster-mysql-replicas   ClusterIP   10.244.38.215   <none>        3306/TCP,8080/TCP   6m50s
service/mysql                       ClusterIP   None            <none>        3306/TCP,9125/TCP   15h

NAME                                READY   AGE
statefulset.apps/my-cluster-mysql   2/2     6m50s

5)查看备份状态

root@k8s-master01:~/mysql# kubectl describe mysqlbackup my-cluster-backup
Name:         my-cluster-backup
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  mysql.presslabs.org/v1alpha1
Kind:         MysqlBackup
Metadata:
  Creation Timestamp:  2025-07-19T01:57:07Z
  Generation:          3
  Resource Version:    1416566
  UID:                 ca9698c1-7cfb-4dd4-8535-f3b50827dbff
Spec:
  Backup Secret Name:    my-cluster-backup-secret
  Backup URL:            s3://mysql/my-cluster-backup.xbackup.gz
  Cluster Name:          my-cluster
  Remote Delete Policy:  retain
Status:
  Completed:  true
  Conditions:
    Last Transition Time:  2025-07-19T01:57:15Z
    Message:               Reached expected number of succeeded pods
    Reason:                CompletionsReached
    Status:                True
    Type:                  Complete
Events:
  Type    Reason              Age   From                    Message
  ----    ------              ----  ----                    -------
  Normal  JobSyncSuccessfull  29s   mysqlbackup-controller  batch/v1, Kind=Job default/my-cluster-backup-backup created successfully

5.3从备份初始化集群

MySQL 操作符提供了一种基于备份(快照)重新创建集群的方法。只需创建一个新的集群,并赋予其新名称,使其initBucketURL字段指向正确的备份即可。

要从备份初始化新集群,只需将 设置initBucketURL为要使用的备份。连接到存储提供商的凭据应在 字段中指定的密钥中设置,与备份部分中显示 initBucketSecretName的 相同 。这些字段可以指向同一个密钥。backupSecretName

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  secretName: the-secret

  initBucketURL: gs://bucket_name/path/to/backup.xbackup.gz
  initBucketSecretName: backup-secret

此配置为您提供了一个从指定备份初始化的新集群gs://bucket_name/path/to/backup.xbackup.gz

六、定期备份

6.1 为 MySQL 集群设置定期备份

为 MySQL 集群配置一个自动定时备份任务,使集群能够按照指定的时间周期(如每天、每周)将数据备份到指定的 S3 存储桶中。要设置自动备份,需要配置backupSchedule字段,使用 crontab 格式。

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  replicas: 2
  backupSchedule: "0 0 0 * * *" # 每天0点备份一次
  secretName: my-secret
  backupSecretName: my-cluster-backup-secret   #指定secret名字
  backupURL: s3://mysql/   # 备份上传的目标 S3 存储桶
  backupRemoteDeletePolicy: retain|delete  #备份保留策略(retain 保留,delete 删除)

Crontab 接受 6 个参数,而不是传统的 5 个。额外的参数是秒字段。

在cron中每项工作的格式都是具有六个字段,这六个字段的意义为

分钟 小时 日期 月份
0-59 0-59 0-23 1-31 1-12 0-7

以下是一些 crontab 示例及其预定义的调度程序:

示例 描述
15 0 0 1 1 * 每年运行一次,1 月 1 日凌晨0点 15 秒
0 0 0 1 * * 每月运行一次,每月1号0点0秒
0 0 0 * * 0 每周运行一次,周日0点0秒
0 0 0 * * * 每天运行一次,0点0秒
0 0 * * * * 每小时运行一次

查看备份情况,mysql operator会动态的生成job去执行备份操作

root@k8s-master01:~/mysql# kubectl get pod
NAME                                               READY   STATUS      RESTARTS         AGE
my-cluster-auto-2025-07-19t02-01-21-backup-7lpqz   0/1     Completed   0                5m4s
my-cluster-auto-2025-07-19t02-01-28-backup-c9slr   0/1     Completed   0                4m57s
my-cluster-auto-2025-07-19t02-04-47-backup-rgpqk   0/1     Completed   0                98s
my-cluster-auto-2025-07-19t02-05-30-backup-fd7kj   0/1     Completed   0                55s
my-cluster-auto-2025-07-19t02-05-37-backup-xvl6x   0/1     Completed   0                48s
my-cluster-auto-2025-07-19t02-05-44-backup-2hfd2   0/1     Completed   0                41s
my-cluster-auto-2025-07-19t02-05-51-backup-hknqw   0/1     Completed   0                34s
my-cluster-auto-2025-07-19t02-05-58-backup-tm5vv   0/1     Completed   0                27s
my-cluster-auto-2025-07-19t02-06-05-backup-98sl8   0/1     Completed   0                20s
my-cluster-auto-2025-07-19t02-06-12-backup-5hsjc   0/1     Completed   0                13s
my-cluster-auto-2025-07-19t02-06-19-backup-m7hnw   0/1     Completed   0                6s
my-cluster-backup-backup-g82sw                     0/1     Completed   0                9m18s
my-cluster-mysql-0                                 4/4     Running     2 (18m ago)      19m
my-cluster-mysql-1                                 4/4     Running     0                18m
nfs-client-provisioner-67fbfc5d9c-95n6k            1/1     Running     34 (4m44s ago)   2d22h

在Minio中查看备份详情

在这里插入图片描述

6.2 禁用 MySQL 集群的定期备份

配置backupSchedule: ""为即可

apiVersion: mysql.presslabs.org/v1alpha1
kind: MysqlCluster
metadata:
  name: my-cluster
spec:
  secretName: my-secret
  backupSchedule: ""  # 设置为空字符串将禁用重复备份
  backupSecretName: my-cluster-backup-secret
  backupURL: s3://mysql/
  backupRemoteDeletePolicy: retain|delete
Logo

一站式 AI 云服务平台

更多推荐