1. 项目概述
在云原生环境中,数据库的高可用性和持久化存储一直是关键挑战。本文将详细介绍如何在Kubernetes集群中使用Ceph RBD作为后端存储部署MySQL数据库。这种架构结合了Kubernetes的编排能力和Ceph的分布式存储优势,为MySQL提供了企业级的存储解决方案。
我最近在一个生产环境中成功实施了这种方案,使用的是OpenEuler 22.04操作系统、Ceph 16.2.7(Pacific版本)和Kubernetes 1.32.2。这种组合特别适合需要高可用性和数据持久化的场景,比如电商平台的订单数据库或金融系统的交易记录存储。
2. 环境准备与架构设计
2.1 基础环境要求
在开始之前,我们需要确保以下组件已经就绪:
- 运行OpenEuler 22.04的服务器节点(至少3个节点用于生产环境)
- 正常运行的Ceph集群(版本16.2.7或更高)
- Kubernetes集群(版本1.32.2)
- 网络互通:Kubernetes节点能够访问Ceph Monitor的6789端口
提示:生产环境中建议Ceph和Kubernetes使用独立的网络,但确保网络策略允许必要的通信。
2.2 架构设计解析
整个方案的架构分为三个主要部分:
- Ceph存储层:提供分布式块存储服务,通过RBD(RADOS Block Device)方式为MySQL提供持久化卷
- Kubernetes CSI驱动层:作为中间桥梁,使Kubernetes能够动态配置和管理Ceph RBD卷
- MySQL应用层:运行在Kubernetes中的MySQL实例,数据存储在Ceph RBD卷上
这种设计的优势在于:
- 数据高可用:Ceph的副本机制确保数据安全
- 弹性扩展:可根据需求动态调整存储容量
- 性能可控:可以针对MySQL的I/O特性优化Ceph池的参数
3. Ceph CSI驱动部署
3.1 CSI驱动安装与配置
首先需要在Kubernetes集群中部署Ceph CSI驱动,这是连接Kubernetes和Ceph的关键组件。
wget https://github.com/ceph/ceph-csi/archive/refs/tags/v3.15.0.zip tar xf ceph-csi-3.15.0.tar.gz -C /usr/local/ cd /usr/local/ceph-csi-3.15.0/deploy/rbd/kubernetes3.2 关键配置文件修改
3.2.1 csi-config-map.yaml
这个配置文件定义了Ceph集群的基本信息:
apiVersion: v1 kind: ConfigMap metadata: name: "ceph-csi-config" data: config.json: |- [ { "clusterID": "65eac714-0bd5-11f1-9e23-000c298c1628", "monitors": [ "192.168.198.22:6789", "192.168.198.41:6789", "192.168.198.43:6789" ] } ]注意:
clusterID可以通过在Ceph集群上执行ceph -s命令获取,Monitors地址应填写Ceph集群中所有Monitor节点的地址。
3.2.2 csi-rbdplugin-provisioner.yaml
这个文件定义了CSI的Provisioner组件,负责动态创建存储卷:
apiVersion: apps/v1 kind: Deployment metadata: name: csi-rbdplugin-provisioner namespace: default spec: replicas: 3 selector: matchLabels: app: csi-rbdplugin-provisioner template: metadata: labels: app: csi-rbdplugin-provisioner spec: containers: - name: csi-rbdplugin image: quay.io/cephcsi/cephcsi:v3.14.0 args: - "--nodeid=$(NODE_ID)" - "--type=rbd" - "--controllerserver=true" - "--v=5" - "--drivername=rbd.csi.ceph.com" env: - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: NODE_ID valueFrom: fieldRef: fieldPath: spec.nodeName3.3 部署CSI驱动
完成配置文件修改后,可以部署CSI驱动:
kubectl apply -f csi-config-map.yaml kubectl apply -f csi-provisioner-rbac.yaml kubectl apply -f csi-nodeplugin-rbac.yaml kubectl apply -f csi-rbdplugin-provisioner.yaml kubectl apply -f csi-rbdplugin.yaml部署完成后,检查Pod状态:
kubectl get pods -n default | grep csi-rbd应该看到类似以下的输出,所有Pod都应处于Running状态:
csi-rbdplugin-provisioner-xxx 6/6 Running 0 2m csi-rbdplugin-xxx 3/3 Running 0 2m4. Ceph存储准备
4.1 创建专用存储池
在Ceph集群上为MySQL创建专用的存储池:
ceph osd pool create k8s_mysql_pool 128 128专业建议:根据预计的数据量和性能需求调整PG(Placement Group)数量。对于生产环境,可以使用Ceph官方提供的PG计算器确定合适的值。
4.2 创建访问用户
为Kubernetes创建专用的Ceph用户:
ceph auth get-or-create client.k8s_mysql_pool_user mon 'allow r' osd 'allow rw pool=k8s_mysql_pool' -o ceph.client.k8s_mysql_pool_user.keyring获取用户的key并转换为base64格式,后续Kubernetes会用到:
echo -n "k8s_mysql_pool_user" | base64 echo -n "AQDveaJpjt5DIRAA3FhB6UBN9jzRs72gKwN3Qw==" | base645. Kubernetes存储配置
5.1 创建Ceph Secret
在Kubernetes中创建Secret来存储Ceph凭据:
apiVersion: v1 kind: Secret metadata: name: ceph-secret namespace: default type: "kubernetes.io/rbd" data: userID: azhzX215c3FsX3Bvb2xfdXNlcg== userKey: QVFEdmVhSnBqdDVEQVJBQTNGaEI2VUJOOWp6UnM3MmdLd04zUXc9PQ==应用这个配置:
kubectl apply -f ceph-secret.yaml5.2 创建StorageClass
定义动态存储供应:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: ceph-rbd provisioner: rbd.csi.ceph.com parameters: clusterID: 65eac714-0bd5-11f1-9e23-000c298c1628 pool: k8s_mysql_pool monitors: 192.168.198.22:6789,192.168.198.41:6789,192.168.198.43:6789 csi.storage.k8s.io/provisioner-secret-name: ceph-secret csi.storage.k8s.io/provisioner-secret-namespace: default csi.storage.k8s.io/controller-expand-secret-name: ceph-secret csi.storage.k8s.io/controller-expand-secret-namespace: default csi.storage.k8s.io/node-stage-secret-name: ceph-secret csi.storage.k8s.io/node-stage-secret-namespace: default fsType: ext4 imageFormat: "2" imageFeatures: layering reclaimPolicy: Retain volumeBindingMode: Immediate重要参数说明:
reclaimPolicy: Retain确保删除PVC时不会删除底层Ceph RBD镜像volumeBindingMode: Immediate表示在创建PVC时立即绑定PV
6. MySQL部署与配置
6.1 创建MySQL Secret
安全存储MySQL的root密码:
apiVersion: v1 kind: Secret metadata: name: mysql-password type: Opaque data: username: cm9vdA== password: QWRtaW4xMjM0 mysql-root-password: QWRtaW4xMjM0 mysql-password: QWRtaW4xMjM0 mysql-database: bXlkYg==6.2 部署MySQL StatefulSet
使用StatefulSet部署MySQL,确保稳定的网络标识和持久化存储:
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0.45 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-password key: mysql-root-password ports: - containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: ceph-rbd resources: requests: storage: 1Gi6.3 创建MySQL Service
暴露MySQL服务:
apiVersion: v1 kind: Service metadata: name: mysql spec: ports: - port: 3306 selector: app: mysql clusterIP: None7. 验证与测试
7.1 检查Pod状态
kubectl get pods -l app=mysql应该看到类似输出:
NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 2m7.2 验证数据持久化
- 连接到MySQL并创建测试数据:
kubectl exec -it mysql-0 -- mysql -uroot -pAdmin1234 -e "CREATE DATABASE testdb; USE testdb; CREATE TABLE test (id INT); INSERT INTO test VALUES (1);"- 删除Pod并验证数据:
kubectl delete pod mysql-0 # 等待Pod重新创建 kubectl exec -it mysql-0 -- mysql -uroot -pAdmin1234 -e "USE testdb; SELECT * FROM test;"应该能看到之前插入的数据(值为1的记录)。
7.3 检查Ceph RBD状态
在Ceph集群上检查RBD镜像:
rbd -p k8s_mysql_pool ls应该看到类似如下的输出,表明Kubernetes已经成功创建了RBD镜像:
csi-vol-xxxxxx8. 性能优化与生产建议
8.1 Ceph池优化
对于生产环境的MySQL,建议对Ceph池进行以下优化:
ceph osd pool set k8s_mysql_pool size 3 ceph osd pool set k8s_mysql_pool min_size 2 ceph osd pool set k8s_mysql_pool crush_rule replicated_ssd这些命令将:
- 设置数据副本数为3
- 设置最小可用副本为2
- 使用SSD优化的CRUSH规则(如果集群有SSD)
8.2 Kubernetes资源限制
为MySQL容器设置适当的资源限制:
resources: requests: memory: "2Gi" cpu: "1" limits: memory: "4Gi" cpu: "2"8.3 MySQL参数调优
在MySQL配置中增加以下参数优化Ceph存储性能:
- name: MYSQL_INNODB_FLUSH_LOG_AT_TRX_COMMIT value: "2" - name: MYSQL_INNODB_FLUSH_METHOD value: "O_DIRECT" - name: MYSQL_INNODB_IO_CAPACITY value: "2000"9. 故障排查与常见问题
9.1 PVC处于Pending状态
可能原因和解决方案:
- CSI驱动未正确安装:检查CSI Pod是否全部运行正常
- Ceph认证失败:验证Secret中的userID和userKey是否正确
- 网络连接问题:确保Kubernetes节点可以访问Ceph Monitor端口
9.2 MySQL无法启动
检查点:
- 查看Pod日志:
kubectl logs mysql-0 - 验证存储是否挂载:
kubectl exec -it mysql-0 -- df -h - 检查PVC状态:
kubectl get pvc
9.3 性能问题
如果遇到性能问题:
- 检查Ceph集群健康状况:
ceph status - 监控IO延迟:
ceph osd perf - 考虑使用Ceph的缓存层或为MySQL池分配更多OSD
10. 扩展与高可用方案
10.1 MySQL主从复制
可以通过部署多个MySQL实例并配置复制来实现高可用:
replicas: 3然后在MySQL配置中添加复制相关参数。
10.2 使用CephFS替代RBD
对于需要多Pod共享存储的场景,可以考虑使用CephFS:
provisioner: cephfs.csi.ceph.com10.3 监控与告警
建议部署以下监控组件:
- Prometheus监控Ceph集群
- MySQL Exporter监控数据库指标
- Grafana展示监控数据
11. 备份与恢复策略
11.1 Ceph RBD快照
利用Ceph的快照功能备份数据:
rbd snap create k8s_mysql_pool/csi-vol-xxxxxx@backup-2024050111.2 Kubernetes VolumeSnapshot
使用Kubernetes的VolumeSnapshot API:
apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: mysql-snapshot spec: volumeSnapshotClassName: csi-rbdplugin-snapclass source: persistentVolumeClaimName: mysql-pvc11.3 MySQL逻辑备份
定期执行mysqldump并存储到安全位置:
kubectl exec -it mysql-0 -- mysqldump -uroot -pAdmin1234 --all-databases > backup.sql12. 安全加固建议
12.1 Ceph安全
- 限制网络访问:配置Ceph防火墙只允许Kubernetes节点访问
- 启用Ceph认证:确保所有访问都经过认证
- 定期轮换密钥:定期更新Ceph用户密钥
12.2 Kubernetes安全
- 使用NetworkPolicy限制MySQL Pod的网络访问
- 为MySQL Service配置TLS加密
- 使用PodSecurityPolicy限制容器的权限
12.3 MySQL安全
- 避免使用root账户进行应用连接
- 定期更改数据库密码
- 启用审计日志监控数据库访问
13. 成本优化
13.1 存储分层
对于历史数据,可以配置Ceph的冷热数据分层:
- 热数据存储在SSD池
- 冷数据迁移到HDD池
13.2 压缩与去重
启用Ceph的压缩和去重功能:
ceph osd pool set k8s_mysql_pool compression_mode aggressive13.3 容量规划
定期评估存储使用情况,避免过度配置:
- 设置PVC自动扩展策略
- 监控存储使用趋势
- 清理不必要的数据
14. 实际应用案例
14.1 电商平台订单系统
在某电商平台中,我们使用这种架构处理日均10万+订单:
- 3节点Kubernetes集群
- 5节点Ceph集群(混合SSD+HDD)
- 每天自动快照备份
- 读写分离配置
14.2 物联网数据存储
为某物联网项目存储设备数据:
- 高写入负载优化
- 使用Ceph的EC(纠删码)池降低成本
- 配置自动扩展策略
15. 未来演进方向
- 多集群部署:跨多个Kubernetes集群共享Ceph存储
- 性能优化:结合SPDK进一步提升I/O性能
- 自动化运维:实现自动扩缩容和故障自愈
- 云原生集成:与Operators框架深度集成,实现一键部署
16. 经验总结与建议
在实际部署过程中,我总结了以下几点关键经验:
版本兼容性至关重要:确保Kubernetes、Ceph和CSI驱动的版本兼容。我们曾因版本不匹配导致性能问题。
监控先行:在部署生产负载前,先建立完善的监控体系。Ceph的
ceph-mgr模块和Prometheus exporter是很好的起点。性能基准测试:使用
fio等工具对Ceph RBD进行基准测试,了解实际性能表现。我们发现在默认配置下,随机写性能可能不如预期。资源隔离:为MySQL的Ceph池单独配置CRUSH规则,避免与其他工作负载争抢资源。
备份策略:除了Ceph快照,我们还实现了逻辑备份和异地备份的多重保护。
渐进式部署:先在测试环境验证所有功能,然后逐步迁移生产负载。我们分三个阶段完成了迁移,每个阶段都进行了充分验证。
文档记录:详细记录所有配置和操作步骤。当半年后需要扩容时,完整的文档节省了大量时间。
对于考虑类似架构的团队,我的建议是:
- 从小规模开始,验证核心功能
- 投入时间理解Ceph和Kubernetes存储子系统的工作原理
- 建立自动化运维流程,减少人工干预
- 定期演练灾难恢复流程
这种架构虽然初期投入较大,但为我们的关键业务数据库提供了企业级的可靠性和灵活性,长期来看非常值得。