总结:K8S持久化存储方案
一、名词介绍首先介绍几个 K8s 原生的概念名词:PV - PersistVolume: 可被 Pod 挂载的持久化数据卷在 K8s 中表示PVC - PersistVolumeClaim: 用于动态管理的持久化存储资源请求对象,定义需要的存储类型,大小,访问方式等StorageClass:定义动态管理行为的资源对象,一般由管理员维护,定义存储资源的来源,权限,分配回收策略等provisioner
一、名词介绍
首先介绍几个 K8s 原生的概念名词:
- PV - PersistVolume: 可被 Pod 挂载的持久化数据卷在 K8s 中表示
- PVC - PersistVolumeClaim: 用于动态管理的持久化存储资源请求对象,定义需要的存储类型,大小,访问方式等
- StorageClass:定义动态管理行为的资源对象,一般由管理员维护,定义存储资源的来源,权限,分配回收策略等
- provisioner:运行在集群中,执行实际管理动作的工作负载。主要承担数据卷的 create、delete 等工作。
- csi (Container Storage Interface): 旨在能为容器编排引擎和存储系统间建立一套标准的存储调用接口,通过该接口能为容器编排引擎提供存储服务。K8s 1.13 版本对 csi 支持进入了 GA(General Availability)状态
- ceph-csi:ceph 社区的 csi 实现(我们的K8S服务就是使用的ceph-csi对接的叶权他们那边的存储)。
PV
通常代表一个存储卷,PVC
与PV
是一一对应关系,通常一个PV
必须被Bound
到一个PVC
上,才能被Pod访问和使用。
Kubernetes从1.4版本开始引入了一个新的资源对象StorageClass(动态管理),用于标记存储资源的特性和性能。到1.6版本时,StorageClass和动态资源供应的机制得到了完善,实现了存储卷的按需创建,在共享存储的自动化管理进程中实现了重要的一步。
在动态管理的场景中,PV
不需要预先创建,而是由PVC
中关联的StorageClass
,根据PVC
中指定的卷大小、访问模式等参数,动态创建得来。
注意:只是动态管理是不需要预先创建PV,在StorageClass之前是需要管理员手动创建的。
PV,PVC,StorageClass都属于共享存储。
Kubernetes支持两种资源的供应模式:静态模式(Static)和动态模式(Dynamic)。资源供应的结果就是创建好的PV。
- 静态模式:集群管理员手工创建许多PV,在定义PV时需要将后端存储的特性进行设置。
- 动态模式:集群管理员无须手工创建PV,而是通过StorageClass的设置对后端存储进行描述,标记为某种类型。此时要求PVC对存储的类型进行声明,系统将自动完成PV的创建及与PVC的绑定。PVC可以声明Class为"",说明该PVC禁止使用动态模式。
二、为什么会有这么多存储定义?
为了方便开发人员更加容易的使用存储出现了PV,PVC,StorageClass三个概念。
通常我们在一个POD中定义使用存储是这样的方式,我们以hostpath类型来说:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- image: nginx
name: mynginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: html
volumes:
- name: html # 名称
hostPath: # 存储类型
path: /data # 物理节点上的真实路径
type: Directory # 如果该路径不存在讲如何处理,Directory是要求目录必须存在
其实通过上面可以看出来,无论你使用什么类型的存储你都需要手动定义,指明存储类型以及相关配置。
这里的hostpath类型还是比较简单的,如果是其他类型的比如分布式存储,那么这对开发人员来说将会是一种挑战,因为毕竟真正的存储是由存储管理员来设置的他们会更加了解,那么有没有一种方式让我们使用存储更加容易,对上层使用人员屏蔽底层细节呢?
答案是肯定的,这就是PV、PVC的概念。
不过需要注意的是我们在集群中通常不使用hostPath、emptyDir这种类型,除非你只是测试使用。
三、PV
PV全称叫做Persistent Volume,持久化存储卷。它是用来描述或者说用来定义一个存储卷的。这个通常都是有运维或者数据存储工程师来定义。
比如下面我们定义一个NFS类型的PV:
apiVersion: v1
kind: PersistentVolume
metadata: # PV建立不要加名称空间,因为PV属于集群级别的
name: nfs-pv001 # PV名称
labels: # 这些labels可以不定义
name: nfs-pv001
storetype: nfs
spec: # 这里的spec和volumes里面的一样
storageClassName: normal
accessModes: # 设置访问模型
- ReadWriteMany
- ReadWriteOnce
- ReadOnlyMany
capacity: # 设置存储空间大小
storage: 500Mi
persistentVolumeReclaimPolicy: Retain # 回收策略
nfs:
path: /work/volumes/v1
server: stroagesrv01.contoso.com
accessModes:支持三种类型
-
ReadWriteMany:多路读写,卷能被集群多个Node挂载并读写
-
ReadWriteOnce:单路读写,卷只能被单一集群Node挂载读写
-
ReadOnlyMany:多路只读,卷能被多个集群Node挂载且只能读
这里的访问模型总共有三种,但是不同的存储类型支持的访问模型不同,具体支持什么需要查询官网。
比如我们这里使用nfs,它支持全部三种。但是ISCI就不支持ReadWriteMany;HostPath就不支持ReadOnlyMany和ReadWriteMany。
persistentVolumeReclaimPolicy:也有三种策略,这个策略是当与之关联的PVC被删除以后,这个PV中的数据如何被处理
-
Retain:保留数据,需要手工处理。回收策略 Retain 使得用户可以手动回收资源。当删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV。
-
Delete:当删除与之绑定的PVC时候
-
Recycle:这个在1.14版本中以及被废弃,取而代之的是推荐使用动态存储供给策略,它的功能是当删除与该PV关联的PVC时,自动删除该PV中的所有数据
注意:PV必须先于POD创建,而且只能是网络存储不能属于任何Node,虽然它支持HostPath类型但由于你不知道POD会被调度到哪个Node上,所以你要定义HostPath类型的PV就要保证所有节点都要有HostPath中指定的路径。
四、PVC
PVC全称是Persistent Volume Claim,也就是持久化存储声明。
PVC是用来描述希望使用什么样的或者说是满足什么条件的存储,它的开发人员使用这个来描述该容器需要一个什么存储。
比如下面使用NFS的PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc001
namespace: default
labels: # 这些labels可以不定义
name: nfs-pvc001
storetype: nfs
capacity: 500Mi
spec:
storageClassName: normal
accessModes: # PVC也需要定义访问模式,不过它的模式一定是和现有PV相同或者是它的子集,否则匹配不到PV
- ReadWriteMany
resources: # 定义资源要求PV满足这个PVC的要求才会被匹配到
requests:
storage: 500Mi # 定义要求有多大空间
这个PVC就会和上面的PV进行绑定,为什么呢?它有一些原则:
-
PV和PVC中的spec关键字段要匹配,比如存储(storage)大小。
-
PV和PVC中的storageClassName字段必须一致,这个后面再说。
注意:上面的labels中的标签只是增加一些描述,对于PVC和PV的绑定没有关系。
应用了上面的PV和PVC,可以看到自动绑定了。
五、在POD中如何使用PVC呢
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat-deploy
spec:
replicas: 1
selector:
matchLabels:
appname: myapp
template:
metadata:
name: myapp
labels:
appname: myapp
spec:
containers:
- name: myapp
image: tomcat:8.5.38-jre8
ports:
- name: http
containerPort: 8080
protocol: TCP
volumeMounts:
- name: tomcatedata
mountPath : "/data"
volumes:
- name: tomcatedata
persistentVolumeClaim:
claimName: nfs-pvc001
六、StorageClass
PV 这个对象的创建,是由运维人员完成的。
但是,在大规模的生产环境里,这其实非常麻烦。因为,一个大规模的 Kubernetes 集群里很可能有成千上万个 PVC,这就意味着运维人员必须得事先创建出成千上万个 PV。更麻烦的是,随着新的 PVC 不断被提交,运维人员就不得不继续添加新的、能满足条件的 PV,否则新的 Pod 就会因为 PVC 绑定不到 PV 而失败。在实际操作中,这几乎没办法靠人工做到。
所以,Kubernetes 为我们提供了一套可以自动创建 PV 的机制,即:Dynamic Provisioning。相比之下,前面人工管理 PV 的方式就叫作 Static Provisioning。Dynamic Provisioning 机制工作的核心,在于一个名叫 StorageClass 的 API资源对象。
而 StorageClass资源对象的作用,其实就是创建 PV 的模板。
具体地说,StorageClass 对象会定义如下两个部分内容:
- PV 的属性。比如,存储类型、Volume 的大小等等。
- 创建这种 PV 需要用到的存储插件。比如,Ceph 等等。
有了这两个信息后,K8S就能够根据用户提交的PVC,找到一个对应的 StorageClass 了。然后,Kubernetes 就会调用该 StorageClass 声明的存储插件,创建出需要的 PV。
创建storageClass:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: storage/nfs
reclaimPolicy: Delete
allowVolumeExpansion: True #允许pvc创建后扩容
创建pvc(指定用什么PV模板,即StorageClass):
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
# 这个名字要和上面创建的storageclass名称一致
storageClassName: nfs-storage
创建Pod挂载pvc:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
type: NodePort
ports:
- port: 3306
nodePort: 30306
protocol: TCP
targetPort: 3306
selector:
app: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.7
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: my-pvc
七、其它存储相关
---------------------------------------------------------------------------------------------------------------------------------------
共享存储为分布式系统非常重要的一部分,存储一般要求稳定、可用、性能、可靠。
从用t户角度看
存储就是一块盘或者一个目录,用户不关心盘或者目录如何实现,用户要求非常“简单”,就是稳定,性能好。为了能够提供稳定可靠的存储产品,各个厂家推出了各种各样的存储技术和概念。为了能够让大家有一个整体认识,本文先介绍存储中的这些概念。
从存储介质角度
存储介质分为机械硬盘和固态硬盘(SSD)。机械硬盘泛指采用磁头寻址的磁盘设备,包括SATA硬盘和SAS硬盘。由于采用磁头寻址,机械硬盘性能一般,随机IOPS一般在200左右,顺序带宽在150MB/s左右。固态硬盘是指采用Flash/DRAM芯片+控制器组成的设备,根据协议的不同,又分为SATA SSD,SAS SSD,PCIe SSD和NVMe SSD。
从产品定义角度
存储分为本地存储(DAS),网络存储(NAS),存储局域网(SAN)和软件定义存储(SDS)四大类
- DAS就是本地盘,直接插到服务器上
- NAS是指提供NFS协议的NAS设备,通常采用磁盘阵列+协议网关的方式
- SAN跟NAS类似,提供SCSI/iSCSI协议,后端是磁盘阵列
- SDS是一种泛指,包括分布式NAS(并行文件系统),ServerSAN等
从应用场景角度
存储分为文件存储(Posix/MPI),块存储(iSCSI/Qemu)和对象存储(S3/Swift)三大类。
Kubernetes是如何给存储定义和分类呢?Kubernetes中跟存储相关的概念有PersistentVolume (PV)和PersistentVolumeClaim(PVC),PV又分为静态PV和动态PV。静态PV方式如下:
动态PV需要引入StorageClass的概念,使用方式如下:
市面上的存储产品种类繁多,但是对于容器场景,主要集中在4种方案:分布式文件存储,分布式块存储,Local-Disk和传统NAS。
分布式块存储包括开源社区的Ceph,Sheepdog,商业产品中EMC的Scale IO,Vmware的vSAN等。分布式块存储不适合容器场景,关键问题是缺失RWX的特性。
参考:
kubernetes【存储】1. 共享存储pv、pvc、StorageClass使用详解_ghostwritten的博客-CSDN博客_pv pvc storageclass
更多推荐
所有评论(0)