k8s 持久化存储-常见的存储卷介绍

艺帆风顺 发布于 2025-04-02 31 次阅读


一、简介

    当在 Kubernetes 中部署应用程序时,数据通常存储在容器内部的文件系统中。然而,容器的生命周期是临时的,当容器被删除或重新启动时,容器内的数据也会丢失。为了解决这个问题,需要在 Kubernetes 中实现数据持久化。数据持久化是将数据保存到持久化存储介质(如磁盘)上,以便在容器被重新创建或迁移到其他节点时仍然可用。数据持久化的场景包括:1、数据存储:许多应用程序需要保存用户生成的数据,如文件、图片、日志等。通过数据持久化,可以确保这些数据在容器销毁或重启后仍然存在。2、数据共享:在某些情况下,多个容器或 Pod 可能需要访问和共享相同的数据。通过将数据存储在持久化卷中,可以使多个容器之间共享数据,实现数据一致性和共享访问。3、数据备份和恢复:持久化存储解决方案通常提供数据备份和恢复机制,以防止数据丢失。这对于保护重要数据、应对故障或恢复到先前的状态非常重要。4、数据迁移和扩展:在 Kubernetes 集群中,可能需要扩展应用程序到多个节点或迁移到其他集群。通过将数据存储在持久化卷中,可以方便地将数据与应用程序一起迁移到新的环境,无需担心数据丢失。5、数据安全:某些行业或应用程序对数据的安全性有严格的要求。持久化存储解决方案通常提供数据加密和访问控制功能,以确保数据在传输和存储过程中的安全性。

    二、存储卷简介

    1、emptyDir

      EmptyDir 卷的使用场景包括:1. 临时文件共享:如果多个容器需要在同一个 Pod 中进行临时文件共享,EmptyDir 卷是一个简便的解决方案。容器可以将文件写入 EmptyDir 卷,并且其他容器可以读取和修改这些文件。当 Pod被删除或重启时,EmptyDir 卷中的文件会被清空。2. 共享数据:某些应用程序可能需要在容器之间共享一些中间结果或临时数据。EmptyDir 卷可以作为容器之间的临时数据交换机制。容器可以将数据写入 EmptyDir 卷,其他容器可以读取和处理这些数据,从而实现数据共享和协作。3. 缓存:EmptyDir 卷可以用作容器的缓存存储。某些应用程序可能需要将频繁访问的数据缓存到本地存储中,以提高性能。EmptyDir 卷提供了一个临时的、高速的存储介质来存储缓存数据,提供快速的读取和写入操作。当在 Kubernetes 中使用存储卷(Volume),需要经历以下步骤:1. 定义 Pod 的 Volume:在 Pod 的配置中定义一个 Volume,指定它要关联到哪个存储上。可以使用不同类型的 Volume,如 EmptyDir、HostPath、PersistentVolumeClaim 等,具体选择取决于需求。2. 在容器中使用 Volume Mounts:在 Pod 的配置中,为每个容器定义 Volume Mounts,将Volume 挂载到容器内部的指定路径上。这样容器就能够访问和操作 Volume 中的数据。3. 通过 Volume 实现数据持久化和共享:一旦 Volume 被挂载到容器中,容器就可以将数据写入Volume 或从 Volume 中读取数据。这使得数据能够在容器的生命周期内持久存在,并且可以被其他容器共享和访问。

      2.hostPath(主机目录)

        1. 直接访问主机文件系统:hostPath 卷允许容器直接访问主机节点上的文件系统。这对于需要访问主机节点上的特定文件或目录的应用程序非常有用。例如,某些日志收集器可能需要访问主机上的日志文件。2. 主机依赖性:hostPath 卷的挂载是与特定主机节点紧密关联的,因此在调度 Pod 时需要特别注意。如果 Pod 被调度到另一个主机节点上,它将无法访问之前挂载的主机文件系统。3. 危险性:hostPath 卷的使用需要谨慎,因为容器可以访问主机节点上的任何文件或目录,包括敏感的系统文件。此外,如果多个 Pod 使用相同的 hostPath 卷并且并发写入同一个文件,可能会导致冲突和数据损坏。4. 开发和测试环境:hostPath 卷特别适用于开发和测试环境,因为它可以方便地将主机节点上的文件或目录映射到容器中,从而加快开发和测试工作流程。

        3.NFS(远程目录)

          1. 基本原理:NFS 允许将存储资源(文件或目录)通过网络共享给其他计算机。NFS 服务器将存储资源公开为共享,并将其挂载到客户端计算机上。客户端可以像访问本地文件系统一样访问这些共享资源。2. 持久化存储方案:在 Kubernetes 中,NFS 可以作为持久化存储方案使用。它可以提供可靠的存储,并在 pod 被重新调度到不同的节点时保持数据的一致性。3. 分布式访问:NFS 允许多个客户端同时访问共享资源。这使得它非常适合那些需要多个容器或Pod 共享数据的场景,例如数据库系统或分布式文件共享。4. 跨平台兼容性:NFS 是一种跨平台的文件系统协议,支持在不同操作系统之间进行文件共享。这使得它成为在混合操作系统集群中实现持久化存储的理想选择。5. 灵活性:NFS 提供了对存储资源的灵活访问和管理。管理员可以根据需求创建和配置 NFS 服务器,设置共享权限以及实施访问控制策略。6. 备份和恢复:NFS 具备备份和恢复数据的能力。通过使用备份工具和策略,可以对 NFS 共享的数据进行定期备份,以防止数据丢失或损坏。

          4.PVC

            K8s PV 是什么?PersistentVolume(PV):PV 是集群中的存储资源,可以是物理存储设备、网络存储或云存储等。PV 独立于 Pod 存在,它们是集群级别的资源,由集群管理员进行配置和管理。PV 具有持久性,即使 Pod被删除,PV 中的数据也会保留。PV 定义了存储的容量、访问模式和其他属性。K8s PVC 是什么?PersistentVolumeClaim(PVC):PVC 是 Pod 对 PV 的申请,它表示 Pod 需要一定的存储资源来满足其持久化存储需求。PVC 在 Pod 和 PV 之间建立了一个抽象层,使得 Pod 无需关心底层存储的具体细节。PVC 定义了 Pod 对存储的需求,包括存储容量、访问模式等。K8s PVC 和 PV 工作原理当创建一个 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)时,它们之间的相互作用和工作原理如下:1. PV 的供应方式: • 静态配置:集群管理员预先创建 PV 对象,包含了实际存储资源的详细信息。这些 PV存在于 Kubernetes API 中,供用户使用。 • 动态配置:当静态 PV 无法匹配用户的 PVC 时,Kubernetes 可以尝试为 PVC 动态地配置 PV。这基于 StorageClass,PVC 必须请求存储类,并且管理员必须创建和配置该类以进行动态配置。2. 绑定: 用户创建 PVC 并指定所需的存储资源和访问模式。 在找到可用的 PV 之前,PVC 保持未绑定状态。3. 使用: 首先,存储管理员创建 PV,并将其划分为多个存储卷。 用户在创建 Pod 之前创建 PVC,并指定所需的 PV 大小和访问模式。 创建 PVC 后,可以将其作为存储卷使用,并在 Pod 定义中引用该 PVC。 PV 和 PVC 是一对一的关系。一旦 PV 被某个 PVC 绑定,其他 PVC 就不能使用它。 如果没有合适的 PV 可用,PVC 将处于挂起状态,直到有一个合适的 PV 可用为止。4. 回收策略: 当删除使用 PVC 作为存储卷的 Pod 时,PVC 与 PV 的绑定将解除。 PV 有不同的回收策略可供选择: Retain(保留):删除 PVC 后,PV 保留,并且数据仍然存在。PV 不会被绑定到其他 PVC 上,可以再次使用。 Recycle(回收,不推荐):删除 PVC 后,PV 会被清空数据并准备重新使用。这个回收策略在 Kubernetes 1.15 版本后被废弃。  • Delete(删除):删除 PVC 后,PV 也会从 Kubernetes 中移除,并且相关的存储资源也会被删除。

            5.storangclass(存储类)

              Kubernetes 提供了 StorageClass 来自动创建 PV,以减轻管理员的维护成本。以下是关于Kubernetes PV、PVC 和 StorageClass 的更新内容:PV(PersistentVolume)是 Kubernetes 中的持久化存储资源,而 PVC(PersistentVolumeClaim)是 Pod 对 PV 的申请。传统的 PV 和 PVC 模式需要管理员预先创建 PV,然后将其与 PVC 进行一对一的绑定。这种方式在大规模部署中可能导致管理复杂性和维护成本的增加。为了解决这个问题,Kubernetes 引入了 StorageClass 机制。StorageClass 是一种动态创建 PV 的模板。集群管理员可以创建多个 StorageClass,每个 StorageClass 定义了存储的类型、访问模式和其他属性。当用户创建一个 PVC 并指定 StorageClass 时,Kubernetes 会自动根据该 StorageClass 创建一个 PV,并将其与 PVC 进行绑定。这样,管理员无需手动创建 PV,而是根据 StorageClass 的定义,动态生成 PV来满足用户的存储需求。StorageClass 提供了以下好处:1. 简化管理:StorageClass 允许管理员创建一组可重用的存储配置模板,而无需为每个 PVC 手动创建和管理 PV。这降低了管理成本和复杂性。2. 动态供应:使用 StorageClass,管理员可以根据需求动态创建 PV,从而自动为 PVC 提供存储资源。这种动态供应的机制使得存储的分配更加灵活和自动化。3. 可选性和灵活性:StorageClass 允许管理员根据存储的不同特性和需求创建不同的StorageClass。用户可以根据自己的需求选择合适的 StorageClass,并使用相应的存储资源。

              三、实战

              1. emptyDir(临时目录)

                vim emptyDir.yaml---apiVersion: v1kind: Podmetadata:  name: emptydir labels: app: emptyDirspec: containers: - name: empty image: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: cache mountPath: /cache volumes: - emptyDir: {} name: cache测试:#查看调度到了那台机器上kubectl get pods -owide#查看pod的uidkubectl get pods -o yaml | grep uid#登录到被调度到的节点cd /var/lib/kubelet/pods/$uid/cd volumes/kubernetes.io~empty-dir/cache/在宿主机创建aa目录mkdir aa登录pod查看kubectl exec -it emptydir /bin/shkubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.# cd cache# lsaa# 在pod创建bb目录mkdir bb在宿主机查看[root@lx110 cache]# lsaa bb删除pod查看是否目录被清空kubectl delete pods emptydir [root@lx110 cache]# ls[root@lx110 cache]

                2.hostPath

                  vim hostPath.yaml---apiVersion: v1kind: Podmetadata: name: hostpathspec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: hostpath mountPath: /cache-nginx - name: tomcat image: docker.io/library/tomcat:latest imagePullPolicy: IfNotPresent volumeMounts: - name: hostpath mountPath: /cache-tomcat volumes: - name: hostpath hostPath: path: /data type: DirectoryOrCreate测试:#查看调度到了那台机器kubectl get pods -owide#在宿主机目录上创建cc目录mkdir /data/cc登录到pod上kubectl exec -it hostpath -c tomcat /bin/shkubectl exec -it hostpath -c nginx /bin/sh查看/cache-tomcat和/cache-nginx和宿主机/data/目录下一样

                  type:

                  取值行为
                  空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
                  DirectoryOrCreate如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
                  Directory在给定路径上必须存在的目录。
                  FileOrCreate如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
                  File在给定路径上必须存在的文件。
                  Socket在给定路径上必须存在的 UNIX 套接字。
                  CharDevice在给定路径上必须存在的字符设备。
                  BlockDevice在给定路径上必须存在的块设备。

                  3.NFS

                    1、搭建NFS服务(控制节点)yum install nfs-utils -y#在宿主机创建 NFS 需要的共享目录mkdir /data/volumes -pv  mkdir: created directory '/data' mkdir: created directory '/data/volumes'systemctl start nfs-servervim /etc/exports /data/volumes *(rw,no_root_squash)exportfs -arvsystemctl restart nfs-serversystemctl enable nfs-server其余节点安装nfs节点驱动yum install nfs-utils -ysystemctl start nfs-server测试连接192.168.1.100/data/volumesshowmount -e 192.168.1.100挂载mount -t nfs 192.168.1.100:/data/volumes /data2/手动卸载umount /data22、编写yaml文件vim nfs.yaml---apiVersion: v1kind: Podmetadata: name: nfsspec: containers: - name: test-nfs image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 protocol: TCP volumeMounts: - name: nfs-volumes mountPath: /usr/share/nginx/html volumes: - name: nfs-volumes nfs: path: /data/volumes server: 192.168.1.1003、测试echo "123" >> /data/volumes/index.htmlkubectl get pods -owideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbusybox-6bb56cf754-sx2dt 1/1 Running 8 (30m ago) 4d 10.247.66.155 lx120 none> none>hostpath 2/2 Running 0 104m 10.246.71.98 lx110 none> none>nfs 1/1 Running 0 25s 10.247.66.157 lx120 none> none>[root@lx100 test]# curl 10.247.66.157:80123

                    4.PVC

                    静态配置

                      1、创建nfs共享目录[root@lx100 test]# mkdir /data/volume_test/v{1,2} -p[root@lx100 test]# vim /etc/exports/data/volumes *(rw,no_root_squash)/data/volume_test/v1 *(rw,no_root_squash)/data/volume_test/v2 *(rw,no_root_squash)[root@lx100 test]# exportfs -arvexporting *:/data/volume_test/v2exporting *:/data/volume_test/v1exporting *:/data/volumes2、创建pv---apiVersion: v1kind: PersistentVolumemetadata: name: testpv1 labels: app: v1spec: capacity: storage: 1Gi accessModes: ["ReadWriteOnce"] #单路读写,只允许一个pod去读写 nfs: path: /data/volume_test/v1 server: 192.168.1.100---apiVersion: v1kind: PersistentVolumemetadata: name: testpv2 labels: app: v2spec: capacity: storage: 2Gi accessModes: ["ReadWriteMany"] #多路读写,允许多个pod读写 nfs: path: /data/volume_test/v2 server: 192.168.1.100查看pvkubectl get pv --show-labels #状态为Available为可用状态3、创建PVC---apiVersion: v1kind: PersistentVolumeClaimmetadata: name: testpvc labels: app: v1spec: selector: matchLabels: app: v1 accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Gi测试:[root@lx100 test]# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEtestpv1 1Gi RWO Retain Bound default/testpvc 10mtestpv2 2Gi RWX Retain Available 10m[root@lx100 test]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtestpvc Bound testpv1 1Gi RWO 35s创建Pod挂载pvc---apiVersion: v1kind: Podmetadata: name: pvctest1spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: pvc mountPath: /usr/share/nginx/html volumes: - persistentVolumeClaim: claimName: testpvc name: pvc测试#查看pod信息kubectl get pods -owideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbusybox-6bb56cf754-sx2dt 1/1 Running 9 (41m ago) 4d1h 10.247.66.155 lx120 hostpath 2/2 Running 0 175m 10.246.71.98 lx110 nfs 1/1 Running 0 71m 10.247.66.157 lx120 pvctest1 1/1 Running 0 113s 10.247.66.158 lx120 [root@lx100 test]# echo 2355555 >> /data/volume_test/v1/index.html[root@lx100 test]# curl 10.247.66.158 2355555

                      storangeclass(存储类)

                        安装nfs provisioner,用于配合存储类动态生成pv参考:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner上传nfs-subdir-external-provisioner.tar.gz并导入镜像ctr -n=k8s.io image import nfs-subdir-external-provisioner.tar.gz#创建运行nfs-provisioner需要的SAvim serviceaccount.yaml ---apiVersion: v1kind: ServiceAccountmetadata:  name: nfs-provisioner#对sa授权kubectl create clusterrolebinding nfs-provisioner --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner
                        #安装nfs-provisioner程序mkdir /data/nfs_pro -pvim /etc/exports/data/volumes *(rw,no_root_squash)/data/volume_test/v1 *(rw,no_root_squash)/data/volume_test/v2 *(rw,no_root_squash)/data/nfs_pro *(rw,no_root_squash)exportfs -arvvim nfs-deployment.yaml---kind: DeploymentapiVersion: apps/v1metadata: name: nfs-provisionerspec: selector: matchLabels: app: nfs-provisioner replicas: 1 strategy: type: Recreate template: metadata: labels: app: nfs-provisioner spec: serviceAccount: nfs-provisioner containers: - name: nfs-provisioner image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0 imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: example.com/nfs - name: NFS_SERVER value: 192.168.1.20 - name: NFS_PATH value: /data/nfs_pro volumes: - name: nfs-client-root nfs: server: 192.168.1.20          path: /data/nfs_pro#创建storageclass,动态供给PVvim nfs-storageclass.yaml---apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: nfsprovisioner: example.com/nfs #应该与上面deployment文件中的env- name: PROVISIONER_NAME值一致kubectl apply -f nfs-storageclass.yaml#查看storageclass是否被创建kubectl get scNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGEnfs example.com/nfs Delete Immediate false 14mvim claim.yaml---kind: PersistentVolumeClaimapiVersion: v1metadata: name: test-claim1spec: accessModes: ["ReadWriteMany"] resources: requests: storage: 1Gi storageClassName: nfs[root@lx20 k8s]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtest-claim1   Bound    pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b   1Gi        RWX            nfs            13mvim read-pod.yaml---kind: PodapiVersion: v1metadata: name: podtestpvcspec: containers: - name: pod image: nginx imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-pvc mountPath: /usr/share/nginx/html restartPolicy: "Never" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: test-claim1kubectl get podsecho liangxi >> /data/nfs_pro/default-test-claim1-pvc-ebdb2ca5-e18f-489e-92a4-ff938a4a310b/index.htmlkubectl get pods -owidecurl http://10.243.166.13liangxi#查看详细信息kubectl describe pod podtestpvcVolumes: nfs-pvc: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: test-claim1    ReadOnly:   false