MySQL Operator 在 Kubernetes 中的部署与运维全指南
MySQL Operator 摘要 Bitpoke MySQL Operator 是一个用于在 Kubernetes 上部署和管理高可用 MySQL 集群的 Kubernetes Operator,基于 Percona Server 和 Openark Orchestrator 实现主从复制。主要特点包括: 架构组成:包含7个核心控制器,管理MySQL集群、数据库、用户、备份等功能。
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_PASSWORD、USER、PASSWORD、DATABASE。请注意,它们仅在集群引导时使用一旦集群初始化完成,更改 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 相关的配置。(例如imagePullSecrets,labels) |
{} | |
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
更多推荐




所有评论(0)