k8s特性04 —— 存储01(pv/pvc/storageclass)
/ / 点击引言
在Pod对象中,如果一个容器需要使用到存储的话,可以通过以下这种方式:
1 | apiVersion: v1 |
在 pod.spec.volumes 仍然定义了其他很多种类型的存储可以使用:
awsElasticBlockStorecephfsgcePersistentDiskglusterfs等等。
得益于K8S的这种设计,在Pod中可以直接定义并使用多种存储,但这样使用存储带来了另外的问题:
- 使用k8s的开发者需要对存储要有所了解,才能够正确使用,这增加了使用的复杂度
- 对于使用到的存储,其地址、授权信息都暴露给用户,增加了信息暴露风险
通常来讲,对于开发者,他们并不需要关注底层的存储连接信息、如何配置、甚至不必关注存储地址,只需要告诉系统要使用多大存储以及读写权限即可。
基于这种情况,K8S 引入了另外一种存储对象:PV(persistent volume) PVC(persistent volume claim),用于降低用户使用存储的门槛。
PV / PVC
PV: Persistent Volume,持久化存储卷。详细的定义了存储卷的类型、大小、连接挂载方式等。
PVC: Persistent Volume Claim,持久化存储卷声明。定义了存储卷大小、读写权限等,没有存储卷的细节信息。
开发者需要使用到存储时,只需要: 1. 定义
pvc; 2. 在pod的volume配置中引用pvc。不需要关注存储本身。存储则由运维人员添加。在这种设计中,将存储的定义与实现解耦,开发者关注定义
pvc,运维人员关注实现(pv),实现了职责分离,也避免向外部暴露更多存储信息。
静态提供存储(static provisioning)
由运维人员创建出
pv。开发者定义pvc,然后由controller-manager来找到最合适的pv然后绑定它,然后给用户使用(也可以在pvc的定义中,通过pvc.spec.volumeName来指定绑定某一个特定的pv。)。
动态提供存储(dynamic provisioning)
在静态提供存储中,需要人工创建大量的
pv给用户使用,但在实际应用场景中,是个比较麻烦的工作。因此,k8s中设计了动态提供存储(dynamic provisioning)的功能(CSI)。
CSI设计

如图,是csi架构设计。
csi的架构协作者主要包括四部分:
- k8s:使用k8s的主体,参与
csi协作的组件主要有:
- apiserver
- scheduler(主要针对立即绑定的
storageClass类型,在pod调度前要先创建出PV,scheduler作条件判断)- kubelet(
pod启动过程中,需要挂载存储,调用csiNode)- external components:由k8s社区维护,打通k8s与用户开发组件的中间层,主要包括以下组件:
- driverRegistar: 负责注册用户
csi组件- externalProvisionor: 负责监听
apiserver的pvc,然后调用用户组件创建存储以及pv等- externalAttacher: 负责
attach/unattach操作,对应csi中的publishing/unpublishing(attach区别于主机attach存储的操作,个人理解这里相当于把存储attach到云上,并非attach到具体node上)- custom components:用户自定义开发的组件,用于管理存储,主要3个组件:
- csiIdentify: csi标识
- csiCcontroller: 存储控制器(
publish/unpublish、create/delete vol、snapshot等操作)- csiNode: 节点插件,
daemonset方式运行,每个节点都要有,由kubelet调用(node stage/unstage:挂载存储到主机、node publish/unpublish:mount存储到pod目录 等操作)- external persistent storage:外部存储供应商,提供存储服务。主要由用户自开发组件中的
controller中的调用。
storageClass
在
CSI的设计中,storageClass是核心的API 资源,它定义了管理存储者(provisioner)的名字以及创建存储时额外的参数、挂载opt、回收策略、pv绑定策略等。
立即绑定
情形1: 未设置
storageClass此时,
controllerManager会自动寻找最合适的pv,并将其与pvc绑定
情形2:设置
storageClass,但sotrageClass的VOLUMEBINDINGMODE为Immediate
此时,controllerManager会自动寻找最合适的pv,并将其与pvc绑定。不同于情形1的是,此处的pv可能是由管理员添加,或者由provisioner添加(provisioner会立即调用相关方法生成pv)。(此处管理员添加的pv的storageClass要同pvc的storageClass一致才可以绑定)
延迟绑定
未设置
storageClass且未配置默认的storageClass时,不存在延迟绑定
情形:设置
storageClass,且其VOLUMEBINDINGMODE值为WaitForFirstConsumer
此时,在控制器控制循环内不会绑定pv,在该pvc被使用时,才会绑定。过程:
waitForConsumer- 创建使用
pvc的podpod调度器在pvc上打上annotation(volume.kubernetes.io/selected-node)controller-manager给pvc打上annotation(volume.beta.kubernetes.io/storage-provisioner)external-provisioner调用csi方法创建pv(创建出来的pv已经带上pvc了)controller-manager执行绑定操作