Kubernetes共享存储详解

Kubernetes 对于有状态的容器应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者 emptyDir 临时存储卷,而且需要更加可靠的存储来保护应用产生的重要数据,以便容器应用在重建之后,仍然可以使用之前的数据。不过,存储资源和计算资源(GPU/内存)的管理方式完全不同。为了能够屏蔽底层存储实现的细节,让用户方便使用,同时能让管理员方便管理,Kubernetes从v1.0版本就引入了 PersistentVolumePersistentVolumeClaim 两个资源对象来实现对存储的管理子系统。

PersistentVolume(PV) 是对底层网络共享存储的对象,将共享存储定义为一种”资源“,比如节点(Node)也是一种容器应用可以”消费“的资源。PV由管理员进行创建和配置,它与共享存储的具体实现直接相关,例如 GlusterFS、iSCSI、RBD或GCE/AWS 公有云提供的共享存储,通过插件式的机制完成与共享存储的对接,以供应用访问和使用。

PersistentVolumeClaim(PVC) 则是用户对于存储资源的一个”申请“。就像 Pod ”消费“ Node 的资源一样,PVC 会”消费“ PV资源。PVC 可以申请特定的存储空间和访问模式。

使用 PVC ”申请“到一定的存储空间仍然不足以满足应用对于存储设备的各种需求。通常应用程序都会对存储设备的特性和性能有不同的要求,包括读写速度、并发性能、数据冗余等更高的要求,Kubernetes 从 v1.4 版本开始引入了一个新的资源对象StorageClass,用于标记存储资源的特性和性能。到v1.6版本时,StorageClass 和动态资源供应的机制得到了完善,实现了存储卷的按需创建,在共享存储的自动化管理进程中实现了重要的一步。

通过 StorageClass 的定义,管理员可以将存储资源定义为某种类别(Class),正如存储设备对于自身的配置描述(Profile),例如"快速存储"、”慢速存储“、”有数据冗余“、”无数据冗余“等。用户依据 StorageClass 的描述就能够直观得知各种存储资源的特性,就可以根据应用对存储资源的需求去申请存储资源了。

下面对Kubernetes的PV、PVC、StorageClass和动态资源供应等共享存储管理机制进行详细说明。

PV详解

PV作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。下面的例子声明的PV具有如下属性:5Gi 存储空间、访问模式为 “ReadWriteOnce”,存储类型为 “slow” (要求系统中已存在名为 slow 的 StorageClass),回收策略为 “Recycle”,并且后端存储类型为 “nfs” (设置了 NFS Server 的IP地址和路径):

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 5Gi
  accessMode:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  nfs:
    path: /tmp
    server: 172.17.0.2

Kubernetes支持的PV类型如下:

  • gcePersistentDisk:GCE公共云提供的 PersistentDisk。
  • AWSElasticBlockStore:AWS公共云提供的 ElasticBlockStore。
  • AzureFile:Azure公共云提供的File。
  • AzureDisk:Azure公共云提供的Disk。
  • FC(Fibre Channel)
  • Flocker
  • NFS:网络文件系统。
  • iSCSI
  • RBD(Rados Block Device):Ceph块存储。
  • CephFS
  • GlusterFS
  • Cinder:OpenStack Cinder块存储。
  • VsphereVolume
  • Quobyte Volumes
  • VMware Photon
  • Portworx Volumes
  • ScaleIO Volumes
  • HostPath:宿主机目录,仅用于单机测试。
    每种存储类型都有各自的特定,在使用时需要根据它们各自的参数进行设置。

1. PV的关键配置参数

1)存储能力(Capacity)

描述存储设备的能力,目前仅支持对存储空间的设置(storage=xx),未来可能加入IOPS、吞吐率等指标的设置。

2)访问模式(Access Modes)

对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限。访问模式如下:

  • ReadWriteOnce(简写为RWO):读写权限,并且只能被单个Node挂载。
  • ReadOnlyMany(简写为ROX):只读权限,允许被多个Node挂载。
  • ReadWriteMany(简写为RWX):读写权限,允许被多个Node挂载。

某些PV可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。

下表描述了不同的存储提供者支持的访问模式,在PV的定义时需要与它们匹配:

3)存储类别(Class)

PV可以设定其存储的类型(Class),通过 storageClassName 参数指定一个 StorageClass 资源对象的名称。具有特定“类别”的 PV 只能与请求了该“类别”的 PVC 进行绑定。未设定 “类别” 的 PV 则只能与不请求任何 “类别” 的 PVC 进行绑定。

4)回收策略

目前支持如下三种回收策略:

  • 保留(Retain):保留数据,需要手工处理。
  • 回收空间(Recycle):简单清除文件的操作(例如执行 rm -rf /thevolume/* 命令)。
  • 删除(Delete):与 PV 向量的后端存储完成 volume 的删除操作;如 AWS EBS、 GCE PD、Azure Disk 和 Cinder volumes 支持 “Delete” 策略。

目前,只有 NFS 和 HostPath 两种类型的存储设备支持 “Recycle” 策略; AWS EBS、 GCE PD、Azure Disk 和 Cinder volumes 支持 “Delete” 策略。

2. PV 生命周期的各个阶段(Phase)

某个 PV 在生命周期中,可以处于以下4个阶段之一:

  • Available:可用状态,还未与某个 PVC 绑定。
  • Bound:已与某个 PVC 绑定。
  • Released:绑定的 PVC 已经删除,资源已释放,但没有被集群回收。
  • Failed:自动资源回收失败。

3. PV 的挂载参数(Mount Options)

在将PV挂载到一个 Node 上时,根据后端存储的特点,可能需要设置额外的挂载参数,目前可以通过在PV的定义中,设置一个名为“volume.beta.kubernetes.io/mount-options”的 annotation 来实现。下面的例子对一个类型的 gcePersistentDisk 的 PV 设置了挂载参数 “discard”:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: gce-disk-1
  annotations:
    volume.beta.kubernetes.io/mount-options: discard
  spec:
    capacity:
      storage: 10Gi
    accessMode:
      - ReadWriteOnce
    gcePersistentDisk:
      fsType: ext4
      pdName: gce-disk-1

并非所有类型的存储都支持设置挂载参数。从 Kubernetes v1.6 版本开始,以下存储类型支持设置挂载参数:

  • gcePersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • NFS
  • iSCSI
  • RBD(Rados Block Device)
  • CephFS
  • GlusterFS
  • Cinder
  • VsphereVolume
  • Quobyte Volumes
  • VMware Photon

定义了 PV 以后如何使用呢?这是就需要用到 PVC 了。

PVC详解

PVC 作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV 选择条件和存储类别等信息的设置。下面的例子声明的 PVC 具有如下属性:申请8Gi存储空间,访问模式为 “ReadWriteOnce”, PV 选择条件为包含标签 “release=stable” 并且包含条件为 “environment In [dev]”的标签,存储类别为 “slow” (要求系统中已存在名为 slow 的 StorageClass):

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

PVC的关键配置参数说明如下:

  • 资源请求(Resources):描述对存储资源的请求,目前仅支持 request.storage 的设置,即存储空间大小。
  • 访问模式(Access Modes):PVC 也可以设置访问模式,用于描述用户应用对存储资源的访问权限。可以设置的三种访问模式与 PV 的设置相同。
  • PV选择条件(Selector):通过 Label Selector 的设置,可使 PVC 对应系统中已存在的各种 PV 进行筛选。系统将根据标签选择出合适的 PV 与该 PVC 进行绑定。选择条件可以使用 matchLabelsmatchExpressions 进行设置,如果两个字段都设置了,则 Selector 的逻辑将是两组条件同时满足才能完成匹配。
  • 存储类别(Class):PVC 在定义时可以设定需要的后端存储的“类别”(通过 storageClassName 字段指定),以降低对后端存储特性的详细信息的依赖。只有设置了该 Class 的 PV 才能被系统选出,并与该 PVC 进行绑定。

PVC 也可以不设置 Class 需求。如果 storageClassName 字段的值被设置为空(storageClassName=“”),则表示该 PVC 不要求特定的 Class,系统将只选择未设定 Class 的 PV 与之匹配和绑定。 PVC 也可以完全不设置 storageClassName 字段,此时系统将根据系统是否启用了名为 “DefaultStorageClass” 的 admission controller 进行相应的操作。

  • 未启用 DefaultStorageClass:等效于 PVC 设置 storageClassName 的值为空(storageClassName=“”),即只能选择未设定 Class 的 PV 与之匹配和绑定。
  • 启用DefaultStorageClass:要求极其管理员已定义默认的 StorageClass。如果系统中不存在默认的 StorageClass, 则等效于不启用 DefaultStorageClass 的情况。如果存在默认的 StorageClass,则系统将自动为 PVC 创建一个 PV(使用默认 StorageClass 的后端存储),并将它们进行绑定。集群管理员设置默认 StorageClass 的方法为,在 StorageClass 的定义中加上一个 annotation “storageclass.kubernetes.io/is-default-class=true”,如果管理员将多个 StorageClass 都定义为default,则由于不唯一,系统将无法为 PVC 创建相应的 PV。

注意,PVC 和 PV 都受限于 namespace,PVC 在选择 PV 时受到 namespace 的限制,只有相同 namespace 中的 PV 才可能与 PVC 绑定。 Pod 在应用 PVC 时同样受到 namespace 的限制,只有相同 namespace 中的 PVC 才能挂载到 Pod 内。

当 Selector 中的 Class 都进行设置时,系统将选择两个条件同时满足的 PV 与之匹配。

另外,如果资源供应使用的是动态模式,即管理员没有预先定义 PV,仅通过 StorageClass 交给系统自动完成 PV 的动态创建,那么 PVC 再设定 Selector 时,系统将无法为其供应任何存储资源了。

在启用动态供应模式的情况下,一旦用户删除了 PVC, 与之绑定的 PV 将根据其默认的回收策略 “Delete” 也会被删除。如果需要保留 PV (用户数据),则在动态绑定成功后,用户需要将系统自动生成 PV 的回收策略从“Delete” 改成 “Retain”。

PV 和 PVC 的生命周期

PV 可以看做可用的存储资源, PVC则是对存储资源的需求,PV 和 PVC 的相互关系遵循如下图所示的声明周期:

PV 和 PVC的生命周期

1.资源供应(Provisioning)

Kubernetes 支持两种资源的供应模式:静态模式(Static)和动态模式(Dynamic)。资源供应的结果就是创建好的 PV。

  • 静态模式:集群管理员手工创建许多 PV,在定义 PV 时需要将后端存储的特性进行设置。
  • 动态模式:集群管理员无需手工创建 PV,而是通过 StorageClass 的设置对后端存储进行描述,标记为某种“类型(Class)”。此时要求 PVC 对存储的类型进行声明,系统将自动完成 PV 的创建及与 PVC 的绑定。PVC 可以声明 Class 为 "",说明该 PVC 禁止使用动态模式。

2.资源绑定(Binding)

在用户定义好 PVC 之后,系统将根据 PVC 对存储资源的请求(存储空间和访问模式)在已存在的 PV 中选择一个满足 PVC 要求的 PV,一旦找到,就将该 PV 与用户定义的 PVC 进行绑定,然后用户的应用就可以使用这个 PVC 了。如果系统中没有满足 PVC 要求的 PV, PVC则会无限期处于 Pending 状态,知道等到系统管理员创建了一个符合其要求的 PV。PV 一旦绑定到某个 PVC 上,就被这个 PVC 独占,不能再与其他 PVC 进行绑定了。在这种情况下,当 PVC 申请的存储空间比 PV 少时,整个 PV 的空间都能够为 PVC 所用,可能会造成资源的浪费,如果资源供应使用的是动态模式,则系统在为 PVC 找到合适的 StorageClass 后,将自动创建一个 PV 并完成与 PVC 的绑定。

3.资源使用(Using)

Pod 使用 volume 的定义,将 PVC 挂载到容器内的某个路径进行使用。volume 的类型为 “persistentVolumeClaim”,在后面的示例中再进行详细说明。在容器应用挂载了一个 PVC 后,就能被持续独占使用。不过,多个 Pod 可以挂载同一个 PVC,应用程序需要考虑多个实例共同访问一块存储空间的问题。

4.资源释放(Releasing)

当用户对存储资源使用完毕后,用户可以删除 PVC,与该 PVC 绑定的 PV 将会被标记为“已释放”,但还不能立刻与其他 PVC 进行绑定。通过之前 PVC 写入的数据可能还留在存储设备上,只有在清除之后该 PV 才能再次使用。

5.资源回收(Reclaiming)

对于 PV,管理员可以设定回收策略(Reclaim Policy),用于设置与之绑定的 PVC 释放资源之后,对于遗留数据如何处理。只有 PV 的存储空间完成回收,才能供新的 PVC 绑定和使用。回收策略详见下节的说明。
下面通过两张图分别对在静态资源供应模式和动态资源供应模式下,PV、PVC、StorageClass 及 Pod 使用 PVC 的原理进行说明。

下图描述了在静态资源供应模式下,通过 PV 和 PVC 完成绑定,并供 Pod 使用的存储管理机制。

在静态模式下的PV和PVC原理

下图描述了在动态资源供应模式下,通过 StorageClass 和 PVC 完成资源动态绑定(系统自动生成 PV),并供 Pod 使用的存储管理机制。


在动态模式下的 StorageClass、PV 和 PVC 原理

接下来,我们再看看 StorageClass 的概念和用法。

StorageClass 详解

StorageClass 作为对存储资源的抽象定义,对用户设置的 PVC 申请屏蔽后端资源存储的细节,一方面减轻用户对存储资源细节的关注,另一方面也减轻了管理员手工管理 PV 的工作,由系统自动完成 PV 的创建和绑定,实现了动态的资源供应。使用基于 StorageClass 的动态资源供应模式将逐步成为云平台的标准存储配置模式。

StorageClass 的定义主要包括名称、后端存储的提供者(Provisioner)和后端存储的相关参数配置。StorageClass 一旦被创建出来,将无法修改。如果需要更改,则只能删除原 StorageClass 的定义重建。下面的例子定义了一个名为 “standard” 的 StorageClass,提供者为 aws-ebs,其参数设置了一个 type=gp2。

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:

1.StorageClass 的关键配置参数

1) 提供者(Provisioner)

描述存储资源的提供者,也可以看做后端存储驱动。目前 Kubernetes 支持的 Provisioner 都以 “kubernetes.io/” 为开头,用户也可以使用自定义的后端存储提供者。为了符合 StorageClass 的用法,自定义 Provisioner 需要符合存储卷的开发规范。

2)参数(Parameters)

后端存储资源提供者的参数设置,不同的 Provisioner 包括不同的参数设置。某些参数可以不显示设定, Provisioner 将使用其默认值。
接下来通过几种常见的 Provisioner 对 StorageClass 的定义进行详细说明:
AWS EBS 存储卷

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  zone: us-east-1d
  iopsPerGB: "10"

参数说明如下(详细说明请参数 AWS EBS文档):

  • type:可选项为io1,gp2,sc1,st1,默认值为gp2
  • zone:AWS zone的名称
  • iopsPerGB:及用于io1类型的volume,意为每秒GiB的I/O操作数量
  • encrypted:是否加密
  • kmsKeyId:加密时的 Amazon Resource Name

GCE PD 存储卷

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
  zone: us-centrall-a

参数说明如下(详细说明请参考GCE文档):

  • type:可选项为pd-standard、pd-ssd,默认值为pd-standard
  • zone:GCE zone名称

GlusterFS 存储卷

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://127.0.0.1:8081"
  clusterid: "2bce7ww8rwruisfdfuuy67wer"
  restauthenabled: "true"
  restuser: "admin"
  restuserkey: "My Secret"
  secretNamespace: "default"
  secretName: "heketi-secret"
  gidMin: "40000"
  gidMax: "50000"
  volumetype: "replicate:3"

参数说明如下(详细说明请参数 GlusterFS 和 Heketi 的文档):
-resturl:Gluster REST服务(Heketi)的URL地址,用于自动完成 GlusterFSvolume的设置。
-restauthenabled:是否对 Gluster REST服务启用安全机制。
-restuser:访问Gluster REST服务的用户名。
-secretNamespace 和 secretName:保存访问 Gluster REST服务密码的 Secret 资源对象名。
-clusterid:GlusterFS 的 Cluster ID。
-gidMin 和 gidMax:StorageClass 的 GID 范围,用于动态资源供应时为 PV 设置的 GID。
-volumetype:GlusterFS 的 volume 类型设置,例如 replicate:3 (Replicate类型,3份副本);disperse:4:2(Disperse类型,数据4份,冗余2份);“none”(Distribute类型)。

OpenStack Cinder存储卷

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gold
provisioner: kubernetes.io/cinder
parameters:
  type: fast
  availability: nova

参数说明如下:

  • type:Cinder 的 VolumeType,默认值为空。
  • availability:Availability Zone,默认值为空。
    其他 Provisioner 的 StorageClass 相关参数设置请参考它们各自的配置手册。

2.设置默认的(Default)StorageClass

要在系统中设置一个默认的 StorageClass,首先需要启用名为“DefaultStorageClass”的 admission controller,即在 kube-apiserver 的命令行参数 --admission-control 中增加:

--admission-control=...,DefaultStorageClass

然后,在 StorageClass 的定义中设置一个 annotation:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: gold
  annotations:
    storageclass.beta.kubernetes.io/is-default-class="true"
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd

通过 kubectl create命令创建成功后,查看 StorageClass 列表,可以看到名为 gold 的 StorageClass 被标记为“default”:

# kubectl get sc
NAME               TYPE
gold(default)           kubernetes.io/gce-pd

你可能感兴趣的:(Kubernetes共享存储详解)