K8s部署MySQL与Ceph存储整合方案详解
1. 项目概述:K8s部署MySQL与Ceph存储整合方案
在云原生架构中,数据库与存储的容器化部署一直是企业级应用的关键环节。最近我在生产环境完成了MySQL on K8s with Ceph的完整部署方案,这个组合完美解决了有状态服务在K8s中的持久化存储难题。传统方案中,MySQL直接使用本地存储或云厂商提供的块存储服务,存在单点故障风险且扩展性受限。而Ceph作为开源的统一分布式存储系统,通过RBD(RADOS Block Device)为K8s提供高可用的块存储服务,使MySQL实例能够像无状态服务一样自由调度。
这个方案的核心价值在于:
- 数据高可用:Ceph的多副本机制确保即使单个节点故障,MySQL数据也不会丢失
- 弹性扩展:存储容量可随业务需求动态调整,无需停机迁移
- 性能可控:Ceph支持SSD/NVMe缓存分层,能满足不同级别的IOPS需求
- 运维标准化:所有资源通过K8s声明式API管理,降低运维复杂度
2. 环境准备与组件选型
2.1 基础环境要求
在开始部署前,需要确保以下基础环境就位:
# K8s集群节点建议配置(生产环境)
控制平面节点:4核CPU/8GB内存/100GB磁盘 x3(高可用部署)
工作节点:8核CPU/16GB内存/200GB磁盘(需预留Ceph OSD磁盘空间)
网络:万兆网络(Ceph对网络带宽敏感)
特别注意:Ceph OSD磁盘必须使用裸设备(未格式化的磁盘),不能使用已有文件系统的磁盘。建议为每个OSD准备单独的SSD或高性能HDD。
2.2 Ceph集群部署方案选择
目前主流的Ceph部署方式有三种:
-
Rook Operator (推荐):
- 优点:全自动化部署,与K8s深度集成,支持CRD管理
- 缺点:对底层硬件抽象较多,调试复杂问题需要熟悉Operator逻辑
-
Cephadm :
- 优点:官方维护,支持最新Ceph版本
- 缺点:需要额外管理节点,与K8s集成度一般
-
手动部署 :
- 优点:完全可控,适合定制化需求
- 缺点:运维成本高,升级困难
对于K8s环境,我强烈推荐使用Rook部署方案。以下是Rook的核心组件:
graph TD
Rook_Operator -->|管理| CephCluster
CephCluster -->|包含| MONs
CephCluster -->|包含| OSDs
CephCluster -->|包含| MGRs
Rook_Operator -->|提供| StorageClass
2.3 MySQL版本选择考量
MySQL在K8s中的部署需要考虑以下版本特性:
| 版本 | 容器化支持 | Group Replication | 内存管理 | 推荐场景 |
|---|---|---|---|---|
| 5.7 | 基础支持 | 需要额外配置 | 较简单 | 传统应用迁移 |
| 8.0 | 优化支持 | 原生支持 | 精细化 | 新建云原生应用 |
建议选择MySQL 8.0+版本,其对分布式场景的支持更完善。特别是以下特性非常有用:
- 原子DDL操作
- 改进的Group Replication
- 更好的内存管理(新增memory_limit参数)
3. Ceph集群部署实战
3.1 通过Rook部署Ceph集群
首先创建Rook的命名空间和Operator:
kubectl create namespace rook-ceph
kubectl apply -f https://raw.githubusercontent.com/rook/rook/release-1.8/cluster/examples/kubernetes/ceph/operator.yaml
等待Operator就绪后,部署Ceph集群配置文件:
# cluster.yaml
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
dataDirHostPath: /var/lib/rook
mon:
count: 3
allowMultiplePerNode: false
cephVersion:
image: ceph/ceph:v16.2.7
storage:
useAllNodes: false
useAllDevices: false
nodes:
- name: "worker-node1"
devices:
- name: "sdb" # 必须是裸设备
- name: "worker-node2"
devices:
- name: "sdb"
dashboard:
enabled: true
应用配置并验证状态:
kubectl apply -f cluster.yaml
# 检查部署状态
kubectl -n rook-ceph get pods -w
常见问题:如果OSD pods一直处于Pending状态,通常是因为:
- 指定设备已被占用(检查lsblk)
- 节点没有正确标签(需要添加rook.io/storage-node=true)
- 节点资源不足(特别是内存)
3.2 创建StorageClass供MySQL使用
Ceph通过RBD提供块存储服务,需要创建对应的StorageClass:
# storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: rook-ceph-block
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
clusterID: rook-ceph
pool: replicapool
imageFormat: "2"
imageFeatures: layering
csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Retain
allowVolumeExpansion: true
关键参数说明:
-
pool: 使用的Ceph存储池,建议为数据库单独创建pool -
reclaimPolicy: 生产环境建议设为Retain,避免误删PV导致数据丢失 -
allowVolumeExpansion: 启用存储卷扩容功能
4. MySQL在K8s中的部署方案
4.1 StatefulSet部署模型
MySQL作为有状态服务,必须使用StatefulSet进行部署。以下是核心配置要点:
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql"
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secrets
key: rootPassword
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "rook-ceph-block"
resources:
requests:
storage: 20Gi
关键设计考量:
- 副本数 :生产环境建议至少3个副本以实现高可用
- 存储大小 :根据数据量预估,建议初始20GB并预留扩容空间
- 资源配置 :MySQL 8.0建议每个实例至少分配4核CPU和8GB内存
4.2 数据持久化验证
部署完成后,验证数据持久化是否正常工作:
# 连接到MySQL pod
kubectl exec -it mysql-0 -- mysql -uroot -p
# 创建测试数据库
CREATE DATABASE ceph_test;
USE ceph_test;
CREATE TABLE test_data (id INT PRIMARY KEY, value VARCHAR(255));
INSERT INTO test_data VALUES (1, 'persistence_test');
# 删除pod并验证数据
kubectl delete pod mysql-0
# 等待K8s重建pod后再次连接,检查数据是否存在
4.3 性能优化配置
在Ceph RBD上运行MySQL需要特别关注以下性能参数:
-
Ceph端配置 :
# 在Ceph配置中增加以下参数 [osd] osd_op_num_threads_per_shard = 4 osd_op_num_shards = 8 rbd_cache = true rbd_cache_size = 256MB -
MySQL端配置 :
# my.cnf关键参数 [mysqld] innodb_buffer_pool_size = 4G # 建议为系统内存的50-70% innodb_io_capacity = 2000 innodb_io_capacity_max = 4000 innodb_flush_neighbors = 0 # SSD环境下建议禁用 innodb_flush_method = O_DIRECT -
K8s存储类参数优化 :
parameters: mapOptions: lock_on_read,queue_depth=1024 csi.volumeAttributes: mounter: rbd-nbd # 使用内核模块提升性能 disableInUseChecks: "true"
5. 高可用与备份方案
5.1 MySQL Group Replication配置
在K8s中实现MySQL高可用的最佳实践是使用Group Replication:
-- 在每个MySQL实例上执行
SET SQL_LOG_BIN=0;
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
SET SQL_LOG_BIN=1;
-- 在第一个节点上
SET GLOBAL group_replication_bootstrap_group=ON;
START GROUP_REPLICATION;
SET GLOBAL group_replication_bootstrap_group=OFF;
-- 在其他节点上
START GROUP_REPLICATION;
对应的K8s Service配置需要支持读写分离:
apiVersion: v1
kind: Service
metadata:
name: mysql-read
spec:
ports:
- name: mysql
port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: v1
kind: Service
metadata:
name: mysql-write
spec:
ports:
- name: mysql
port: 3306
selector:
app: mysql
statefulset.kubernetes.io/pod-name: mysql-0 # 只指向主节点
5.2 基于Ceph快照的备份方案
利用Ceph的快照功能实现MySQL的时间点恢复:
# 创建快照
rbd snap create replicapool/csi-vol-<pv-id>@snap-$(date +%Y%m%d)
# 定期快照策略(CronJob示例)
apiVersion: batch/v1
kind: CronJob
metadata:
name: mysql-snapshot
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: rbd-snap
image: ceph/ceph:v16
command:
- /bin/sh
- -c
- |
rbd snap create replicapool/csi-vol-$(kubectl get pvc mysql-data-mysql-0 -o jsonpath='{.spec.volumeName}')@snap-$(date +%Y%m%d)
rbd snap ls replicapool/csi-vol-$(kubectl get pvc mysql-data-mysql-0 -o jsonpath='{.spec.volumeName}')
恢复数据时,可以基于快照创建新的PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-restore
spec:
storageClassName: rook-ceph-block
dataSource:
name: snap-20230801
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
6. 监控与运维实践
6.1 监控体系搭建
完整的监控需要覆盖三个层面:
-
Ceph集群监控 :
- 通过Rook自带的Prometheus exporter暴露指标
- 关键指标:OSD状态、存储池使用率、IOPS延迟
-
MySQL监控 :
- 使用mysqld_exporter采集数据库指标
- 关键指标:查询延迟、连接数、缓冲池命中率
-
K8s资源监控 :
- 通过kube-state-metrics获取PVC/PV状态
- 关键指标:存储卷容量、IOPS限制
示例Grafana监控面板配置:
-- MySQL关键查询
SELECT
SUM(COUNT_STAR) AS QPS,
SUM(SUM_TIMER_WAIT)/SUM(COUNT_STAR)/1e9 AS avg_latency
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST_TEXT NOT LIKE '%performance_schema%';
6.2 日常运维命令速查
Ceph常用命令 :
# 检查集群状态
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph -s
# 查看OSD使用情况
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd df
# 调整存储池副本数
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph osd pool set replicapool size 3
MySQL运维命令 :
# 快速检查Group Replication状态
kubectl exec -it mysql-0 -- mysql -uroot -p -e "SELECT * FROM performance_schema.replication_group_members"
# 手动故障转移(当主节点失效时)
kubectl exec -it mysql-1 -- mysql -uroot -p -e "SELECT group_replication_set_as_primary('mysql-1.mysql.default.svc.cluster.local:3306')"
6.3 性能调优实战案例
案例1:解决高并发写入延迟问题
现象:MySQL在业务高峰期出现写入延迟增加,Ceph监控显示OSD队列深度持续高位。
解决方案:
-
调整Ceph OSD线程数:
ceph tell osd.* injectargs '--osd_op_num_threads_per_shard 8' -
优化MySQL事务提交频率:
innodb_flush_log_at_trx_commit = 2 # 平衡性能与持久性 sync_binlog = 1000 -
增加RBD缓存大小:
parameters: rbd_cache_size: "512MB"
案例2:存储卷扩容操作
当MySQL数据增长需要扩容PVC时:
# 1. 编辑PVC定义
kubectl edit pvc mysql-data-mysql-0
# 修改spec.resources.requests.storage为所需大小
# 2. 在Ceph端确认扩容
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- rbd info replicapool/csi-vol-<pv-id>
# 3. 在MySQL内部确认文件系统已扩容
kubectl exec -it mysql-0 -- df -h /var/lib/mysql
7. 故障排查与问题解决
7.1 常见问题速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| MySQL pod一直CrashLoopBackOff | 数据目录权限问题 | 设置initContainer修正权限 |
| Ceph OSD无法启动 | 设备已被占用 | 使用lsblk检查设备,清理残留分区 |
| 存储卷无法扩容 | StorageClass未允许扩容 | 修改allowVolumeExpansion: true |
| Group Replication无法同步 | 网络策略限制 | 检查Calico/NetworkPolicy配置 |
| RBD挂载超时 | 内核模块缺失 | 节点安装rbd-nbd工具 |
7.2 数据恢复实战
当误删重要数据时,可以通过以下步骤恢复:
- 从最近的快照创建新PVC
- 启动临时MySQL实例挂载该PVC
- 使用mysqldump导出需要的数据
- 将数据导入生产数据库
具体操作:
# 1. 创建恢复用的PVC
kubectl apply -f mysql-restore.yaml
# 2. 启动临时MySQL实例
kubectl run mysql-restore --image=mysql:8.0 --restart=Never \
--overrides='{"spec":{"volumes":[{"name":"mysql-data","persistentVolumeClaim":{"claimName":"mysql-restore"}}],"containers":[{"name":"mysql","image":"mysql:8.0","volumeMounts":[{"name":"mysql-data","mountPath":"/var/lib/mysql"}]}]}}'
# 3. 导出数据
kubectl exec -it mysql-restore -- mysqldump -uroot -p dbname > dump.sql
# 4. 导入生产库
kubectl cp dump.sql mysql-0:/tmp/
kubectl exec -it mysql-0 -- mysql -uroot -p dbname < /tmp/dump.sql
7.3 关键日志收集
当出现问题时,需要收集以下关键日志:
-
Ceph相关 :
kubectl -n rook-ceph logs deploy/rook-ceph-operator kubectl -n rook-ceph logs deploy/rook-ceph-osd-0 -
MySQL相关 :
kubectl logs mysql-0 kubectl exec -it mysql-0 -- cat /var/log/mysql/error.log -
存储插件日志 :
kubectl -n rook-ceph logs deploy/csi-rbdplugin-provisioner
对于复杂问题,建议同时收集以下信息:
-
kubectl describe pod/mysql-0 -
kubectl get events --sort-by=.metadata.creationTimestamp -
Ceph状态输出:
ceph -s和ceph osd df
更多推荐
所有评论(0)