K8s数据持久化实战:用PV/PVC为MySQL部署保驾护航(含节点故障模拟)
K8s数据持久化实战:用PV/PVC为MySQL部署保驾护航(含节点故障模拟)
在云原生架构中,数据库的高可用部署一直是技术团队面临的挑战。当MySQL运行在Kubernetes集群时,如何确保数据在Pod重启、节点故障等意外情况下依然安全可靠?这正是PV(PersistentVolume)和PVC(PersistentVolumeClaim)要解决的核心问题。
传统容器中的存储会随着Pod销毁而消失,这对于有状态应用如MySQL简直是灾难。通过PV/PVC机制,Kubernetes实现了存储与计算资源的解耦——就像为数据库插上了一块"外接硬盘",即使容器漂移到其他节点,数据也能完好无损地跟随迁移。本文将带您从零构建一个生产级MySQL部署方案,并通过模拟节点宕机来验证这套架构的可靠性。
1. 持久化存储架构设计
1.1 PV与PVC的协作机制
PV是集群中的一块持久化存储空间,由管理员预先配置;PVC则是用户发出的存储资源申请。当两者通过StorageClass和访问策略匹配成功后,PVC就会"绑定"到合适的PV上。这种设计带来了三个关键优势:
- 职责分离:开发人员只需声明需要的存储大小和性能,无需关心底层是NFS、云盘还是本地SSD
- 资源抽象:同一套YAML配置可以在不同环境的Kubernetes集群中运行
- 动态供给:支持按需自动创建存储卷(需StorageClass支持)
1.2 MySQL的存储需求分析
设计MySQL的持久化方案时,需要特别注意以下几点:
| 需求维度 | 具体要求 | PV/PVC实现方案 |
|---|---|---|
| 数据一致性 | 单节点读写,避免多节点同时写入 | accessModes: ReadWriteOnce |
| 故障恢复 | 节点宕机后数据不丢失 | persistentVolumeReclaimPolicy: Retain |
| 性能要求 | 低延迟IO操作 | 选择SSD存储类 |
| 容量规划 | 预留20%缓冲空间 | 申请容量=预估数据量×1.2 |
2. 实战环境准备
2.1 基础设施配置
我们采用NFS作为后端存储(生产环境建议使用云厂商的块存储服务),先在存储节点执行:
# 安装NFS服务 sudo apt-get install -y nfs-kernel-server # 创建共享目录 sudo mkdir -p /data/mysql-pv sudo chmod 777 /data/mysql-pv # 配置导出目录 echo "/data/mysql-pv *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee /etc/exports.d/mysql.exports # 启动服务 sudo systemctl enable --now nfs-server在Kubernetes所有工作节点安装NFS客户端工具:
sudo apt-get install -y nfs-common2.2 创建静态PV
定义PV资源文件mysql-pv.yaml:
apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv-01 labels: type: nfs spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: mysql-storage nfs: path: /data/mysql-pv server: 192.168.1.100关键参数说明:
persistentVolumeReclaimPolicy: 设置为Retain确保PVC释放后数据不会自动删除storageClassName: 自定义存储类名称,用于PVC匹配
创建PV资源:
kubectl apply -f mysql-pv.yaml3. MySQL部署实战
3.1 创建专属PVC
定义PVC声明文件mysql-pvc.yaml:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-data-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: mysql-storage应用PVC配置:
kubectl apply -f mysql-pvc.yaml验证绑定状态:
kubectl get pvc mysql-data-pvc -o wide预期看到STATUS为Bound,且VOLUME列显示绑定的PV名称。
3.2 部署MySQL有状态服务
编写Deployment配置mysql-deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: selector: matchLabels: app: mysql strategy: type: Recreate template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD value: "securepassword" ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql volumes: - name: mysql-data persistentVolumeClaim: claimName: mysql-data-pvc几个关键设计点:
- 使用
Recreate策略确保单实例运行 - 数据挂载到MySQL默认目录
/var/lib/mysql - 通过环境变量设置root密码(生产环境应使用Secret)
部署MySQL服务:
kubectl apply -f mysql-deployment.yaml3.3 服务暴露与验证
创建NodePort服务便于外部访问:
apiVersion: v1 kind: Service metadata: name: mysql-service spec: type: NodePort ports: - port: 3306 targetPort: 3306 nodePort: 30306 selector: app: mysql连接MySQL并创建测试数据:
# 获取Pod名称 MYSQL_POD=$(kubectl get pods -l app=mysql -o jsonpath='{.items[0].metadata.name}') # 执行MySQL命令行 kubectl exec -it $MYSQL_POD -- mysql -uroot -psecurepassword -- 在MySQL交互界面执行 CREATE DATABASE k8s_test; USE k8s_test; CREATE TABLE persistent_data ( id INT AUTO_INCREMENT PRIMARY KEY, value VARCHAR(255) NOT NULL ); INSERT INTO persistent_data(value) VALUES('K8s PV/PVC Test');4. 节点故障模拟测试
4.1 确定Pod运行节点
首先查询MySQL Pod所在节点:
kubectl get pod -l app=mysql -o wide记录NODE列显示的节点名称,例如node-1。
4.2 模拟节点故障
在目标节点上执行关机操作(生产环境请勿直接操作):
# 连接到目标节点 ssh node-1 # 模拟节点宕机 sudo systemctl poweroff观察Kubernetes的恢复过程:
watch kubectl get pods -l app=mysql -o wide大约1-2分钟后,会看到Pod被重新调度到其他可用节点(如node-2)。
4.3 数据完整性验证
重新连接MySQL验证数据:
# 获取新的Pod名称 NEW_MYSQL_POD=$(kubectl get pods -l app=mysql -o jsonpath='{.items[0].metadata.name}') # 查询测试数据 kubectl exec -it $NEW_MYSQL_POD -- mysql -uroot -psecurepassword -e "SELECT * FROM k8s_test.persistent_data"预期输出应显示之前插入的记录,证明数据在节点故障转移过程中保持完整。
5. 高级配置与优化
5.1 存储类动态供给
对于需要频繁创建数据库实例的场景,可以配置StorageClass实现动态供给:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: mysql-dynamic-storage provisioner: example.com/nfs parameters: archiveOnDelete: "false"然后在PVC中引用:
storageClassName: mysql-dynamic-storage5.2 多副本MySQL部署
对于生产环境,建议使用StatefulSet部署MySQL集群:
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql-cluster spec: serviceName: mysql replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ROOT_PASSWORD value: "securepassword" ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: mysql-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "mysql-storage" resources: requests: storage: 10Gi5.3 备份策略配置
为确保数据安全,建议配置定期备份:
# 临时备份Pod配置 apiVersion: batch/v1 kind: CronJob metadata: name: mysql-backup spec: schedule: "0 2 * * *" jobTemplate: spec: template: spec: containers: - name: mysqldump image: mysql:5.7 command: - /bin/sh - -c - mysqldump -uroot -p$MYSQL_ROOT_PASSWORD --all-databases > /backup/mysql-$(date +%Y%m%d).sql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password volumeMounts: - name: backup-volume mountPath: /backup restartPolicy: OnFailure volumes: - name: backup-volume persistentVolumeClaim: claimName: backup-pvc6. 生产环境注意事项
在实际生产部署时,还需要考虑以下关键因素:
- 性能监控:配置Prometheus监控MySQL和存储性能指标
- 资源限制:为MySQL容器设置合理的requests和limits
- 网络策略:限制只有特定服务可以访问MySQL端口
- 加密存储:敏感数据应考虑使用加密存储卷
- 灾备方案:建立跨可用区的备份恢复机制
通过这套方案,我们成功在Kubernetes上部署了具备持久化存储能力的MySQL服务。当模拟节点故障时,观察到Pod会自动迁移到健康节点,且通过PVC挂载的数据卷保持了完整的数据一致性。这为在K8s上运行有状态服务提供了可靠的基础保障。
