59.持久化卷(Persistent Volume)

持久化卷(Persistent Volume)

本文档介绍了KubernetesPersistentVolume 的当前状态。建议您在阅读本文档前先熟悉 volume

介绍

对于管理计算资源来说,管理存储资源明显是另一个问题。PersistentVolume 子系统为用户和管理员提供了一个API,该API将如何提供存储的细节抽象了出来。为此,我们引入两个新的API资源:PersistentVolumePersistentVolumeClaim

PersistentVolume(PV)是由管理员设置的存储,它是集群的一部分。就像节点是集群中的资源一样,PV也是集群中的资源。PVVolume之类的卷插件,但具有独立于使用PVPod的生命周期。此API对象包含存储实现的细节,即NFSiSCSI或特定于云供应商的存储系统。

PersistentVolumeClaim(PVC)是用户存储的请求。它与Pod相似。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或 只读多次模式挂载

虽然 PersistentVolumeClaims 允许用户使用抽象存储资源,但用户需要具有不同性质(例如性能)的 PersistentVolume 来解决不同的问题。集群管理员需要能够提供各种各样的 PersistentVolume,这些PersistentVolume 的大小和访问模式可以各有不同,但不需要向用户公开实现这些卷的细节。对于这些需求,StorageClass 资源可以实现。

请参阅工作示例的详细过程

卷和声明的生命周期

PV属于集群中的资源。PVC是对这些资源的请求,也作为对资源的请求的检查。PVPVC之间的相互作用遵循这样的生命周期:

配置(Provision)

有两种方式来配置PV:静态或动态。

静态

集群管理员创建一些PV。它们带有可供集群用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费。

动态

根据 StorageClasses,当管理员创建的静态PV都不匹配用户的 PersistentVolumeClaim 时,集群可能会尝试动态地为PVC创建卷。

绑定

在动态配置的情况下,用户创建或已经创建了具有特定存储量的 PersistentVolumeClaim 以及某些访问模式。master中的控制环路监视新的PVC,寻找匹配的PV(如果可能,并将它们绑定在一起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦PVPVC绑定后,PersistentVolumeClaim 绑定是排他性的,不管它们是如何绑定的。PVCPV绑定是一对一的映射。

如果没有匹配的卷,声明将无限期地保持未绑定状态。随着匹配卷的可用,声明将被绑定。例如,配置了许多50Gi PV的集群将不会匹配请求100GiPVC。将100Gi PV添加到集群时,可以绑定PVC

使用

Pod使用声明作为卷。集群检查声明以查找绑定的卷并为集群挂载该卷。对于支持多种访问模式的卷,用户指定在使用声明作为容器中的卷时所需的模式。

用户进行了声明,并且该声明是绑定的,则只要用户需要,绑定的PV就属于该用户。用户通过在Podvolume配置中包含 persistentVolumeClaim 来调度Pod并访问用户声明的PV

持久化卷声明的保护

PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失。

注意:当pod状态为 Pending 并且pod已经分配给节点或podRunning 状态时,PVC处于活动状态。

当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何pod使用。

您可以看到,当PVC的状态为 Teminatiing 时,PVC受到保护,Finalizers 列表中包含 kubernetes.io/pvc-protection

kubectl described pvc hostpath
Name:          hostpath
Namespace:     default
StorageClass:  example-hostpath
Status:        Terminating
Volume:
Labels:        <none>
Annotations:   volume.beta.kubernetes.io/storage-class=example-hostpath
               volume.beta.kubernetes.io/storage-provisioner=example.com/hostpath
Finalizers:    [kubernetes.io/pvc-protection]
...

回收

用户用完volume后,可以从允许回收资源的API中删除PVC对象。PersistentVolume 的回收策略告诉集群在存储卷声明释放后应如何处理该卷。目前,volume的处理策略有保留、回收或删除。

保留

保留回收策略允许手动回收资源。当 PersistentVolumeClaim 被删除时,PersistentVolume 仍然存在,volume被视为“已释放”。但是由于前一个声明人的数据仍然存在,所以还不能马上进行其他声明。管理员可以通过以下步骤手动回收卷。

  1. 删除 PersistentVolume。在删除PV后,外部基础架构中的关联存储资产(如AWS EBS、GCE PD、Azure DiskCinder卷)仍然存在。
  2. 手动清理相关存储资产上的数据。
  3. 手动删除关联的存储资产,或者如果要重新使用相同的存储资产,请使用存储资产定义创建新的 PersistentVolume

回收

如果存储卷插件支持,回收策略会在volume上执行基本擦除(rm -rf / thevolume / *,可被再次声明使用。

但是,管理员可以使用如此处所述的Kubernetes controller manager命令行参数来配置自定义回收站pod模板。自定义回收站pod模板必须包含 volumes 规范,如下面的示例所示:

apiVersion: v1
kind: Pod
metadata:
  name: pv-recycler
  namespace: default
spec:
  restartPolicy: Never
  volumes:
    - name: vol
      hostPath:
        path: /any/path/it/will/be/replaced
  containers:
    - name: pv-recycler
      image: "k8s.gcr.io/busybox"
      command:
        [
          "/bin/sh",
          "-c",
          'test -e /scrub && rm -rf /scrub/..?* /scrub/.[!.]* /scrub/*  && test -z "$(ls -A /scrub)" || exit 1',
        ]
      volumeMounts:
        - name: vol
          mountPath: /scrub

但是,volumes 部分的自定义回收站模块中指定的特定路径将被替换为正在回收的卷的特定路径。

删除

对于支持删除回收策略的卷插件,删除操作将从Kubernetes中删除 PersistentVolume 对象,并删除外部基础架构(如AWS EBS、GCE PD、Azure DiskCinder卷)中的关联存储资产。动态配置的卷继承其 StorageClass,默认为Delete。管理员应该根据用户的期望来配置 StorageClass,否则就必须要在PV创建后进行编辑或修补。请参阅更改PersistentVolume的回收策略

扩展持久化卷声明

Kubernetes 1.8增加了对扩展持久化存储卷的Alpha支持。在v1.9中,以下持久化卷支持扩展持久化卷声明:

  • gcePersistentDisk
  • awsElasticBlockStore
  • Cinder
  • glusterfs
  • rbd

管理员可以通过将 ExpandPersistentVolumes 特性门设置为true来允许扩展持久卷声明。管理员还应该启用PersistentVolumeClaimResize 准入控制插件来执行对可调整大小的卷的其他验证。

一旦 PersistentVolumeClaimResize 准入插件已打开,将只允许其 allowVolumeExpansion 字段设置为true的存储类进行大小调整。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gluster-vol-default
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://192.168.10.100:8080"
  restuser: ""
  secretNamespace: ""
  secretName: ""
allowVolumeExpansion: true

一旦功能门和前述准入插件打开后,用户就可以通过简单地编辑声明以请求更大的 PersistentVolumeClaim 卷。这反过来将触发 PersistentVolume 后端的卷扩展。

在任何情况下都不会创建新的 PersistentVolume 来满足声明。Kubernetes将尝试调整现有volume来满足声明的要求。

对于扩展包含文件系统的卷,只有在ReadWrite模式下使用 PersistentVolumeClaim 启动新的Pod时,才会执行文件系统调整大小。换句话说,如果正在扩展的卷在pod或部署中使用,则需要删除并重新创建要进行文件系统调整大小的pod。此外,文件系统调整大小仅适用于以下文件系统类型:

  • XFS
  • Ext3、Ext4

注意:扩展EBS卷是一个耗时的操作。另外,每6个小时有一个修改卷的配额。

持久化卷类型

PersistentVolume 类型以插件形式实现。Kubernetes目前支持以下插件类型:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • FC (Fibre Channel)
  • FlexVolume
  • Flocker
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack block storage)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • HostPath (仅限于但节点测试—— 不会以任何方式支持本地存储,也无法在多节点集群中工作)
  • VMware Photon
  • Portworx Volumes
  • ScaleIO Volumes
  • StorageOS

原始块支持仅适用于以上这些插件。

持久化卷

每个PV配置中都包含一个sepc规格字段和一个status卷状态字段。

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv0003
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path: /tmp
    server: 172.17.0.2

容量

通常,PV将具有特定的存储容量。这是使用PV的容量属性设置的。查看Kubernetes 资源模型 以了解 capacity 预期。

目前,存储大小是可以设置或请求的唯一资源。未来的属性可能包括IOPS、吞吐量等。

卷模式

v1.9之前,所有卷插件的默认行为是在持久卷上创建一个文件系统。在v1.9中,用户可以指定一个volumeMode,除了文件系统之外,它现在将支持原始块设备。volumeMode的有效值可以是“Filesystem”或“Block”。如果未指定,volumeMode将默认为“Filesystem”。这是一个可选的API参数。

注意:该功能在V1.9中是alpha的,未来可能会更改。

访问模式

PersistentVolume 可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式。

存储模式包括:

  • ReadWriteOnce——该卷可以被单个节点以读/写模式挂载
  • ReadOnlyMany——该卷可以被多个节点以只读模式挂载
  • ReadWriteMany——该卷可以被多个节点以读/写模式挂载

在命令行中,访问模式缩写为:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany

重要!一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。例如,GCEPersistentDisk可以由单个节点作为ReadWriteOnce模式挂载,或由多个节点以ReadOnlyMany模式挂载,但不能同时挂载。

Volume插件 ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStore - -
AzureFile
AzureDisk - -
CephFS
Cinder - -
FC -
FlexVolume -
Flocker - -
GCEPersistentDisk -
Glusterfs
HostPath - -
iSCSI -
PhotonPersistentDisk - -
Quobyte
NFS
RBD -
VsphereVolume - - (当pod并列时有效)
PortworxVolume -
ScaleIO -
StorageOS - -

PV可以具有一个类,通过将 storageClassName 属性设置为 StorageClass 的名称来指定该类。一个特定类别的PV只能绑定到请求该类别的PVC。没有 storageClassNamePV就没有类,它只能绑定到不需要特定类的PVC

过去,使用的是 volume.beta.kubernetes.io/storage-class 注解而不是 storageClassName 属性。这个注解仍然有效,但是将来的Kubernetes版本中将会完全弃用它。

回收策略

当前的回收策略包括:

  • Retain(保留)——手动回收
  • Recycle(回收)——基本擦除(rm -rf /thevolume/*
  • Delete(删除)——关联的存储资产(例如AWS EBS、GCE PD、Azure DiskOpenStack Cinder卷)将被删除

当前,只有NFSHostPath支持回收策略。AWS EBS、GCE PD、Azure DiskCinder卷支持删除策略。

挂载选项

Kubernetes管理员可以指定在节点上为挂载持久卷指定挂载选项。

注意:不是所有的持久化卷类型都支持挂载选项。

以下卷类型支持挂载选项:

  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • NFS
  • iSCSI
  • RBD (Ceph Block Device)
  • CephFS
  • Cinder (OpenStack卷存储)
  • Glusterfs
  • VsphereVolume
  • Quobyte Volumes
  • VMware Photon

挂载选项没有校验,如果挂载选项无效则挂载失败。

过去,使用 volume.beta.kubernetes.io/mount-options 注解而不是 mountOptions 属性。这个注解仍然有效,但在将来的Kubernetes版本中它将会被完全弃用。

状态

卷可以处于以下的某种状态:

  • Available(可用)——一块空闲资源还没有被任何声明绑定
  • Bound(已绑定)——卷已经被声明绑定
  • Released(已释放)——声明被删除,但是资源还未被集群重新声明
  • Failed(失败)——该卷的自动回收失败

命令行会显示绑定到PVPVC的名称。

PersistentVolumeClaim

每个PVC中都包含一个spec规格字段和一个status声明状态字段。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  storageClassName: slow
  selector:
    matchLabels:
      release: "stable"
    matchExpressions:
      - { key: environment, operator: In, values: [dev] }

访问模式

在请求具有特定访问模式的存储时,声明使用与卷相同的约定。

卷模式

声明使用与卷相同的约定,指示将卷作为文件系统或块设备使用。

资源

pod一样,声明可以请求特定数量的资源。在这种情况下,请求是用于存储的。相同的资源模型适用于卷和声明。

选择器

声明可以指定一个标签选择器来进一步过滤该组卷。只有标签与选择器匹配的卷可以绑定到声明。选择器由两个字段组成:

  • matchLabels:volume必须有具有该值的标签
  • matchExpressions:这是一个要求列表,通过指定关键字,值列表以及与关键字和值相关的运算符组成。有效的运算符包括In、NotIn、ExistsDoesNotExist

所有来自 matchLabelsmatchExpressions 的要求都被“与”在一起——它们必须全部满足才能匹配。

声明可以通过使用属性 storageClassName 指定 StorageClass 的名称来请求特定的类。只有所请求的类与PVC具有相同 storageClassNamePV才能绑定到PVC

PVC不一定要请求类。其 storageClassName 设置为 ""PVC始终被解释为没有请求类的PV,因此只能绑定到没有类的PV(没有注解或 ""。没有 storageClassNamePVC根据是否打开DefaultStorageClass 准入控制插件,集群对其进行不同处理。

  • 如果打开了准入控制插件,管理员可以指定一个默认的 StorageClass。所有没有 StorageClassNamePVC将被绑定到该默认的PV。通过在 StorageClass 对象中将注解 storageclass.kubernetes.io/is-default-class 设置为 “true” 来指定默认的 StorageClass。如果管理员没有指定缺省值,那么集群会响应PVC创建,就好像关闭了准入控制插件一样。如果指定了多个默认值,则准入控制插件将禁止所有PVC创建。
  • 如果准入控制插件被关闭,则没有默认 StorageClass 的概念。所有没有 storageClassNamePVC只能绑定到没有类的PV。在这种情况下,没有 storageClassNamePVC的处理方式与 storageClassName 设置为 ""PVC的处理方式相同。

根据安装方法的不同,默认的 StorageClass 可以在安装过程中通过插件管理器部署到Kubernetes集群。

PVC指定了 selector,除了请求一个 StorageClass 之外,这些需求被“与”在一起:只有被请求的类的PV具有和被请求的标签才可以被绑定到PVC

注意:目前,具有非空 selectorPVC不能为其动态配置PV

过去,使用注解 volume.beta.kubernetes.io/storage-class 而不是 storageClassName 属性。这个注解仍然有效,但是在未来的Kubernetes版本中不会支持。

声明作为卷

通过将声明用作卷来访问存储。声明必须与使用声明的pod存在于相同的命名空间中。集群在pod的命名空间中查找声明,并使用它来获取支持声明的 PersistentVolume。该卷然后被挂载到主机的pod上。

kind: Pod
apiVersion: v1
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: dockerfile/nginx
      volumeMounts:
        - mountPath: "/var/www/html"
          name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: myclaim

命名空间注意点

PersistentVolumes 绑定是唯一的,并且由于 PersistentVolumeClaims 是命名空间对象,因此只能在一个命名空间内挂载具有“多个”模式(ROXRWX)的声明。

原始块卷支持

原始块卷的静态配置在v1.9中作为alpha功能引入。由于这个改变,需要一些新的API字段来使用该功能。目前,Fibre Channl是支持该功能的唯一插件。

使用原始块卷作为持久化卷

apiVersion: v1
kind: PersistentVolume
metadata:
  name: block-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  volumeMode: Block
  persistentVolumeReclaimPolicy: Retain
  fc:
    targetWWNs: ["50060e801049cfd1"]
    lun: 0
    readOnly: false

持久化卷声明请求原始块卷

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

Pod规格配置中为容器添加原始块设备

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-block-volume
spec:
  containers:
    - name: fc-container
      image: fedora:26
      command: ["/bin/sh", "-c"]
      args: ["tail -f /dev/null"]
      volumeDevices:
        - name: data
          devicePath: /dev/xvda
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: block-pvc

注意:当为Pod增加原始块设备时,我们在容器中指定设备路径而不是挂载路径。

绑定块卷

如果用户通过使用 PersistentVolumeClaim 规范中的 volumeMode 字段指示此请求来请求原始块卷,则绑定规则与以前不认为该模式为规范一部分的版本略有不同。

下面是用户和管理员指定请求原始块设备的可能组合的表格。该表指示卷是否将被绑定或未给定组合。静态设置的卷的卷绑定矩阵:

PV volumeMode PVC volumeMode 结果
unspecified unspecified 绑定
unspecified Block 不绑定
unspecified Filesystem 绑定
Block unspecified 不绑定
Block Block 绑定
Block Filesystem 不绑定
Filesystem Filesystem 绑定
Filesystem Block 不绑定
Filesystem unspecified 绑定

注意alpha版本只支持静态配置卷。使用原始块设备时,管理员应该注意考虑这些值。

编写可移植配置

如果您正在编写在多种集群上运行并需要持久存储的配置模板或示例,我们建议您使用以下模式:

  • 要在您的在配置组合中包含 PersistentVolumeClaim 对象(与DeploymentConfigMap等一起
  • 不要在配置中包含 PersistentVolume 对象,因为用户实例化配置可能没有创建 PersistentVolume 的权限。
  • 给用户在实例化模板时提供存储类名称的选项。
    • 如果用户提供存储类名称,则将该值放入 persistentVolumeClaim.storageClassName 字段中。如果集群具有由管理员启用的StorageClass,这将导致PVC匹配正确的存储类别。
    • 如果用户未提供存储类名称,则将 persistentVolumeClaim.storageClassName 字段保留为nil
      • 这将导致使用集群中默认的StorageClass为用户自动配置PV。许多集群环境都有默认的StorageClass,或者管理员可以创建自己的默认StorageClass
  • 在您的工具中,请注意一段时间之后仍未绑定的PVC,并向用户展示它们,因为这表示集群可能没有动态存储支持(在这种情况下用户应创建匹配的PV,或集群没有存储系统(在这种情况下用户不能部署需要PVC的配置

原文地址:https://kubernetes.io/docs/concepts/storage/persistent-volumes/

译者:rootsongjc

上一页
下一页