首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >K8s持久化存储深度解析:PV、PVC、StorageClass三剑客的生产实战

K8s持久化存储深度解析:PV、PVC、StorageClass三剑客的生产实战

作者头像
悠悠12138
发布2026-04-15 18:12:53
发布2026-04-15 18:12:53
50
举报

做了这么多年运维,K8s的存储这块一直是个让人又爱又恨的东西。说它复杂吧,确实概念挺多的,PV、PVC、StorageClass这些名词听起来就头大;说它简单吧,一旦搞明白了原理,用起来还是很顺手的。

今天我就把自己这些年在生产环境中踩过的坑、总结的经验分享给大家,让你们少走点弯路。

为什么需要持久化存储

容器本身是无状态的,这个大家都知道。Pod一重启,里面的数据就没了,这对于数据库、文件存储这些有状态应用来说简直是灾难。

我记得刚开始用K8s的时候,有次MySQL的Pod重启了,结果所有数据都丢了,那个心情...简直想死的心都有。从那以后我就深刻认识到,持久化存储在K8s中有多重要。

K8s的持久化存储主要解决这么几个问题:

  • • 数据持久性:Pod重启、迁移后数据不丢失
  • • 数据共享:多个Pod可以访问同一份数据
  • • 存储抽象:屏蔽底层存储实现细节

PV、PVC、StorageClass的关系

这三个概念的关系,我用一个比较接地气的比喻来解释:

**PV(PersistentVolume)**就像是一个仓库,管理员提前准备好的存储空间。 **PVC(PersistentVolumeClaim)**就像是租仓库的申请单,用户说我要多大的空间、什么类型的。 StorageClass就像是仓库的分类标准,比如高性能仓库、普通仓库、便宜仓库等。

具体来说:

PV(持久卷)

PV是集群级别的资源,由管理员创建,代表集群中的一块存储。它包含存储实现的具体细节,比如NFS、iSCSI、云存储等。

代码语言:javascript
复制
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.1.100
    path: /data/nfs

这个配置我在生产环境用过很多次,需要注意几个点:

  • capacity定义存储大小
  • accessModes定义访问模式,RWO(ReadWriteOnce)表示只能被一个节点挂载
  • persistentVolumeReclaimPolicy定义回收策略

PVC(持久卷声明)

PVC是用户对存储的请求,它会去寻找合适的PV进行绑定。

代码语言:javascript
复制
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

这里有个坑要注意,PVC请求的存储大小必须小于等于PV提供的大小,而且访问模式也要匹配。

StorageClass(存储类)

StorageClass提供了动态创建PV的方式,不需要管理员手动创建PV。

代码语言:javascript
复制
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  zone: us-west-2a

静态供应 vs 动态供应

静态供应

静态供应就是管理员提前创建好PV,然后用户创建PVC去绑定。这种方式比较传统,适合小规模或者对存储有特殊要求的场景。

我在一个项目中就是用的静态供应,因为客户要求数据必须存储在指定的NFS服务器上,所以只能手动创建PV。

动态供应

动态供应通过StorageClass自动创建PV,用户只需要在PVC中指定StorageClass即可。

代码语言:javascript
复制
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 20Gi

这种方式更灵活,特别适合云环境。我现在基本都用动态供应,省事多了。

生命周期管理

PV和PVC的生命周期有几个关键阶段:

Available(可用)

PV已创建,但还没有被PVC绑定。

Bound(已绑定)

PV已经被PVC绑定,正在使用中。

Released(已释放)

PVC被删除,但PV还没有被回收。

Failed(失败)

自动回收失败。

这里要特别说一下回收策略,有三种:

  • Retain:保留数据,需要手动清理
  • Delete:自动删除PV和底层存储
  • Recycle:已废弃,不建议使用

我在生产环境中一般用Retain策略,因为数据安全第一,宁可手动清理也不能误删数据。

访问模式详解

K8s支持三种访问模式:

ReadWriteOnce (RWO)

只能被一个节点以读写方式挂载。这是最常用的模式,适合大部分应用。

ReadOnlyMany (ROX)

可以被多个节点以只读方式挂载。适合配置文件、静态资源等场景。

ReadWriteMany (RWX)

可以被多个节点以读写方式挂载。这个模式对存储系统要求比较高,不是所有存储都支持。

我遇到过一个坑,就是用了不支持RWX的存储系统,结果Pod一直处于Pending状态。后来查了半天才发现是访问模式的问题。

实际生产案例

案例1:MySQL数据库持久化

代码语言:javascript
复制
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: mysql-storage
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  encrypted: "true"

---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: mysql-storage
  resources:
    requests:
      storage: 100Gi

---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "password123"
        volumeMounts:
        - name: mysql-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-storage
        persistentVolumeClaim:
          claimName: mysql-pvc

这个配置我用了好几年,非常稳定。关键点是:

  • • 使用加密的EBS卷保证数据安全
  • • 100Gi的存储空间足够大部分应用使用
  • • 挂载到MySQL的数据目录

案例2:多Pod共享存储

有时候需要多个Pod共享同一份数据,比如Web应用的静态文件。

代码语言:javascript
复制
# 使用NFS的PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: shared-pv
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: nfs-server.example.com
    path: /shared/data

---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Gi

这种场景下必须使用支持RWX的存储系统,NFS是个不错的选择。

性能优化技巧

选择合适的存储类型

不同的存储类型性能差异很大:

  • SSD:IOPS高,延迟低,适合数据库
  • HDD:容量大,成本低,适合日志、备份
  • 网络存储:可共享,但性能一般

我的经验是,数据库一定要用SSD,日志可以用HDD,配置文件用网络存储。

合理设置存储大小

存储大小不是越大越好,要根据实际需求来:

  • • 预留20-30%的空间用于扩展
  • • 考虑备份和快照的空间需求
  • • 定期清理无用数据

监控存储使用情况

我一般会用Prometheus监控存储使用率:

代码语言:javascript
复制
# 存储使用率告警规则
groups:
- name: storage.rules
  rules:
  - alert: PVCStorageUsageHigh
    expr: (kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) * >
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "PVC storage usage is high"

常见问题排查

PVC一直Pending

这是最常见的问题,可能的原因:

  • • 没有合适的PV可以绑定
  • • StorageClass配置错误
  • • 存储资源不足

排查方法:

代码语言:javascript
复制
kubectl describe pvc my-pvc
kubectl get pv
kubectl get storageclass

Pod挂载失败

挂载失败通常是因为:

  • • 节点不支持该存储类型
  • • 权限问题
  • • 存储系统故障

我遇到过一次EBS卷挂载失败,最后发现是AWS的配额限制导致的。

数据丢失

这个问题最严重,预防措施:

  • • 使用Retain回收策略
  • • 定期备份重要数据
  • • 测试恢复流程

最佳实践总结

根据我这些年的经验,总结几个最佳实践:

  1. 1. 生产环境优先使用动态供应,配置合适的StorageClass
  2. 2. 重要数据使用Retain回收策略,手动管理PV生命周期
  3. 3. 合理选择访问模式,大部分情况用RWO就够了
  4. 4. 监控存储使用情况,及时发现问题
  5. 5. 定期备份数据,做好灾难恢复准备

存储选型建议

  • 数据库:高性能SSD + RWO + Retain策略
  • 文件服务:网络存储 + RWX + Delete策略
  • 日志收集:大容量HDD + RWO + Delete策略
  • 临时数据:本地存储 + RWO + Delete策略

如果觉得这篇文章对你有帮助,别忘了点个赞、转发一下,让更多的运维小伙伴看到。你们的支持是我持续输出干货的动力!

关注@运维躬行录,获取更多实战干货,我们一起在运维的道路上躬行实践!


公众号:运维躬行录 个人博客:躬行笔记

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维躬行录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要持久化存储
  • PV、PVC、StorageClass的关系
    • PV(持久卷)
    • PVC(持久卷声明)
    • StorageClass(存储类)
  • 静态供应 vs 动态供应
    • 静态供应
    • 动态供应
  • 生命周期管理
    • Available(可用)
    • Bound(已绑定)
    • Released(已释放)
    • Failed(失败)
  • 访问模式详解
    • ReadWriteOnce (RWO)
    • ReadOnlyMany (ROX)
    • ReadWriteMany (RWX)
  • 实际生产案例
    • 案例1:MySQL数据库持久化
    • 案例2:多Pod共享存储
  • 性能优化技巧
    • 选择合适的存储类型
    • 合理设置存储大小
    • 监控存储使用情况
  • 常见问题排查
    • PVC一直Pending
    • Pod挂载失败
    • 数据丢失
  • 最佳实践总结
    • 存储选型建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档