Kubernetes12-共享存储原理

1、共享存储机制概述

  • Kubernetes对于有状态的应用或者对数据需要持久化的应用,不仅需要将容器内的目录挂载到宿主机的目录或者emptyDir临时存储卷,而且需要更加可靠的存储来保存应用产生的重要数据,以便容器应用在重建之后仍然可以使用之前的数据。
  • 存储资源和计算资源(CPU/内存)的管理方式完全不同。
    • 为了能够屏蔽底层存储实现的细节,让用户方便使用,同时让管理员方便管理,Kubernetes从1.0版本就引入PersistentVolume(PV)PersistentVolumeClaim(PVC)两个资源对象来实现对存储的管理子系统。
  • PV是什么:
    • PV是对底层网络共享存储的抽象,将共享存储定义为一种“资源”,比如Node也是一种容器应用可以“消费”的资源。
    • PV由管理员创建和配置,它与共享存储的具体实现直接相关,例如GlusterFS、iSCSI、RBD或GCE或AWS公有云提供的共享存储,通过插件式的机制完成与共享存储的对接,以供应用访问和使用。
  • PVC是什么:
    • PVC则是用户对存储资源的一个“申请”。就像Pod“消费”Node的资源一样,PVC能够“消费”PV资源。
    • PVC可以申请特定的存储空间和访问模式。
  • StorageClass资源对象:
    • 使用PVC“申请”到一定的存储空间仍然不能满足应用对存储设备的各种需求。通常应用程序都会对存储设备的特性和性能有不同的要求,包括读写速度、并发性能、数据冗余等更高的要求,Kubernetes从1.4版本开始引入了一个新的资源对象StorageClass,用于标记存储资源的特性和性能。到1.6版本时,StorageClass和动态资源供应的机制得到了完善,实现了存储卷的按需创建,在共享存储的自动化管理进程中实现了重要的一步。
    • 通过StorageClass的定义,管理员可以将存储资源定义为某种类别(Class),正如存储设备对于自身的配置描述(Profile),例如“快速存储”、“慢速存储”、“有数据冗余”、“无数据冗余”等。用户根据StorageClass的描述就能够直观地得知各种存储资源的特性,就可以根据应用对存储资源的需求去申请存储资源了。
  • CSI(Container StorageInterface,容器存储接口):
    • Kubernetes从1.9版本开始引入容器存储接口机制,目标是在Kubernetes和外部存储系统之间建立一套标准的存储管理接口,通过该接口为容器提供存储服务,类似于CRI(容器运行时接口)和CNI(容器网络接口)。

2、PV详解

  • PV作为存储资源,主要包括存储能力、访问模式、存储类型、回收策略、后端存储类型等关键信息的设置。

示例:

  • 定义一个PV,以及PV具有的属性。
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:                 #存储容量
    storage: 5Gi              #5GiB存储空间
  volumeMode: Filesystem    #存储卷类型,可用值有Filesystem(文件系统)和Block(块设备),默认值为Filesystem。
  accessModes:              #访问模式,可用值有ReadWriteOnce、ReadOnlyMany、ReadWriteMany或ReadWriteOncePod
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain    #回收策略,可用值有Retain(保留)、Delete(删除)、Recycle(回收)
  storageClassName: slow    #StorageClass的名称(要求在系统中已存在名为slow的StorageClass)。空值表示该卷不属于任何StorageClass
  nfs:                      #后端存储类型为nfs(设置了NFS Server的IP地址和路径)
    path: /tmp
    server: 172.17.0.2
  mountOptions:             #挂载参数
    - hard
    - nfsvers=4.1
  nodeAffinity:             #节点亲和性
    required:                 #节点硬亲和性
      nodeSelectorTerms:      #节点选择器
      - mathExpressions:        #使用节点标签列出的节点选择器要求列表。
        - key: kubernetes.io/hostname
          operator: In            #可用值有In、NotIn、Exists、DoesNotExist、Gt或Lt
          values:                 #如果操作符是In或NotIn,值数组必须非空。如果操作符是Exists或DoesNotExist,值数组必须为空。如果操作符是Gt或Lt,值数组必须只有一个元素,该元素将被解释为整数
          - my-node
      #- matchFields:           #按节点字段列出的节点选择器要求列表
  • Kubernetes支持的PV类型有:
    • AWSElasticBlockStore:AWS公有云提供的ElasticBlockStore。
    • AzureFile:Azure公有云提供的File。
    • AzureDisk:Azure公有云提供的Disk。
    • CephFS:一种开源共享存储系统。
    • FC(Fibre Channel):光纤存储设备。
    • FlexVolume:一种插件式的存储机制。
    • Flocker:一种开源共享存储系统。
    • GCEPersistentDisk:GCE公有云提供的PersistentDisk。
    • Glusterfs:一种开源共享存储系统。
    • HostPath:宿主机目录,仅用于单机测试。
    • iSCSI:iSCSI存储设备。
    • Local:本地存储设备,从Kubernetes 1.7版本引入,到1.14版本时更新为稳定版,目前可以通过指定块(Block)设备提供Local PV,或通过社区开发的sig-storage-local-static-provisioner插件(https://github.com/kubernetes-sigs/sigstorage-local-static-provisioner)来管理Local PV的生命周期。
    • NFS:网络文件系统。
    • Portworx Volumes:Portworx提供的存储服务。
    • Quobyte Volumes:Quobyte提供的存储服务。
    • RBD(Ceph Block Device):Ceph块存储。
    • ScaleIO Volumes:DellEMC的存储设备。
    • StorageOS:StorageOS提供的存储服务。
    • VsphereVolume:VMWare提供的存储系统。
  • 每种存储类型都有各自的特点,在使用时需要根据它们各自的参数进行设置。

2.1、PV的关键配置参数

2.1.1、存储能力(Capacity)

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

2.1.2、存储卷类型(Volume Mode)

  • Kubernetes从1.13版本开始引入存储卷类型的设置(volumeMode=xxx)。
    • 可选项包括Filesystem(文件系统)和Block(块设备),默认值为Filesystem
  • 目前有以下PV类型支持块设备类型:
    • AWSElasticBlockStore
    • AzureDisk
    • FC
    • GCEPersistentDisk
    • iSCSI
    • Local volume
    • RBD(Ceph Block Device)
    • VsphereVolume(alpha)

示例:

  • 使用块设备的PV定义。
apiVersion: v1
kind PersistentVolume
metadata:
  name: block-pv
spec:
  capacity:
    storage: 10Gi
  accessNodes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  volumeMode: Block    #使用块设备
  fc:                  #使用fc
    targetWWNs: ["50060e801049cfd1"]
    lun: 0
    readOnly: false

2.1.3、访问模式(Access Modes)

  • 对PV的访问模式,用于描述用户的应用对存储资源的访问权限。
  • 访问模式有四种:
    • ReadWriteOnce(RWO):读写权限,并且只能被一个Node挂载,但允许多个pod在同一节点上读写该卷。。
    • ReadOnlyMany(ROX):只读权限,允许被多个Node挂载。
    • ReadWriteMany(RWX):读写权限,允许被多个Node挂载。
    • ReadWriteOncePod:读写权限,只能被一个pod挂载。只支持CSI卷和Kubernetes版本1.22+。
  • 某些PV可能支持多种访问模式,但PV在挂载时只能使用一种访问模式,多种访问模式不能同时生效。
  • 不同的存储支持访问模式如表所示:

2.1.4、StorageClass的名称

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

2.1.5、回收策略(Reclaim Policy)

  • 通过PV定义中的persistentVolumeReclaimPolicy字段进行设置,可选项如下。
    • Retain(保留):保留数据,需要手工处理。
    • Delete(删除):与PV相连的后端存储完成Volume的删除操作(如AWSEBS、GCE PD、Azure Disk、OpenStack Cinder等设备的内部Volume清理)。
    • Recycle(回收):简单清除文件的操作(例如执行rm -rf /thevolume/*命令)。
  • 目前,只有NFS和HostPath两种类型的存储支持Recycle策略;AWSEBS、GCE PD、Azure Disk和Cinder volumes支持Delete策略。

2.1.6、挂载参数(Mount Options)

  • 在将PV挂载到一个Node上时,根据后端存储的特点,可能需要设置额外的挂载参数,可以根据PV定义中的mountOptions字段进行设置。
  • 如果挂载选项无效,则挂载失败
  • 以下卷类型支持挂载参数:
    • awsElasticBlockStore
    • azureDisk
    • azureFile
    • cephfs
    • cinder (deprecated in v1.18)
    • gcePersistentDisk
    • glusterfs
    • iscsi
    • nfs
    • rbd
    • vsphereVolume

示例:

  • 对一个类型为gcePersistentDisk的PV设置挂载参数。
apiVersion: v1
kind: PersistentVolume
metadata:
  name: gce-disk-1
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  mountOptions:         #挂载参数
  - hard
  - nolock
  - nfsvers=3
  gcePersistentDisk:    #!
    fsType: ext4
    pdName: gce-disk-1

2.1.7、节点亲和性(Node Affinity)

  • PV可以设置节点亲和性(nodeAffinity字段)来限制只能通过某些Node访问Volume。使用这些Volume的Pod将被调度到满足条件的Node上。
  • 公有云提供的存储卷(如AWS EBS、GCE PD、Azure Disk等)都由公有云自动完成节点亲和性设置,无须用户手工设置。

示例:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-local-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:    #节点亲和性
    required:
      nodeSelectorTerms:
      - mathExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - my-node

2.2、PV生命周期的各个阶段

  • 一个PV在生命周期中可能处于以下4个阶段(Phaes)之一。
    • Available:可用状态,还未与某个PVC绑定。
    • Bound:已与某个PVC绑定。
    • Released:绑定的PVC已经删除,资源已释放,但没有被集群回收。
    • Failed:自动资源回收失败。
  • 定义了PV以后如何使用呢?这时就需要用到PVC了。

3、PVC详解

  • PVC作为用户对存储资源的需求申请,主要包括存储空间请求、访问模式、PV选择条件和存储类别等信息的设置。

示例:

  • 定义一个PVC,以及PVC具有的属性。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  resources:                #资源请求
    requests:
      storage: 8Gi            #申请8GiB存储空间
  accessModes:              #访问模式,可用值有ReadWriteOnce、ReadOnlyMany、ReadWriteMany或ReadWriteOncePod
  - ReadWriteOnce
  volumeMode: Filesystem    #存储卷类型,可用值有Filesystem(文件系统)和Block(块设备),默认值为Filesystem。
  storageClassName: gold    #StorageClass的名称,默认值是gold(要求在系统中已存在名为gold的StorageClass)
  selector:                 #PV选择条件为包含标签“release=stable”并且包含条件为“environment In [dev]”的标签
    matchLabels:
      release: stable
    matchExpressions:
    - {key: enviroment, operator: In, values: [dev]}

3.1、PVC的关键配置参数

  • 资源请求(Resources):描述对存储资源的请求,目前仅支持request.storage的设置,即存储空间大小。
  • 访问模式(Access Modes):PVC也可以设置访问模式,用于描述用户应用对存储资源的访问权限。访问模式的设置与PV的设置相同。
  • 存储卷类型(Volume Modes):PVC也可以设置存储卷模式,用于描述希望使用的PV存储卷模式,包括文件系统和块设备。
  • PV选择条件(Selector):通过对Label Selector的设置,可使PVC对于系统中已存在的各种PV进行筛选。
    • 系统将根据标签选出合适的PV与该PVC进行绑定。
    • 选择条件可以使用matchLabels和matchExpressions进行设置。如果两个字段都设置了,则Selector的逻辑将是两组条件同时满足才能完成匹配。
  • StorageClass的名称(storageClassName):PVC 在定义时可以设定需要的后端存储的类别(通过storageClassName字段指定),以减少对后端存储特性的详细信息的依赖。
    • 只有设置了该storageClassName的PV才能被系统选出,并与该PVC进行绑定
    • PVC也可以不设置storageClassName需求。
      • 如果storageClassName字段的值被设置为空(storageClassName=""),则表示该PVC不要求特定的storageClassName,系统将只选择未设定storageClassName的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/isdefault-class= true”。
          • 如果管理员将多个StorageClass都定义为default,则由于不唯一,系统将无法为PVC创建相应的PV。

3.2、使用PVC的注意事项

  • Namespace对PVC和PV的影响:
    • PV是集群级别的资源,不属于名称空间
    • PVC是名称空间级别的资源,属于具体的名称空间
    • Pod在引用PVC时受Namespace的限制,只有相同Namespace中的PVC才能挂载到Pod内。
  • 当Selector和storageClassName都进行了设置时,系统将选择两个条件同时满足的PV与之匹配。
  • 如果资源供应使用的是动态模式,即管理员没有预先定义PV,仅通过StorageClass交给系统自动完成PV的动态创建,那么PVC再设定Selector时,系统将无法为其供应任何存储资源。
  • 在启用动态供应模式的情况下,一旦用户删除了PVC,与之绑定的PV也将根据其默认的回收策略“Delete”被删除。如果需要保留PV(用户数据),则在动态绑定成功后,用户需要将系统自动生成PV的回收策略从“Delete”改成“Retain”。

4、PV和PVC的生命周期

  • 可以将PV看作可用的存储资源,PVC则是对存储资源的需求,PV和PVC的相互关系遵循如图8.1所示的生命周期。

4.1、资源供应

  • Kubernetes支持两种资源的供应模式:静态模式(Static)和动态模式(Dynamic)。
  • 静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置。
  • 动态模式
    • 集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种类型。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及与PVC的绑定
    • PVC可以声明storageClassName为""(即空值),说明该PVC禁止使用动态模式。
  • 图8.2描述了在静态资源供应模式下,通过PV和PVC完成绑定,并供Pod使用的存储管理机制。

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

4.2、资源绑定

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

4.3、资源使用

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

4.4、资源释放

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

4.5、资源回收

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

5、StorageClass详解

  • StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节。
    • 一方面减少了用户对于存储资源细节的关注。
    • 另一方面减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现了动态的资源供应。
  • 基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储配置模式。
  • StorageClass的定义主要包括名称、后端存储的提供者(provisioner)和后端存储的相关参数配置。StorageClass一旦被创建出来,则将无法修改。如需更改,则只能删除原StorageClass的定义重建。
  • 下例定义了一个名为standard的StorageClass,提供者为aws-ebs,其参数设置了一个type,值为gp2:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: myclaim
provisioner:  kubernetes.io/aws-ebs    #存储资源的提供者,也可以看作后端存储驱动
parameters:                            #后端存储资源提供者的参数
  type: gp2

5.1、StorageClass的关键配置参数

1、提供者(Provisioner)

  • 描述存储资源的提供者,也可以看作后端存储驱动。目前Kubernetes支持的Provisioner都以“kubernetes.io/”为开头,用户也可以使用自定义的后端存储提供者。

2、参数(Parameters)

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

(1)AWS EBS存储卷

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner:  kubernetes.io/aws-ebs
parameters:
  type: iol
  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。

(2)GCE PD存储卷

apiVersion: storage.k8s.io/v1
kind: StorageClass
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名称。

(3)GlusterFS存储卷

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner:  kubernetes.io/glusterfs
parameters:
  resturl: "http://127.0.0.1:8081"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "default"
  secretName: "heketi-secret"
  clusterid: "630372ccdc720a92c681fb928f27b53f"
  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份,冗余两份)、“none”(Distribute类型)。

(4)OpenStack Cinder存储卷

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gold
provisioner:  kubernetes.io/cinder
parameters:
  type: fast
  availability: nova
  • 参数说明如下:
    • type:Cinder的VolumeType,默认值为空。
    • availability:Availability Zone,默认值为空。

5.2、设置默认的StorageClass

  • 要在系统中设置一个默认的StorageClass。
  • (1)首先需要启用名为DefaultStorageClass的admission controller,即在kube-apiserver的命令行参数--admission-control中增加:
--admission-control=...,DefaultStorageClass
  • (2)然后,在StorageClass的定义中设置一个annotation:
apiVersion: storage.k8s.io/v1
kind: StorageClass
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             PROVISIONER            RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
gold (default)   kubernetes.io/gce-pd   Delete          Immediate           false                  20s

6、实现存储卷

  • 在10.1.1.13上安装nfs,并提供三个共享目录。
]# yum install nfs-utils rpcbind

]# vim /etc/exports
/data1/ 10.1.0.0/16(rw)
/data2/ 10.1.0.0/16(rw)
/data3/ 10.1.0.0/16(rw)

]# mkdir /data{1,2,3}
]# chown nfsnobody.nfsnobody -R /data{1,2,3}

]# systemctl start rpcbind.service
]# systemctl start nfs.service

6.1、静态存储卷

1、创建PV

  • 创建三个PV的yaml文件(pv-data.yaml)
    • 注意,PV是集群级别的资源,因此不需要名称空间。
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data1
  labels:
    name: pv-data1
spec:
  nfs:
    path: /data1
    server: 10.1.1.13
  accessModes: ["ReadWriteOnce", "ReadWriteMany"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data2
  labels:
    name: pv-data2
spec:
  nfs:
    path: /data2
    server: 10.1.1.13
  accessModes: ["ReadOnlyMany"]
  capacity:
    storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-data3
  labels:
    name: pv-data3
spec:
  nfs:
    path: /data3
    server: 10.1.1.13
  accessModes: ["ReadWriteMany"]
  capacity:
    storage: 10Gi
  • 创建,并查看PV
//创建PV
]# kubectl apply -f pv-data.yaml 

//查看PV
]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-data1   1Gi        RWO,RWX        Retain           Available                                   8s
pv-data2   5Gi        ROX            Retain           Available                                   8s
pv-data3   10Gi       RWX            Retain           Available                                   8s

2、创建PVC

  • 创建名称空间

]# kubectl create namespace test
  • 创建PVC的yaml文件(pvc1.yaml)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
  namespace: test
  labels:
    name: pvc1
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 3Gi
  storageClassName: ""
  • 创建PVC,并查看PV和PVC
//创建PVC
]# kubectl apply -f pvc1.yaml 

//查看PVC
]# kubectl get pvc -A
NAMESPACE   NAME   STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test        pvc1   Bound    pv-data3   10Gi       RWX                           8s

//查看PV
]# kubectl get pv
NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM       STORAGECLASS   REASON   AGE
pv-data1   1Gi        RWO,RWX        Retain           Available                                       2m47s
pv-data2   5Gi        ROX            Retain           Available                                       2m47s
pv-data3   10Gi       RWX            Retain           Bound       test/pvc1                           2m47s

3、在pod中使用PVC

  • 创建pod的yaml文件(pod-pvc.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-deployment
  namespace: test
spec:
  selector:
    matchLabels:
      app: busybox-pod
  replicas: 1
  template:
    metadata:
      labels:
        app: busybox-pod
    spec:
      containers:
      - name: busybox-container
        image: busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh", "-c", "while true; do echo $(date) >> /data/log/time.log; sleep 3; done"]
        volumeMounts:
        - name: log
          mountPath: /data/log/
      volumes:
      - name: log
        persistentVolumeClaim:    #!
          claimName: pvc1         #PVC的名称

4、查看nfs上的time.log文件

]# tailf /data3/time.log 
Tue Oct 4 21:03:14 UTC 2022
Tue Oct 4 21:03:17 UTC 2022
Tue Oct 4 21:17:11 UTC 2022
...

6.2、动态存储卷

  • 可以动态的创建PV,而不是事先提前创建好PV。
  • 使用nfs-subdir-external-provisioner插件实现StorageClass(动态创建PV),它通过现有的NFS服务器作为后端存储服务器。
  • PV命名规则如下:${namespace}-${pvcName}-${pvName}
  • nfs-subdir-external-provisioner插件是对nfs-client-provisioner的扩展,nfs-client-provisioner已经不提供更新,且nfs-client-provisioner的Github仓库已经迁移到 nfs-subdir-external-provisione的仓库。GitHub地址是:https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner。

6.2.1、创建ServiceAccount

  • 创建名称空间
]# kubectl create namespace ns-storageclass
  • 创建RBAC资源的yaml文件

    • 在github上的位置:nfs-subdir-external-provisioner/deploy/rbac.yaml
    • 注意:请提前修改里面的Namespace名称为你要想部署Namespace空间。
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: ns-storageclass
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: ns-storageclass
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: ns-storageclass
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: ns-storageclass
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: ns-storageclass
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  • 创建RBAC
]# kubectl apply -f rbac.yaml

6.2.2、创建nfs-subdir-external-provisioner

  • 创建nfs-subdir-external-provisioner的yaml文件
    • 在github上的位置:nfs-subdir-external-provisioner/deploy/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: ns-storageclass
spec:
  replicas: 1
  strategy: 
    type: Recreate                        #设置升级策略为删除再创建(默认为滚动更新)
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          #image: gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
          image: dyrnq/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME     #Provisioner的名称,下面的StorageClass的provisioner要和这个保持一致
              value: nfs-client
            - name: NFS_SERVER           #NFS服务器地址
              value: 10.1.1.13
            - name: NFS_PATH             #NFS服务器共享出来的目录
              value: /data1/
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.1.1.13           #NFS服务器地址
            path: /data1/               #NFS服务器共享出来的目录
  • 创建,并查看
//创建
]# kubectl apply -f deployment.yaml

//查看
]# kubectl get pods -n ns-storageclass
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-678bbdf997-z8htb   1/1     Running   0          54s

6.2.3、创建NFS SotageClass

  • 创建NFS SotageClass的yaml文件
    • 在github上的位置:nfs-subdir-external-provisioner/deploy/class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"  #是否设置为默认的storageclass
provisioner: nfs-client                                   #动态卷分配者名称,必须和上面创建的PROVISIONER_NAME变量保存一致
parameters:
  archiveOnDelete: "true"                                 #删除pv的时候,是否备份数据。"false"不保留数据,"true"保留数据
mountOptions: 
  - hard                                                  #指定为硬挂载方式
  - nfsvers=4                                             #指定NFS版本,这个需要根据NFS Server版本号设置
  • 创建,并查看
//创建
]# kubectl apply -f class.yaml

//查看
]# kubectl get StorageClass
NAME         PROVISIONER   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   nfs-client    Delete          Immediate           false                  36s

6.2.4、创建PVC

  • 创建名称空间
]# kubectl create namespace test
  • 创建PVC的yaml文件
    • 在github上的位置:nfs-subdir-external-provisioner/deploy/test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  namespace: test
spec:
  storageClassName: nfs-client    ## 需要与上面创建的StorageClass的名称一致
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
  • 创建,并查看
//创建
]# kubectl apply -f test-claim.yaml

//查看pvc
]# kubectl get pvc -A
NAMESPACE   NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test        test-claim   Bound    pvc-1b4d3ca2-30fb-4391-8401-bb2a87e86885   500Mi      RWO            nfs-client     12s

//查看pv
]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   REASON   AGE
pvc-1b4d3ca2-30fb-4391-8401-bb2a87e86885   500Mi      RWO            Delete           Bound    default/test-claim   nfs-client              15s

6.2.5、在pod中使用PVC

  • 创建pod的yaml文件(test-pod.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-deployment
  namespace: test
spec:
  selector:
    matchLabels:
      app: busybox-pod
  replicas: 1
  template:
    metadata:
      labels:
        app: busybox-pod
    spec:
      containers:
      - name: busybox-container
        image: busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh", "-c", "while true; do echo $(date) >> /data/log/time.log; sleep 3; done"]
        volumeMounts:
        - name: log
          mountPath: /data/log/
      volumes:
      - name: log
        persistentVolumeClaim:     #!
          claimName: test-claim    #PVC的名称
  • 创建,并查看
//创建
]# kubectl apply -f test-pod.yaml

//查看
]# kubectl get pods -n test
NAME                                  READY   STATUS    RESTARTS   AGE
busybox-deployment-78cc67f5bb-bqkhn   1/1     Running   0          24s
  • 查看存储服务器
]# tailf /data1/test-test-claim-pvc-3836b222-694d-4429-967c-e0bc3406cdf7/time.log 
Fri Oct 8 01:49:35 UTC 2022
Fri Oct 8 01:49:38 UTC 2022
Fri Oct 8 01:49:41 UTC 2022
...

1

#                                                                                                                        #
posted @ 2022-06-20 12:15  麦恒  阅读(137)  评论(0编辑  收藏  举报