Kubernetes 中实现持久化存储的简单指南
了解如何在 Kubernetes 中为有状态应用程序实现持久化存储。本指南将揭秘持久卷 (PV) 和持久卷声明 (PVC),解释访问模式和存储类 (StorageClasses)。包含用于定义 PVC 和将存储挂载到 Pod 的实用 YAML 示例,从而实现容器化应用程序中可靠的数据持久性。
Kubernetes 持久化存储实现简易指南
Kubernetes 持久化存储解决了一个简单的问题:您的容器可能会消失,但数据库文件、上传内容或队列数据不能丢失。无状态 Pod 可以随时被替换,而有状态应用需要能够承受 Pod 重启、重新调度和节点维护的存储。
本指南将结合实际 YAML 示例,讲解 PersistentVolume(PV)、PersistentVolumeClaim(PVC)、访问模式和 StorageClass,您可以直接将其应用于实际工作负载。
理解 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)
在将存储挂载到 Pod 之前,需要明确每个对象负责什么:
- PersistentVolume(PV): PV 是由管理员预先制备或通过 StorageClass 动态制备的集群存储资源。PV 是集群资源,类似于节点,其生命周期独立于任何使用它的 Pod。PV 抽象了底层存储实现的细节(例如 NFS、iSCSI、云提供商块存储)。
- PersistentVolumeClaim(PVC): PVC 是用户对存储的请求。它消耗集群中作为 PV 可用的存储资源。PVC 类似于 Pod,消耗计算资源,并且作用域限定在命名空间内。PVC 指定所需的存储容量、访问模式,以及可选的 StorageClass。
这种分离让平台团队管理存储细节,而应用团队只需请求所需的容量和访问模式。
关键概念:访问模式与 StorageClass
两个设置控制着大多数 PVC 的行为:卷的挂载方式以及由哪个存储后端创建它。
访问模式
访问模式定义了卷如何挂载到 Pod。可用的访问模式包括:
ReadWriteOnce(RWO):卷可以被单个节点以读写方式挂载。ReadOnlyMany(ROX):卷可以被多个节点以只读方式挂载。ReadWriteMany(RWX):卷可以被多个节点以读写方式挂载。ReadWriteOncePod(RWOP):卷可以被单个 Pod 以读写方式挂载。当需要更严格的单写入者行为且 CSI 驱动支持时,此模式非常有用。
需要注意的是,这些模式的实际支持情况取决于底层存储提供商。
StorageClass
StorageClass 为管理员提供了一种描述其提供的存储“类别”的方式。不同的类别可能对应不同的服务质量级别、备份策略或集群管理员决定的任意策略。StorageClass 包含一个用于制备存储的制备器(provisioner)以及一组制备器参数。当 PVC 创建时没有指定具体的 PV,并且请求了 StorageClass,Kubernetes 将使用指定的 StorageClass 动态制备一个 PV。
逐步实现持久化存储
让我们通过一个常见场景来演示:为 Pod 请求并使用持久化存储。
步骤 1:定义 PersistentVolumeClaim(PVC)
首先,您需要创建一个 PVC 来指定存储需求。这个 PVC 将作为应用对存储的请求。
示例 pvc.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
在此示例中:
name: my-pvc:这是 PVC 的名称。accessModes: - ReadWriteOnce:我们请求的存储可以被单个节点以读写方式挂载。resources.requests.storage: 1Gi:我们请求 1 GB 的存储空间。
应用 PVC:
将上述内容保存为 pvc.yaml 文件,然后应用到集群:
kubectl apply -f pvc.yaml
应用后,您可以检查 PVC 的状态:
kubectl get pvc my-pvc
如果存在合适的 PV 或已动态制备,您应该会看到 PVC 的状态为 Bound。
步骤 2:创建使用 PVC 的 Pod
现在,让我们创建一个使用 PVC 所请求存储的 Pod。我们将把 PVC 提供的卷挂载到容器内的特定目录。
示例 pod-with-pv.yaml:
apiVersion: v1
kind: Pod
metadata:
name: my-stateful-pod
spec:
containers:
- name: my-container
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: my-persistent-storage
mountPath: /usr/share/nginx/html
volumes:
- name: my-persistent-storage
persistentVolumeClaim:
claimName: my-pvc
在此示例中:
volumes:我们定义了一个名为my-persistent-storage的卷。persistentVolumeClaim.claimName: my-pvc:这将我们的卷链接到之前创建的 PVC。volumeMounts:在容器定义中,我们指定了卷的挂载路径(mountPath: /usr/share/nginx/html)。
应用 Pod:
将上述内容保存为 pod-with-pv.yaml 文件,然后应用:
kubectl apply -f pod-with-pv.yaml
现在,您的 nginx 容器将能够访问由 my-pvc 定义的持久化存储,路径为 /usr/share/nginx/html。只要 PVC 及其底层 PV 存在,写入该路径的任何数据都将在 Pod 被删除并重新创建后持久保存。
使用 StorageClass 进行动态制备
手动创建 PV 可能很繁琐。Kubernetes 提供了动态制备功能,当 PVC 请求的存储无法由现有 PV 满足时,会自动创建 PV。这通过 StorageClass 实现。
大多数云提供商(AWS、GCP、Azure)都提供预配置的 StorageClass。您可以使用以下命令查看:
kubectl get storageclass
要使用动态制备,只需在 PVC 定义中添加 storageClassName 字段:
示例 pvc-dynamic.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-dynamic-pvc
spec:
storageClassName: standard # 将 'standard' 替换为实际的 StorageClass 名称
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
当您应用此 PVC 时,Kubernetes 将查找名为 standard(或您指定的任何名称)的 StorageClass,并指示其制备器创建一个 5Gi 的新 PV,并将其绑定到此 PVC。
提示与最佳实践
- 选择合适的访问模式: 仔细考虑应用所需的访问模式。
ReadWriteOnce适用于单副本数据库,而ReadWriteMany则用于多个 Pod 共享的文件系统。 - 了解存储性能: 不同的存储提供商和 StorageClass 提供不同的性能特性(IOPS、吞吐量)。选择满足应用性能需求的 StorageClass。
- 备份策略: 持久化存储并不意味着自动备份。为持久卷实施稳健的备份策略,尤其是对于关键数据。
- PV 回收策略: PV 具有
persistentVolumeReclaimPolicy,常见的有Delete或Retain。动态制备的卷通常使用其 StorageClass 定义的回收策略。旧的Recycle策略已弃用,不应在新设置中使用。 - 命名空间注意事项: PVC 是命名空间作用域的。确保 Pod 和 PVC 位于同一命名空间,以便绑定成功。
总结
Kubernetes 中的持久化存储始于 PVC、Pod 挂载以及与工作负载匹配的 StorageClass。对于单副本数据库,从 ReadWriteOnce 声明开始,确认其状态为 Bound,挂载到容器中,并从第一天起将备份纳入设计。