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
# #