K8S 本地持久卷实战:从手动配置到自动化管理

张开发
2026/5/5 0:29:54 15 分钟阅读
K8S 本地持久卷实战:从手动配置到自动化管理
1. 本地持久卷的核心价值与适用场景在Kubernetes集群中处理有状态应用时持久化存储是绕不开的话题。相比传统的网络存储方案本地持久卷Local Persistent Volume直接将节点本地磁盘暴露给Pod使用这种方案最显著的优势是性能直接碾压网络存储。我做过实测本地SSD的IOPS能达到云厂商高端云盘的5-8倍延迟更是降低到1/10以下。但本地存储也不是万金油它特别适合以下三类场景高性能数据库比如MySQL、PostgreSQL等关系型数据库当业务对写入延迟极其敏感时消息队列中间件Kafka、RabbitMQ这类对磁盘顺序读写性能要求高的组件临时数据处理比如Spark计算节点需要快速存取中间计算结果不过要注意两个硬性限制首先使用本地卷的Pod会被强绑定到特定节点这意味着节点故障时无法自动迁移其次存储容量受单节点物理限制不能像云存储那样弹性扩展。去年我们有个Cassandra集群就踩过坑当时没规划好容量后来不得不连夜迁移数据。2. 手动配置本地卷的完整流程2.1 基础环境准备先确保集群节点有可用存储设备这里演示用目录模拟物理设备# 在所有工作节点执行 mkdir -p /data/local_volumes/{ssd1,hdd1} chmod 777 /data/local_volumes/*建议用LVM管理本地磁盘方便后期扩容。我常用的组合是PVVGLV三件套pvcreate /dev/sdb vgcreate k8s_vg /dev/sdb lvcreate -L 500G -n ssd1 k8s_vg mkfs.ext4 /dev/k8s_vg/ssd1 mount /dev/k8s_vg/ssd1 /data/local_volumes/ssd12.2 StorageClass的关键配置创建延迟绑定的StorageClass是核心步骤这个配置直接影响调度行为apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer reclaimPolicy: Retain # 生产环境建议用Retain防止误删重点参数说明volumeBindingModeWaitForFirstConsumer实现延迟绑定等Pod调度确定节点后再绑定PVreclaimPolicyRetain删除PVC后保留PV和数据避免自动化清理导致数据丢失2.3 PV定义的精妙之处PV定义需要特别注意节点亲和性配置这是实现本地存储的关键apiVersion: v1 kind: PersistentVolume metadata: name: node1-ssd-pv spec: capacity: storage: 500Gi storageClassName: local-storage local: path: /data/local_volumes/ssd1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - node1 # 必须替换为实际节点名实际使用中我推荐用脚本批量生成PV定义。比如用这个Python脚本根据节点列表自动生成PVimport yaml nodes [node1, node2, node3] for i, node in enumerate(nodes): pv { apiVersion: v1, kind: PersistentVolume, metadata: {name: f{node}-ssd-pv}, spec: { capacity: {storage: 500Gi}, storageClassName: local-storage, local: {path: f/data/local_volumes/ssd1}, nodeAffinity: { required: { nodeSelectorTerms: [{ matchExpressions: [{ key: kubernetes.io/hostname, operator: In, values: [node] }] }] } } } } with open(fpv-{node}.yaml, w) as f: yaml.dump(pv, f)3. 从手动到自动化的进化之路3.1 手动方案的运维痛点在早期项目中我们完全采用手动管理PV的方式很快遇到三个典型问题扩容效率低每次新增节点都要手动创建PV定义清理不彻底删除PVC后需要人工介入清理数据和PV容量管理难无法直观查看各节点存储使用情况最严重的一次事故是某节点磁盘写满导致Kubelet异常但直到业务报警才发现问题。后来我们不得不用PrometheusGrafana搭建了存储监控看板。3.2 Local Volume Provisioner工作原理Kubernetes社区提供的local-volume-provisioner方案本质上是通过DaemonSet在每个节点部署一个Provisioner Pod它主要完成三项工作发现机制定期扫描配置的发现目录如/mnt/disksPV生命周期管理自动创建/删除PV并在PV释放时清理数据缓存同步维护本地PV状态缓存减少API Server压力架构示意图如下省略代码块每个节点运行一个Provisioner实例通过hostPath挂载发现目录使用Leader选举避免并发冲突3.3 生产级部署实践3.3.1 准备存储目录推荐使用绑定挂载将实际存储目录映射到发现目录# 创建实际存储目录和发现目录 mkdir -p /mnt/actual_ssd/{vol1,vol2} mkdir -p /mnt/disks/{ssd_vol1,ssd_vol2} # 建立绑定挂载 mount --bind /mnt/actual_ssd/vol1 /mnt/disks/ssd_vol1 mount --bind /mnt/actual_ssd/vol2 /mnt/disks/ssd_vol2 # 确保重启后挂载不丢失 echo /mnt/actual_ssd/vol1 /mnt/disks/ssd_vol1 none bind 0 0 /etc/fstab3.3.2 定制Provisioner配置修改官方提供的DaemonSet配置重点调整这些参数containers: - name: provisioner image: registry.k8s.io/sig-storage/local-volume-provisioner:v2.6.0 env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: USE_JOURNALD # 启用journald日志 value: true volumeMounts: - mountPath: /etc/provisioner/config name: provisioner-config - mountPath: /mnt/disks name: local-disks mountPropagation: HostToContainer # 关键参数3.3.3 高级运维技巧存储分级通过不同StorageClass区分SSD和HDDstorageClassMap: ssd: hostDir: /mnt/ssd_disks volumeMode: Filesystem fsType: ext4 hdd: hostDir: /mnt/hdd_disks volumeMode: Filesystem fsType: xfs自动扩容脚本定期检查并创建新卷#!/bin/bash for i in {1..5}; do if [ ! -d /mnt/actual_ssd/vol${i} ]; then mkdir -p /mnt/actual_ssd/vol${i} mount --bind /mnt/actual_ssd/vol${i} /mnt/disks/ssd_vol${i} fi done4. 生产环境避坑指南4.1 常见故障排查问题现象PVC一直处于Pending状态检查项kubectl describe pvc name查看事件kubectl get storageclass确认StorageClass存在kubectl get pv检查可用PV的容量和访问模式问题现象Pod启动失败报错Unable to mount volumes检查项登录对应节点检查/var/log/kubelet.log确认挂载点权限为777检查是否触发SELinux限制4.2 性能优化实践文件系统选型对于SSD建议用ext4或xfs数据库类应用可考虑直接使用raw block设备内核参数调优# 提高虚拟内存脏页比例 echo vm.dirty_ratio 20 /etc/sysctl.conf echo vm.dirty_background_ratio 10 /etc/sysctl.conf sysctl -pIO调度器选择# 对NVMe SSD使用none调度器 echo none /sys/block/nvme0n1/queue/scheduler4.3 数据安全策略备份方案定期使用rsync同步到网络存储对关键数据增加Velero备份故障转移设计# 在Deployment中配置反亲和性 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - my-db topologyKey: kubernetes.io/hostname监控指标通过Node Exporter采集磁盘使用率设置Prometheus告警规则- alert: DiskSpaceCritical expr: node_filesystem_avail_bytes{mountpoint/data} / node_filesystem_size_bytes{mountpoint/data} 0.1 for: 30m

更多文章