8Kubernetes 实战

持久存储与卷

数据持久化

PersistentVolumeStorageClass

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第8章:持久存储和卷(Persistent Storage and Volumes)

一、导读

1.1 本章学习目标

容器是临时的,Pod 重启后数据就会丢失。本章讲解 Kubernetes 的持久化存储方案:从最简单的 emptyDir 到网络存储,再到动态供给。你将理解 PV/PVC 的设计哲学、StorageClass 的自动供给机制、以及不同存储方案的适用场景。

本章的核心学习目标包括:

  • 理解容器存储的临时性:为什么容器删除后数据丢失。
  • 掌握 Volume 的基本类型:emptyDir、hostPath、NFS。
  • 理解 PV/PVC 的设计:为什么需要分离存储的提供和使用。
  • 使用 StorageClass 实现动态供给:按需自动创建存储。
  • 理解访问模式和回收策略:RWO/ROX/RWX、Retain/Delete。
  • 为 StatefulSet 配置持久存储:有状态应用的存储管理。

1.2 为什么本章如此重要

数据库、消息队列、文件存储等应用需要持久化数据。如果 Pod 重启后数据丢失,这些应用就无法在 Kubernetes 中运行。理解 K8s 的存储模型,是运行有状态应用的前提。

PV/PVC 的设计体现了 Kubernetes 的解耦思想:集群管理员提供存储资源(PV),用户按需申请(PVC),两者通过 StorageClass 自动匹配。这种模式使得存储管理可以独立于应用部署。

1.3 核心问题引导

为什么需要 PV 和 PVC 两个资源?为什么不直接在 Pod 中定义存储?

PersistentVolume 和 PersistentVolumeClaim 的关系是什么?

StorageClass 的动态供给是如何工作的?

访问模式 ReadWriteOnce 和 ReadOnlyMany 的区别是什么?

Pod 删除后,PV 中的数据会丢失吗?回收策略如何控制?


二、核心概念详解

2.1 容器存储的问题

容器的可写层是临时的:

  • Pod 重启 → 可写层保留,数据不丢失
  • Pod 删除重建 → 可写层丢失,数据丢失
  • 多容器共享数据 → 需要共享存储

2.2 Volume 基础类型

2.2.1 emptyDir

yaml
volumes:
  - name: cache
    emptyDir:
      sizeLimit: 1Gi
      # medium: Memory  # 使用 tmpfs
  • Pod 生命周期内存在
  • Pod 删除时数据丢失
  • 适合临时缓存、容器间共享数据

2.2.2 hostPath

yaml
volumes:
  - name: data
    hostPath:
      path: /data
      type: DirectoryOrCreate
  • 使用节点文件系统
  • 节点数据丢失则 Pod 数据丢失
  • 安全风险:可以访问节点文件
  • 适合 DaemonSet 访问节点日志

2.2.3 NFS

yaml
volumes:
  - name: nfs-data
    nfs:
      server: nfs.example.com
      path: /exports/data
  • 网络存储,多 Pod 共享
  • 不依赖节点文件系统
  • 需要 NFS 服务器

2.3 PersistentVolume 和 PersistentVolumeClaim

PV/PVC 的设计将存储的提供和使用分离:

  • PersistentVolume(PV):集群级存储资源,由管理员创建或动态供给
  • PersistentVolumeClaim(PVC):用户的存储请求,由系统匹配 PV
yaml
# PersistentVolume
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-01
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: slow
  nfs:
    server: nfs.example.com
    path: /exports/data-01
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: slow

2.3.1 访问模式

模式缩写说明
ReadWriteOnceRWO单节点读写
ReadOnlyManyROX多节点只读
ReadWriteManyRWX多节点读写
ReadWriteOncePodRWOP单 Pod 读写

2.3.2 回收策略

  • Retain:PVC 删除后,PV 保留数据(手动清理)
  • Delete:PVC 删除后,PV 和数据一起删除
  • Recycle:已废弃

2.3.3 PV 的状态

  • Available:可用,未被 PVC 绑定
  • Bound:已绑定到 PVC
  • Released:PVC 已删除,等待回收
  • Failed:回收失败

2.4 StorageClass 动态供给

StorageClass 定义存储的"类别",实现按需自动创建 PV。

yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd
  fsType: ext4
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
yaml
# 使用 StorageClass 的 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: dynamic-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast-ssd
  resources:
    requests:
      storage: 20Gi

当 PVC 创建时:

系统查找匹配的 StorageClass

StorageClass 的 provisioner 自动创建 PV

PV 自动绑定到 PVC

常见的 provisioner:

  • kubernetes.io/gce-pd:Google Cloud Persistent Disk
  • kubernetes.io/aws-ebs:AWS EBS
  • kubernetes.io/azure-disk:Azure Disk
  • nfs-subdir-external-provisioner:NFS 动态供给

2.5 在 Pod 中使用 PVC

yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-storage
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc

2.6 StatefulSet 的存储

StatefulSet 为每个 Pod 创建独立的 PVC,Pod 删除后 PVC 保留。

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: database
spec:
  serviceName: db-headless
  replicas: 3
  selector:
    matchLabels:
      app: database
  template:
    metadata:
      labels:
        app: database
    spec:
      containers:
        - name: postgres
          image: postgres:15
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 50Gi

StatefulSet 创建的 PVC 命名规则:<volumeClaimTemplate-name>-<statefulset-name>-<ordinal>

  • data-database-0
  • data-database-1
  • data-database-2

三、实战案例

3.1 使用 NFS 存储

yaml
# PV
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.1.100
    path: /exports/shared
---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: shared-data
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
---
# Pod 使用 PVC
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: shared-data

3.2 数据库持久化

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres-headless
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:15
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-secret
                  key: password
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              cpu: 2000m
              memory: 4Gi
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 100Gi

四、本章小结

容器存储是临时的,Pod 删除后数据丢失。

PV/PVC 分离了存储的提供和使用,实现解耦管理。

StorageClass 实现动态供给,按需自动创建存储。

访问模式决定了存储的共享方式:RWO、ROX、RWX。

StatefulSet 为每个 Pod 创建独立的 PVC,适合有状态应用。


五、思考与练习

思考题

如果 PVC 找不到匹配的 PV,会发生什么?

StorageClass 的 volumeBindingMode: WaitForFirstConsumer 有什么作用?

为什么 StatefulSet 需要 headless Service?

如何备份 PVC 中的数据?

动态供给的 PV 被删除后,数据会丢失吗?如何防止误删?

练习题

使用 NFS 创建 PV/PVC,挂载到 Pod 中验证数据持久化。

配置 StorageClass 实现动态供给,创建 PVC 观察自动创建的 PV。

创建 StatefulSet 运行数据库,验证 Pod 重建后数据保留。

练习 PVC 的扩容:修改 PVC 的 storage 大小,观察是否生效。

8/8持久存储
0%