Kubernetes共享存储

原创
半兽人 发表于: 2018-10-26   最后更新时间: 2022-01-18 16:31:28  
{{totalSubscript}} 订阅, 11,115 游览

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

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

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

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

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

下面对Kubermetes的PVPVCStorageClass动态资源供应等共享存储管理机制进行详细说明。

PV 详解

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

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - 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。
  • Cinder: OpenStack Cinder块存储。
  • GlusterFS。
  • VsphereVolume.
  • Quobyte Volumes。
  • VMware Photon。
  • Portworx Volumes。
  • ScaleIO Volumes。
  • HostPath:宿主机目录,仅用于单机测试。

每种存储类型都有各自的特点,在使用时需要根据它们各自的参数进行设置。

1、Capacity(容量)

描述存储设备具备的能力,目前仅支持对存储空间的设置(storage=xx),未来可能加入

2、访问模式(Access Modes)

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

注意:即使volume支持很多种访问模式,但它同时只能使用一种访问模式。比如,GCEPersistentDisk可以被单个节点映射为ReadWriteOnce,或者多个节点映射为ReadOnlyMany,但不能同时使用这两种方式来映射。

Volume Plugin ReadWriteOnce ReadOnlyMany ReadWriteMany
AWSElasticBlockStore - -
AzureFile
AzureDisk - -
CephFS
Cinder - -
FC -
FlexVolume -
Flocker - -
GCEPersistentDisk -
Glusterfs
HostPath - -
iSCSI -
PhotonPersistentDisk - -
Quobyte
NFS
RBD -
VsphereVolume - -
PortworxVolume -
ScaleIO -

3、存储类别(Class)

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

4、回收策略(Reclaim Policy)

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

  • 保留(Retain): 保留数据,需要手工处理。
  • 回收空间( Recycle): 简单清除文件的操作(例如执行rm -rf /thevolume/*命令)。
  • 删除(Delete): 与PV相连的后端存储完成volume的删除操作(如AWS EBS、GCE PD、Azure Disk、OpenStack Cinder等设备的内部volume清理)。

目前,只有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”
  accessModes :
    - ”ReadWriteOnce”
gcePersistentDisk:
  fsType: "ext4"
  pdName : "gce-disk-1

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

  • gcePersistentDisk。
  • AWSElasticBlockStore.
  • AzureFile。
  • AzureDisk。
  • NFS。
  • iSCSI。
  • RBD
  • (Rados Block Device): Ceph 块存储。
  • CephFS。
  • Cinder: OpenStack 块存储。
  • GlusterFS。
  • VsphereVolume.
  • Quobyte Volumes.
  • VMware Photon。

PVC详解

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

kind: PersistentVolumeClaim
apiVersion: v1
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进行绑定。选择条件可以使用matchLabels和matchExpressions进行设置。如果两个条件都设置了,则Selector的逻辑是两组条件同时满足才能完成匹配。
  • 存储类别(Class):PVC在定义时可以设定需要的后端存储的"类别"(通过storageClassName字段指定),以降低对后端存储特性的详细信息的依赖。只有设置了该Class的PV才能被系统选出,并与该PVC进行绑定。

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

  • 未启用DefaultStorageClass:等效于PVC设置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的相互关系遵循下图所示的生命周期。

screenshot

1 资源供应(Provisioning)

k8s支持两种资源的供应模式:静态模式(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 资源回收(Reclaimig)

对于PV,管理员可以设定回收策略(Reclaim Policy),用于设置与之绑定的PVC释放资源之后,对于遗留数据如何处理。只有PV的存储空间完成回收,才能供新的PVC绑定和使用。

下面通过两张图分别对在静态资源供应模式和动态资源供应模式下,PV、PVC、StorageClass及Pod使用PVC的原理进行说明。

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

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:
  type: gp2

1 StorageClass的关键配置参数

1)提供者(Provisioner)

描述存储资源的提供者,也可以看作后端存储驱动。
目前k8s支持的Provisioner都以"kubernetes.io/"为开头,用户也可以使用自定义的后端存储提供者。为了符合StorageClass的用法,自定义Provisioner需要符合存储卷的开发规范,详见该链接的说明:https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/volume-provisioning.md

2)参数(Parameters)

后端存储资源提供者的参数设置,不同的Provisioner包括不同的参数设置。某些参数可以不显示设定,Provisioner将使用其默认值。

3)下面介绍几种常用的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-id
  iopsPerGB: "10"

参数说明如下:

  • 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

参数说明:

  • 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: "https://127.0.0.1:8081"
  clusterid: "sadfa2435hfghsrg462345"
  restauthenabled: "true"
  restuser: "admin"
  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 设置默认的StorageClass

要在系统中设置一个默认的StorageClass,首先需要启动名为"DefaultStorageClass"admission controller, 即在kube-apiserver的命令行参数--admission-controll中增加:
--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/cinder
parameters:
  type: fast
  availability: nova

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

# kubectl get sc
gold (default)  kubernetes.io/cinder

动态存储管理实战:GlusterFS

本节以GlusterFS为例,从定义StorageClass、创建GlusterFS和Heketi服务、用户申请PVC到创建Pod使用存储资源,对StorageClass和动态资源分配进行详细说明,进一步剖析k8s的存储机制。

1 准备工作

首先在用于部署GlusterFS的三个节点上安装GlusterFS客户端:

yum -y install glusterfs glusterfs-fuse

GlusterFS管理服务容器需要以特权模式运行,中kube-apiserver的启动参数中确认已经打开了:

--allow-privileged=true

给要部署GlusterFS管理服务的节点打上"storagenode=glusterfs"的标签,这样可以将GlusterFS容器定向部署到安装了GlusterFS的Node上:

[k8s@kube-server harbor]$ kubectl label node kube-node1 storagenode=glusterfs
node "kube-node1" labeled
[k8s@kube-server harbor]$ kubectl label node kube-node2 storagenode=glusterfs
node "kube-node2" labeled
[k8s@kube-server harbor]$ kubectl label node kube-node3 storagenode=glusterfs
node "kube-node3" labeled

2 创建GlusterFS服务容器集群

GlusterFS服务容器以DaemonSet的方式进行部署,确保每台Node上都运行一个GlusterFS管理服务,glusterfs-daemonset.yaml内容如下。参照 https://github.com/gluster/gluster-kubernetes。

1)在各个Node节点的启动参数中增加以下选项,因为GlusterFS需要使用容器的特权模式运行

--allow-privileged

生效:

systemctl daemon-reload
systemctl restart kubelet
systemctl status kubelet

2)给每个运行GlusterFS的Node节点增加一块数据磁盘

注意数据盘挂载后,在系统中使用的设备描述符,需要在下一步配置中使用到。

3)编辑topology.json拓朴文件

获取一份安装资源:

git clone https://github.com/gluster/gluster-kubernetes.git

[k8s@kube-server deploy]$ pwd
/home/k8s/gluster-kubernetes/deploy
[k8s@kube-server deploy]$ ls
gk-deploy  heketi.json.template  kube-templates  ocp-templates  topology.json

至少需要3个节点,按下面格式对该文件进行更新:

[k8s@kube-serverserver deploy]$ catcat topology.json
{
  "clusters": [
    {
      "nodes": [
        {
          "nodes": [
        {
          "node": {
            "hostnames": {
              "manage": [
                "kube-node1"
              ],
              "storage": [
                "172.16.10.101"
              ]
            },
            "zone": 1
          },
          "devices": [
            "/dev/sdb"
          ]
        },
        {
          "node": {
            "hostnames": {
              "manage": [
                "kube-node2"
              ],
              "storage": [
                "172.16.10.102"
              ]
            },
            "zone": 1
          },
          "devices": [
            "/dev/sdb"
          ]
        },
        {
          "node": {
            "hostnames": {
              "manage": [
                "kube-node3"
              ],
              "storage": [
                "172.16.10.103"
              ]
            },
            "zone": 1
          },
          "devices": [
            "/dev/sdb"
          ]
        }
      ]
    }
  ]
}

4)在k8s上部署 GlusterFS + heketi

需要先检查下环境:

  • 至少需要3个节点
  • 每个节点上至少提供一个裸块存储设备;
  • 确保以下端口没有被占用:2222,24007, 24008, 49152~49251
  • 在系统中加载以下模块: modprobe dm_snapshot && modprobe dm_mirror && modprobe dm_thin_pool
  • 安装依赖包:yum -y install glusterfs-fuse

执行部署命令:

[k8s@kube-server deploy]$ ./gk-deploy -g

注:-g参数表示要创建出一套glusterfs集群服务。

如果一切顺利,在结束时会看到下面的输出:

....
service "heketi" created
deployment.extensions "heketi" created
Waiting for heketi pod to start ... OK
Flag --show-all has been deprecated, will be removed in an upcoming release

heketi is now running and accessible via https://172.30.86.3:8080 . To run
administrative commands you can install 'heketi-cli' and use it as follows:

  # heketi-cli -s https://172.30.86.3:8080 --user admin --secret '<ADMIN_KEY>' cluster list

You can

You can find it at

You can find it

You can find it at https://github.com/heketi/heketi/releases . Alternatively,
use it from within
use it from within
use it from within the heketi pod:

  # /opt/k8s
use it from within
use it from within the heketi pod:

  # /opt/k8s/bin/kubectl -n defaultt fromhe heketi/opt
use it from within the heketi pod:

  # /opt/k8s/bin/kubectl -n default exec -i heketi-75dcfb7d44-vj9bk -- heketidcfb7d44-vj9bk -- heketi-cli -sdcfb7d44-vj9bk -- heketi-cli -s https://localhost:8080 --user admin --secret '<ADMIN_KEY>' cluster list

For dynamic provisioning, create this:

---
apiVersion: storage.k8s

For dynamic provisioning, create a StorageClass similarisioning, create

For dynamic provisioning, create a provisioning

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage

For dynamic provisioning

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storagedynamicisioning, createimilar to

For

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storageic provisioninging, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.iodynamicrageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: glusterfs dynamicreate a similar

For dynamic provisioning, create a

For

For dynamic provisioning, create aisioning, create a StorageClass similar to this provisioning, create a StorageClass similar to this:

---
apiVersion

For dynamic provisioningovisioning, create a StorageClass similar

For dynamic provisioning, create

For dynamic provisioning, create a

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kindprovisioning create a StorageClassFor dynamic provisioning, create a

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage dynamiconing, create StorageClass

For dynamic provisioningFor dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8sdynamicisioning, create

For dynamic provisioning, create a

For dynamic provisioning, create a StorageClass similar to thisor dynamicing, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind

For dynamic provisioning, create a

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8samic provisioningreate a

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create

For dynamic provisioning, create a

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kinddynamiconing, createageClass similar

For dynamic provisioning, create a StorageClass

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata

For dynamic provisioning, create

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: glusterfs-storage
provisioner: kubernetes

For dynamic provisioning, create a StorageClass

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: glusterfs-storage
provisionerdynamicsioning, createate ato

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: glusterfsamic provisioningreate a

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar

For dynamic provisioning, create a StorageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name

For dynamicic provisioningoning, createrageClass similar to this:

---
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: glusterfs-storage
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "https://172.30.86.3:8080"

Deployment complete!

查看下都创建出了哪些服务实例:

[k8s@kube-server deploy]$ kubectl get pods -o wide
NAME                        READY     STATUS    RESTARTS   AGE       IP              NODE
glusterfs-88469             1/1       Running   0          2h        172.16.10.102   kube-node2
glusterfs-lwm4n             1/1       Running   0          2h        172.16.10.103   kube-node3
glusterfs-pfgwb             1/1       Running   0          2h        172.16.10.101   kube-node1
heketi-75dcfb7d44-vj9bk     1/1       Running   0          1h        172.30.86.3     kube-node2
my-nginx-86555897f9-2kn92   1/1       Running   2          8h        172.30.49.2     kube-node1
my-nginx-86555897f9-d95t9   1/1       Running   4          2d        172.30.48.2     kube-node3
[k8s@kube-server deploy]$ kubectl get svc -o wide
NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE       SELECTOR
heketi                     ClusterIP   10.254.42.129    <none>        8080/TCP   1h        glusterfs=heketi-pod
heketi-storage-endpoints   ClusterIP   10.254.4.122     <none>        1/TCP      1h        <none>
kubernetes                 ClusterIP   10.254.0.1       <none>        443/TCP    7d        <none>
my-nginx                   ClusterIP   10.254.191.237   <none>        80/TCP     5d        run=my-nginx
[k8s@kube-server deploy]$ kubectl get deployment
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
heketi     1         1         1            1           1h
my-nginx   2         2         2            2           5d

[k8s@kube-server deploy]$ kubectl get secret
NAME                                 TYPE                                  DATA      AGE
default-token-p5wjd                  kubernetes.io/service-account-token   3         7d
heketi-config-secret                 Opaque                                3         1h
heketi-service-account-token-mrtsx   kubernetes.io/service-account-token   3         2h
kubelet-api-test-token-gdj7g         kubernetes.io/service-account-token   3         6d
[k8s@kube-server deploy]$

5)使用示例

在可以调用kubectl管理k8s集群的节点上,安装一个heketi客户端:

yum -y install heketi-client

创建个1GB的PV存储卷:

[k8s@kube-server deploy]$ export HEKETI_CLI_SERVER=https://172.30.86.3:8080
[k8s@kube-server deploy]$ heketi-cli volume create --size=1 --persistent-volume --persistent-volume-endpoint=heketi-storage-endpoints | kubectl create -f -
persistentvolume "glusterfs-900fb349" created

回到Dashboard上看看这个刚创建的存储卷:
screenshot
通过heketi服务查看和管理GlusterFS集群: 查看集群列表:

[root@kube-node1 ~]# curl 10.254.42.129:8080/clusters
{"clusters":["ada54ffbeac15a5c9a7521e0c7d2f636"]}

查看集群详情:

[root@kube-node1 ~]# curl 10.254.42.129:8080/clusters/ada54ffbeac15a5c9a7521e0c7d2f636
{"id":"ada54ffbeac15a5c9a7521e0c7d2f636","nodes":["49ac6f56ef21408bcad7c7613cd40bd8","bdf51ae46025cd4fcf134f7be36c32de","fc21262379ec3636e3eadcae15efcc94"],"volumes":["42b01b9b08af23b751b2359fb161c004","900fb349e56af275f47d523d08fdfd6e"],"block":true,"file":true,"blockvolumes":[]}

查看节点详情:

[root@kube-node1 ~]# curl 10.254.42.129:8080/nodes/49ac6f56ef21408bcad7c7613cd40bd8
{"zone":1,"hostnames":{"manage":["kube-node3"],"storage":["172.16.10.103"]},"cluster":"ada54ffbeac15a5c9a7521e0c7d2f636","id":"49ac6f56ef21408bcad7c7613cd40bd8","state":"online","devices":[{"name":"/dev/sdb","storage":{"total":8253440,"free":5087232,"used":3166208},"id":"2f6b2f6c289a2f6bf48fbec59c0c2009","state":"online","bricks":[{"id":"2ea90ebd791a4230e927d233d1c8a7d1","path":"/var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_2ea90ebd791a4230e927d233d1c8a7d1/brick","device":"2f6b2f6c289a2f6bf48fbec59c0c2009","node":"49ac6f56ef21408bcad7c7613cd40bd8","volume":"42b01b9b08af23b751b2359fb161c004","size":2097152},{"id":"4c98684d878ffe7dbfc1008336460eed","path":"/var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_4c98684d878ffe7dbfc1008336460eed/brick","device":"2f6b2f6c289a2f6bf48fbec59c0c2009","node":"49ac6f56ef21408bcad7c7613cd40bd8","volume":"900fb349e56af275f47d523d08fdfd6e","size":1048576}]}]}
  • state 为 online说明节点正常

6)创建一个使用GlusterFS动态存储供应服务的nginx应用

注:在本示例中的用户认证是未启用的,如果要启动用户认证服务,则可以创建一个secret,然后通过StorageClass配置参数传递给Gluster动态存储供应服务。
下面是一个存储类的示例,它将请求2GB的按需存储,用于在我们的HelloWorld应用程序中使用。

gluster-storage-class.yaml
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata:
  name: gluster-heketi  
provisioner: kubernetes.io/glusterfs 
parameters:
  resturl: "https://10.254.42.129:8080"
  restuser: "joe"  
  restuserkey: "My Secret Life"
  • name,StorageClass名称
  • provisioner,存储服务提供者
  • resturl,Heketi REST Url
  • restuser,因为未启用认证,所以这个参数无效
  • restuserkey,同上

创建该存储类:

[k8s@kube-server ~]$ kubectl create -f gluster-storage-class.yaml
storageclass.storage.k8s.io "gluster-heketi" created

[k8s@kube-server ~]$ kubectl get storageclass
NAME             PROVISIONER               AGE
gluster-heketi   kubernetes.io/glusterfs   43s

创建PersistentVolumeClaim(PVC)以请求我们的HelloWorld应用程序的存储:
我们将创建一个要求2GB存储空间的PVC,此时,Kubernetes Dynamic Provisioning Framework和Heketi将自动配置新的GlusterFS卷并生成Kubernetes PersistentVolume(PV)对象。

gluster-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gluster1
  annotations:
    volume.beta.kubernetes.io/storage-class: gluster-heketi
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  • annotations,Kubernetes存储类注释和存储类的名称

    [k8s@kube-server ~]$ kubectl create -f gluster-pvc.yaml
    persistentvolumeclaim "gluster1" created
    

可以看到PVC是绑定到一个动态供给的存储卷上的:

[k8s@kube-server ~]$ kubectl get pvc
NAME       STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
gluster1   Bound     pvc-53e824cf-7eb7-11e8-bf5c-080027395360   2Gi        RWO            gluster-heketi   53s

[k8s@kube-server ~]$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM              STORAGECLASS     REASON    AGE
glusterfs-900fb349                         1Gi        RWX            Retain           Available                                                 2h
pvc-53e824cf-7eb7-11e8-bf5c-080027395360   2Gi        RWO            Delete           Bound       default/gluster1   gluster-heketi             1m

创建一个使用该PVC的nginx实例:

nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod1
  labels:
    name: nginx-pod1
spec:
  containers:
  - name: nginx-pod1
    image: nginx:1.7.9
    ports:
    - name: web
      containerPort: 80
    volumeMounts:
    - name: gluster-vol1
      mountPath: /usr/share/nginx/html
  volumes:
  - name: gluster-vol1
    persistentVolumeClaim:
      claimName: gluster1

claimName,要使用的PVC的名称

[k8s@kube-server ~]$ kubectl create -f nginx-pod.yaml
pod "nginx-pod1" created

[k8s@kube-server ~]$ kubectl get pods -o wide|grep nginx-pod
nginx-pod1                  1/1       Running   0          33s       172.30.86.3     kube-node2

登录到该Pod中并创建一个网页文件:

[k8s@kube-server ~]$ kubectl exec -it nginx-pod1  /bin/bash
root@nginx-pod1:/# df -h
Filesystem                                          Size  Used Avail Use% Mounted on
rootfs                                               41G  7.1G   34G  18% /
overlay                                              41G  7.1G   34G  18% /
tmpfs                                                64M     0   64M   0% /dev
tmpfs                                               496M     0  496M   0% /sys/fs/cgroup
/dev/mapper/centos_bogon-root                        41G  7.1G   34G  18% /dev/termination-log
shm                                                  64M     0   64M   0% /dev/shm
/dev/mapper/centos_bogon-root                        41G  7.1G   34G  18% /etc/resolv.conf
/dev/mapper/centos_bogon-root                        41G  7.1G   34G  18% /etc/hostname
/dev/mapper/centos_bogon-root                        41G  7.1G   34G  18% /etc/hosts
/dev/mapper/centos_bogon-root                        41G  7.1G   34G  18% /var/cache/nginx
172.16.10.101:vol_1b6e32efd9b6f07e2b056bed2ce6cc73  2.0G   53M  2.0G   3% /usr/share/nginx/html
tmpfs                                               496M   12K  496M   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                                64M     0   64M   0% /proc/kcore
tmpfs                                                64M     0   64M   0% /proc/keys
tmpfs                                                64M     0   64M   0% /proc/timer_list
tmpfs                                                64M     0   64M   0% /proc/timer_stats
tmpfs                                                64M     0   64M   0% /proc/sched_debug
tmpfs                                               496M     0  496M   0% /proc/scsi
tmpfs                                               496M     0  496M   0% /sys/firmware

root@nginx-pod1:/# cd /usr/share/nginx/html
dex.htmlnx-pod1:/usr/share/nginx/html# echo 'Hello World from GlusterFS!!!' > in
root@nginx-pod1:/usr/share/nginx/html# ls
index.html
root@nginx-pod1:/usr/share/nginx/html# cat index.html
Hello World from GlusterFS!!!
root@nginx-pod1:/usr/share/nginx/html# exit
exit

访问一下我们的网页:

[k8s@kube-server ~]$ curl https://172.30.86.3
Hello World from GlusterFS!!!

再检查一下gluster pod,找到我们刚写入的index.html文件,登录任一个gluster pod:

screenshot

[root@kube-node1 brick]# pwd
/var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_6e016b1ed8e16b6a28839f1670a56d00/brick
[root@kube-node1 brick]# ls
index.html
[root@kube-node1 brick]# cat index.html
Hello World from GlusterFS!!!

7)删除 glusterfs 集群配置

curl -X DELETE 10.254.42.129:8080/devices/46b2685901f56d6fe0cc85bf3d37bf75 # 使用的是device id,删除device
curl -X DELETE 10.254.42.129:8080/nodes/8bd8497a8dcda0708508228f4ae8c2ae #使用的是node id, 删除node

每个节点都要删除掉device才能再删除node

cluster 列表下的所有节点都删除后 才能删除cluster:
curl -X DELETE 10.254.42.129:8080/clusters/ada54ffbeac15a5c9a7521e0c7d2f636

Heketi服务

GlusterFS 是个开源的分布式文件系统,而 Heketi 在其上提供了 REST 形式的 API,二者协同为 Kubernetes 提供了存储卷的自动供给能力。Heketi还支持GlusterFS多集群管理。当一个集群中同时有多种规格、性能和容量特点的存储资源时,Heketi可以通过接入多个存储集群,在每个集群中又按资源特性划分出多个Zone来进行管理。

Heketi服务

1)在k8s中部署Heketi服务前需要为其创建一个ServiceAccount账号

我们继续看一下前面例子中使用到的一些配置资源:

[k8s@kube-server deploy]$ pwd
/home/k8s/gluster-kubernetes/deploy
[k8s@kube-server deploy]$ cat ./kube-templates/heketi-service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: heketi-service-account
  labels:
    glusterfs: heketi-sa
    heketi: sa

[k8s@kube-server deploy]$ kubectl get sa | grep heketi
heketi-service-account   1         4h

2)通过Deployment部署Heketi服务

[k8s@kube-server deploy]$ kubectl get deployment
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
heketi     1         1         1            1           3h

[k8s@kube-server kube-templates]$ pwd
/home/k8s/gluster-kubernetes/deploy/kube-templates
[k8s@kube-server kube-templates]$ cat heketi-deployment.yaml
---
kind: Service
apiVersion: v1
metadata:
  name: heketi
  labels:
    glusterfs: heketi-service
    heketi: service
  annotations:
    description: Exposes Heketi Service
spec:
  selector:
    glusterfs: heketi-pod
  ports:
  - name: heketi
    port: 8080
    targetPort: 8080
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  name: heketi
  labels:
    glusterfs: heketi-deployment
    heketi: deployment
  annotations:
    description: Defines how to deploy Heketi
spec:
  replicas: 1
  template:
    metadata:
      name: heketi
      labels:
        glusterfs: heketi-pod
        heketi: pod
    spec:
      serviceAccountName: heketi-service-account
      containers:
      - image: heketi/heketi:dev
        imagePullPolicy: IfNotPresent
        name: heketi
        env:
        - name: HEKETI_USER_KEY
          value: ${HEKETI_USER_KEY}
        - name: HEKETI_ADMIN_KEY
          value: ${HEKETI_ADMIN_KEY}
        - name: HEKETI_EXECUTOR
          value: ${HEKETI_EXECUTOR}
        - name: HEKETI_FSTAB
          value: ${HEKETI_FSTAB}
        - name: HEKETI_SNAPSHOT_LIMIT
          value: '14'
        - name: HEKETI_KUBE_GLUSTER_DAEMONSET
          value: "y"
        - name: HEKETI_IGNORE_STALE_OPERATIONS
          value: "true"
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: db
          mountPath: "/var/lib/heketi"
        - name: config
          mountPath: /etc/heketi
        readinessProbe:
          timeoutSeconds: 3
          initialDelaySeconds: 3
          httpGet:
            path: "/hello"
            port: 8080
        livenessProbe:
          timeoutSeconds: 3
          initialDelaySeconds: 30
          httpGet:
            path: "/hello"
            port: 8080
      volumes:
      - name: db
        glusterfs:
          endpoints: heketi-storage-endpoints
          path: heketidbstorage
      - name: config
        secret:
          secretName: heketi-config-secret

定义了两个volumes,其中"db"是使用的glusterfs提供的存储卷,而"config"的volume则是使用的"secret"

查看一下被当作volume使用的secret的内容:

[k8s@kube-server kube-templates]$ kubectl describe secret heketi-config-secret
Name:         heketi-config-secret
Namespace:    default
Labels:       glusterfs=heketi-config-secret
              heketi=config-secret
Annotations:  <none>

Type:  Opaque

Data
====
heketi.json:    909 bytes
private_key:    0 bytes
topology.json:  1029 bytes

可以看到这个secret中是包含了三个配置文件

这个secret是使用脚本创建的:

[k8s@kube-server deploy]$ pwd
/home/k8s/gluster-kubernetes/deploy
[k8s@kube-server deploy]$ ls
gk-deploy  heketi.json.template  kube-templates  ocp-templates  topology.json
[k8s@kube-server deploy]$ grep heketi-config-secret gk-deploy
  eval_output "${CLI} create secret generic heketi-config-secret --from-file=private_key=${SSH_KEYFILE} --from-file=./heketi.json --from-file=topology.json=${TOPOLOGY}"
  eval_output "${CLI} label --overwrite secret heketi-config-secret glusterfs=heketi-config-secret heketi=config-secret"
[k8s@kube-server deploy]$

3)为Heketi设置GlusterFS集群

使用一个topology.json的配置文件来完成各个GlusterFS节点和设备的定义。
Heketi要求一个GlusterFS集群中至少有3个节点。在topology.json配置文件的hostnames字段中的manage中填写主机名,在storage上填写IP地址,devices要求是未创建文件系统的裸设备(支持多块磁盘)。这样Heketi就可以自动完成PV、VG和LV的创建。

topology.json文件的内容在前面已经提供了,不再重复。

当使用gluster-kubernetes项目提供的脚本工具和模板创建glusterfs和heketi服务时,不需要额外的手动干预。但如果是手动创建这些服务,则可以按下面的方法使用Heketi加载topology配置,完成GlusterFS服务集群的创建。
可以登录进入Hekiti容器执行以下命令:

# export HEKETI_CLI_SERVER=https://localhost:8080
# heketi-cli topology load --json=topology.json

这样Heketi就完成了GlusterFS集群的创建,同时在GlusterFS集群的各个节点的/dev/sdb盘上成功创建了PV和VG。
此时,查看Heketi的topology信息,可以看到很详细的Node和Device信息:

[k8s@kube-server deploy]$ heketi-cli topology info

Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636

    Volumes:

    Name: vol_1b6e32efd9b6f07e2b056bed2ce6cc73
    Size: 2
    Id: 1b6e32efd9b6f07e2b056bed2ce6cc73
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Mount: 172.16.10.103:vol_1b6e32efd9b6f07e2b056bed2ce6cc73
    Mount Options: backup-volfile-servers=172.16.10.102,172.16.10.101
    Durability Type: replicate
    Replica: 3
    Snapshot: Disabled

        Bricks:
            Id: 6e016b1ed8e16b6a28839f1670a56d00
            Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_6e016b1ed8e16b6a28839f1670a56d00/brick
            Size (GiB): 2
            Node: fc21262379ec3636e3eadcae15efcc94
            Device: f8776d0d92102fc3e272f2ec899e5f18

            Id: c7acfcecaf85aada98b0c0208798440f
            Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_c7acfcecaf85aada98b0c0208798440f/brick
            Size (GiB): 2
            Node: 49ac6f56ef21408bcad7c7613cd40bd8
            Device: 2f6b2f6c289a2f6bf48fbec59c0c2009

            Id: e2acc8268f17f05e940ebe679dacfa3a
            Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_e2acc8268f17f05e940ebe679dacfa3a/brick
            Size (GiB): 2
            Node: bdf51ae46025cd4fcf134f7be36c32de
            Device: e100120226d5d9567ed0f92b9810236c


    Name: heketidbstorage
    Size: 2
    Id: 42b01b9b08af23b751b2359fb161c004
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Mount: 172.16.10.103:heketidbstorage
    Mount Options: backup-volfile-servers=172.16.10.102,172.16.10.101
    Durability Type: replicate
    Replica: 3
    Snapshot: Disabled

        Bricks:
            Id: 2ea90ebd791a4230e927d233d1c8a7d1
            Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_2ea90ebd791a4230e927d233d1c8a7d1/brick
            Size (GiB): 2
            Node: 49ac6f56ef21408bcad7c7613cd40bd8
            Device: 2f6b2f6c289a2f6bf48fbec59c0c2009

            Id: 9dc7238db3240146f12189dd28320227
            Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_9dc7238db3240146f12189dd28320227/brick
            Size (GiB): 2
            Node: fc21262379ec3636e3eadcae15efcc94
            Device: f8776d0d92102fc3e272f2ec899e5f18

            Id: cb68cbf4e992abffc86ab3b5db58ef56
            Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_cb68cbf4e992abffc86ab3b5db58ef56/brick
            Size (GiB): 2
            Node: bdf51ae46025cd4fcf134f7be36c32de
            Device: e100120226d5d9567ed0f92b9810236c


    Name: vol_900fb349e56af275f47d523d08fdfd6e
    Size: 1
    Id: 900fb349e56af275f47d523d08fdfd6e
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Mount: 172.16.10.103:vol_900fb349e56af275f47d523d08fdfd6e
    Mount Options: backup-volfile-servers=172.16.10.102,172.16.10.101
    Durability Type: replicate
    Replica: 3
    Snapshot: Disabled

        Bricks:
            Id: 4c98684d878ffe7dbfc1008336460eed
            Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_4c98684d878ffe7dbfc1008336460eed/brick
            Size (GiB): 1
            Node: 49ac6f56ef21408bcad7c7613cd40bd8
            Device: 2f6b2f6c289a2f6bf48fbec59c0c2009

            Id: 7c82d03c88d73bb18d407a791a1053c2
            Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_7c82d03c88d73bb18d407a791a1053c2/brick
            Size (GiB): 1
            Node: bdf51ae46025cd4fcf134f7be36c32de
            Device: e100120226d5d9567ed0f92b9810236c

            Id: 822266f7ad3cf62b1e45686265cf7268
            Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_822266f7ad3cf62b1e45686265cf7268/brick
            Size (GiB): 1
            Node: fc21262379ec3636e3eadcae15efcc94
            Device: f8776d0d92102fc3e272f2ec899e5f18


    Nodes:

    Node Id: 49ac6f56ef21408bcad7c7613cd40bd8
    State: online
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Zone: 1
    Management Hostname: kube-node3
    Storage Hostname: 172.16.10.103
    Devices:
        Id:2f6b2f6c289a2f6bf48fbec59c0c2009   Name:/dev/sdb            State:online    Size (GiB):7       Used (GiB):5       Free (GiB):2       
            Bricks:
                Id:2ea90ebd791a4230e927d233d1c8a7d1   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_2ea90ebd791a4230e927d233d1c8a7d1/brick
                Id:4c98684d878ffe7dbfc1008336460eed   Size (GiB):1       Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_4c98684d878ffe7dbfc1008336460eed/brick
                Id:c7acfcecaf85aada98b0c0208798440f   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_2f6b2f6c289a2f6bf48fbec59c0c2009/brick_c7acfcecaf85aada98b0c0208798440f/brick

    Node Id: bdf51ae46025cd4fcf134f7be36c32de
    State: online
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Zone: 1
    Management Hostname: kube-node2
    Storage Hostname: 172.16.10.102
    Devices:
        Id:e100120226d5d9567ed0f92b9810236c   Name:/dev/sdb            State:online    Size (GiB):7       Used (GiB):5       Free (GiB):2       
            Bricks:
                Id:7c82d03c88d73bb18d407a791a1053c2   Size (GiB):1       Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_7c82d03c88d73bb18d407a791a1053c2/brick
                Id:cb68cbf4e992abffc86ab3b5db58ef56   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_cb68cbf4e992abffc86ab3b5db58ef56/brick
                Id:e2acc8268f17f05e940ebe679dacfa3a   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_e100120226d5d9567ed0f92b9810236c/brick_e2acc8268f17f05e940ebe679dacfa3a/brick

    Node Id: fc21262379ec3636e3eadcae15efcc94
    State: online
    Cluster Id: ada54ffbeac15a5c9a7521e0c7d2f636
    Zone: 1
    Management Hostname: kube-node1
    Storage Hostname: 172.16.10.101
    Devices:
        Id:f8776d0d92102fc3e272f2ec899e5f18   Name:/dev/sdb            State:online    Size (GiB):7       Used (GiB):5       Free (GiB):2       
            Bricks:
                Id:6e016b1ed8e16b6a28839f1670a56d00   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_6e016b1ed8e16b6a28839f1670a56d00/brick
                Id:822266f7ad3cf62b1e45686265cf7268   Size (GiB):1       Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_822266f7ad3cf62b1e45686265cf7268/brick
                Id:9dc7238db3240146f12189dd28320227   Size (GiB):2       Path: /var/lib/heketi/mounts/vg_f8776d0d92102fc3e272f2ec899e5f18/brick_9dc7238db3240146f12189dd28320227/brick

总结:使用Kubernetes的动态存储供应模式,配置StorageClass和Heketi共同搭建基于GlusterFS的共享存储,相对于静态模式至少有两大优势。

  1. 一个是管理员无须预先创建大量的PV作为存储资源
  2. 用户在申请PVC时也无法保证容量与预置PV的容量能够一致。因此,从k8s v1.6开始,建议用户优先考虑使用StorageClass的动态存储供应模式进行存储管理。
更新于 2022-01-18

查看kubernetes更多相关的文章或提一个关于kubernetes的问题,也可以与我们一起分享文章