Kubernetes 持久化存储解密:PV 和 PVC 的工作原理与实践

168

我们都知道,在 Kubernetes 这个动态环境中,Pods 可以被创建、销毁并在多个节点之间移动。这引出了一个问题:如何在这种动态环境中处理存储呢?答案就在 Kubernetes 的 PV(Persistent Volume)和 PVC(Persistent Volume Claim)。

PV 和 PVC 的重要性

在 Kubernetes 中,PV 是在集群中提供给用户使用的存储资源的抽象,就像一种云上的硬盘。而 PVC 则是用户对这些资源的请求或申请,就像租赁一块硬盘。

这种设计策略是一种很明智的区分:PV 是供应方的角色,是管理员的事情,管理集群内的实际存储资源。而 PVC 则是消费方的角色,是用户或开发者的事情,他们只需要关心如何消费这些存储资源。

PV 和 PVC 的工作原理

PV 在 Kubernetes 中是集群级别的资源,具有以下特性:

  1. PV 不受 Pod 生命周期限制:当删除与 PV 对象关联的 Pod 时,PV 仍然存在。

  2. PV 在故障中仍然存在:当 Pod 崩溃时,PV 仍然在集群中存在。

  3. PV 是集群范围的:PV 可以附加到在集群中运行的任何 Pod。

PV 支持三种访问模式:

  • ReadWriteOnce(单节点读写)

  • ReadOnlyMany(多节点只读)

  • ReadWriteMany(多节点读写)

PV 和 PVC 的交互过程可以分为两部分:静态供应和动态供应。

静态供应:

对于 PVC,开发者在其应用的配置文件中创建一个 PVC,其中指定了所需的存储大小和访问模式。Kubernetes 会查找符合这些要求的 PV 并将其与 PVC 绑定。这被称为静态供应。静态供应需要管理员先创建 PV,然后用户通过 PVC 来申请使用 PV。这个过程就像管理员为用户准备了一系列的储物柜(PV),用户则通过储物柜钥匙(PVC)来申请使用这些储物柜。

static-volume-provisioning.png

然而,当集群规模扩大,手动创建 PV 和 PVC 可能变得复杂和繁琐。为了解决这个问题,Kubernetes 提供了动态供应。动态供应中,PV 的创建将被自动化。当创建 PVC 时,PV 将自动在后台创建。Kubernetes 使用另一个叫做 Storage Class 的对象来实现这一点。

动态供应:

动态供应则更为方便,它不需要管理员事先创建 PV。当用户创建 PVC 时,Kubernetes 会自动为这个 PVC 创建一个满足其请求的 PV。这就好比你走到一个储物柜前,自动售货机会根据你的需求,为你现场制造一个储物柜。

dynamic-volume-provisioning.png

Kubernetes PV 和 PVC 的源码实现

Kubernetes 的源代码在 GitHub 上开源,你可以在 pkg/controller/volume 目录下找到 PV 和 PVC 的实现。其中,persistentvolume 子目录是 PV 和 PVC 的核心实现

源码中的 pv_controller.go 是 PV 和 PVC 控制器的主要实现,它监听 PVC 和 PV 的事件,并根据事件类型执行相应的操作。这种事件驱动的设计是 Kubernetes 控制器的典型模式,也是其能够自动化管理资源的关键。

对于静态供应,PV 和 PVC 控制器会在 PVC 创建时寻找满足其要求的 PV。如果找到了,则会将 PVC 和 PV 绑定,否则 PVC 将一直处于等待状态。

对于动态供应,PV 和 PVC 控制器会在 PVC 创建时,检查是否存在满足其要求的 PV,如果没有,并且 PVC 定义了 Storage Class,则会根据 Storage Class 动态创建一个 PV。

PV 和 PVC 的实践使用

那么,如何在实际中使用 PV 和 PVC 呢?让我们通过一个例子来看。

假设我们要创建一个名为 my-pv 的 PV,存储大小为 10Gi,访问模式为 ReadWriteOnce。我们可以创建以下 PV 资源:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /data/my-pv

然后,我们要创建一个 PVC 来申请这个 PV:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  resources:
    requests:
      storage: 10Gi
  accessModes:
    - ReadWriteOnce

创建这两个资源后,Kubernetes 就会自动将 PVC my-pvc 和 PV my-pv 绑定。现在,我们就可以在 Pod 中通过这个 PVC 来使用存储空间了。

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  volumes:
    - name: my-storage
      persistentVolumeClaim:
        claimName: my-pvc
  containers:
    - name: my-container
      image: nginx
      volumeMounts:
        - mountPath: /data
          name: my-storage

结论

通过使用 PV 和 PVC,Kubernetes 提供了一种简单且灵活的方法来在动态环境中处理存储问题。而且,通过查看 Kubernetes 的源码,我们可以深入理解其工作原理,进一步提升我们的 Kubernetes 技能。

参考资料: