tnblog
首页
视频
资源
登录

Kubernetes 应用存储和持久化数据卷:存储快照与拓扑调度

5867人阅读 2021/3/18 16:01 总访问:3478623 评论:0 收藏:0 手机
分类: 容器编排

Kubernetes

Kubernetes 应用存储和持久化数据卷:存储快照与拓扑调度

基本知识

存储快照产生背景


1. 如何保证重要数据在误操作之后可以快速恢复,以提高数据操作容错率?
2. 如何能够快速进行复制,迁移重要数据的动作?如进行环境复制与数据开发等。

Kubernetes CSI Snapshotter controller正是为了解决这些需求而设计的。

存储快照用户接口 - snapshot


k8s中通过pvc以及pv的设计体系来简化用户对存储的使用,而存储快照的设计其实是仿照 pvc & pv体系的思想设计。当用户需要存储快照功能时,可以通过 VolumeSnapshot 对象来声明,并指定相应的 VolumeSnapshotClass。如下对比图所示,动态生成 VolumeSnapshotContent 和动态生成 pv 的流程是非常相似的。

存储快照用户接口 - restore


有了存储快照之后,如何将快照数据快速恢复过来呢?

如上图所示的流程,可以借助PVC对象将其的 dataSource 字段指定为 VolumeSnapshot对象。这样当 PVC 提交后,会由集群中的相关组件找到 dataSource 所指向的存储快照数据,然后新创建对应的存储以及 pv 对象,将存储快照数据恢复到新的pv中,这样数据就恢复回来了,这就是存储快照的restore用法。

Topolopy-含义


首先了解一下拓扑是什么意思:这里所说的拓扑是K8s集群中为管理的nodes划分的一种”位置”关系,意思为:可以通过在node的labels信息里面填写某一个node属于某一个拓扑。

常见的有三种,这三种在使用时经常会遇到的:

- 第一种,在使用云存储访问的时候,经常会遇到region,也就是地区的概念,在k8s中常用通过 label failure-domain.beta.kubernetes.io/region 来标识。这个是为了标识单个 k8s 集群管理的跨 region 的 nodes 到底属于哪个地方;

- 第二种,比较常用的是可用区,也就是available zone,在 k8s 中常通过 label failure-domain.beta.kubernetes.io/zone来标识。这个是为了标识单个 k8s 集群管理的跨 zone 的 nodes 到底属于哪个可用区;

- 第三种,是hostname,就是单机维度,是拓扑域为 node 范围,在k8s中常通过 label kubernetes.io/hostname 来标识,这个在文章的最后讲 local pv 的时候,会再详细描述。

上面讲到的三个拓扑是比较常用的,而拓扑其实是可以自己定义的。可以定义一个字符串来标识一个拓扑域,这个 key 所对应的值其实就是拓扑域下不同的拓扑位置。

举个例子:可以以机房中的机架这个纬度来做一个拓扑域。这样就可以将不同机架(rack)上面的机器标记为不同的拓扑位置,也就是说可以将不同机架上机器的位置关系通过rack这个纬度来标识。属于 rack1 上的机器,node label 中都添加 rack 的标识,它的value就标识成 rack1,即 rack=rack1;另外一组机架上的机器可以标识为rack=rack2,这样就可以通过机架的纬度就来区分来k8s中的node所处的位置。

接下来就一起来看看拓扑再 K8s 存储中的使用。

存储拓扑调度产生背景


Kubernetes 中通过PVC&PV 体系将存储与计算分离,即使用不同的Controllers管理存储资源和计算资源。但如果创建的PV有访问 “位置” (.spec.nodeAffinity)的限制,也就是只在特定的一些Nodes上才能访问PV。原有的创建Pod的与创建PV的流程的分离,就无法保证新创建的Pod被调度到可以访问PV的Node上,最终导致Pod无法正常运行起来。

如场景一:Local PV只能在指定的Node上被Pod使用



场景二:单 Region 多 Zone K8s 集群,阿里云云盘当前只能被同一个Zone的Node上的Pod访问


存储拓扑调度

  1. 本质问题
    PV在Binding或者Dynamic Provisioning时,并不知道使用它的Pod被会调度到哪些Node上?但PV本身的访问对Node的 “位置”(拓扑)有限制。
  2. 流程改进
    Binding/Dynamic Provisioning PV的操作 Delay 到 Pod 调度结果确定之后做,好处:
    • 对于pre-provisioned 的含有 Node Affinity的PV对象,可以在Pod运行的Node确认之后,根据Node找到合适的PV对象,然后与Pod中使用的PVC Binding,保证Pod运行的Node满足PV对访问 “位置”(拓扑)的要求。
    • 对于dynamic provisioning PV 场景,在Pod运行的Node确认之后,在Pod运行的Node确认之后,可以结合Node的 “位置”(拓扑)信息创建可被该 Node 访问的PV对象
  3. Kubernetes 相关组件改进
    • PV Controller:支持延迟Binding操作
    • Dynamic PV Provisioner:动态创建PV时要结合Pod待运行的Node的 “位置”(拓扑)信息
    • Scheduler:选择Node时要考虑Pod的PVC Binding需求,也就是要结合 pre-provisioned 的 PV 的 Node Affinity 以及 dynamic provisioning 时 PVC 指定 StorageClass.AllowedTopologies的限制

Volume Snapshot/Restore示例


首先需要集群管理员,在集群中创建 VolumeSnapshotClass 对象,VolumeSnapshotClass 中一个重要字段就是 Snapshot,它是指定真正创建存储快照所使用的卷插件,这个卷插件是需要提前部署的,稍后再说这个卷插件。

接下来用户他如果要做真正的存储快照,需要声明一个 VolumeSnapshotClass,VolumeSnapshotClass 首先它要指定的是 VolumeSnapshotClassName,接着它要指定的一个非常重要的字段就是 source,这个 source 其实就是指定快照的数据源是啥。这个地方指定 name 为 disk-pvc,也就是说通过这个 pvc 对象来创建存储快照。提交这个 VolumeSnapshot 对象之后,集群中的相关组件它会找到这个 PVC 对应的 PV 存储,对这个 PV 存储做一次快照。

有了存储快照之后,那接下来怎么去用存储快照恢复数据呢?这个其实也很简单,通过声明一个新的 PVC 对象并在它的 spec 下面的 DataSource 中来声明我的数据源来自于哪个 VolumeSnapshot,这里指定的是 disk-snapshot 对象,当我这个 PVC 提交之后,集群中的相关组件,它会动态生成新的 PV 存储,这个新的 PV 存储中的数据就来源于这个 Snapshot 之前做的存储快照。

  1. # 创建VolumeSnapshotClass对象
  2. apiVersion: snapshot.storage.k8s.io/v1alpha1
  3. kind: VolumeSnapshotClass
  4. metadata:
  5. name: disk-snapshotclass
  6. snapshotter: diskplugin.csi.alibabacloud.com
  7. # 指定Volume Snapshot时使用的Volume Plugin
  1. # 创建VolumeSnapshot对象
  2. apiVersion: snapshot.storage.k8s.io/v1alpha1
  3. kind: VolumeSnapshot
  4. metadata:
  5. name: disk-snapshot
  6. spec:
  7. snapshotClassName: disk-snapshotclass
  8. source:
  9. name: disk-pvc # Snapshot的数据源
  10. kind: PersistentVolumeClaim
  1. # 从snapshot中恢复数据到新生成的PV对象中
  2. apiVersion: v1
  3. kind: PersistentVolumeClaim
  4. metadata:
  5. name: restore-pvc
  6. spec:
  7. dataSource:
  8. name: disk-snapshot
  9. kind: VolumeSnapshot
  10. apiGroup: snapshot.storage.k8s.io
  11. accessModes:
  12. - ReadWriteOnce
  13. resources:
  14. requests:
  15. storage: 20Gi
  16. storageClassName: csi-disk

Local PV示例


Local PV 大部分使用的时候都是通过静态创建的方式,也就是要先去声明PV对象,即然Local PV只能是本地访问,就需要在声明PV对象的,在PV对象中通过nodeAffinity来限制我中国PV只能在单node上访问也就是给中国PV加上拓扑限制。如下列代码所示,keykubernetes.io/hostname来做标记,也就是只能在node1访问。如果想用这个PV,你的pod必须要调度到node1上。

  1. # 创建Local PV对象
  2. apiVersion: v1
  3. kind: PersistentVolume
  4. metadata:
  5. name: local-pv
  6. spec:
  7. capacity:
  8. storage: 60Gi
  9. accessModes:
  10. - ReadWriteOnce
  11. persistentVolumeReclaimPolicy: Retain
  12. storageClassName: local-storage
  13. local:
  14. path: /share
  15. nodeAffinity: # 限制该PV只能再node1上被使用
  16. required:
  17. nodeSelectorTerms:
  18. - matchExpressions:
  19. - key: kubernetes.io/hostname
  20. operator: In
  21. values:
  22. - node1


即然是静态创建PV的方式,这里为什么还需要 storageClassName 呢?前面也说了,在 Local PV 中,如果要想让它正常工作,需要用到延迟绑定特性才行,那即然是延迟绑定,当用户在写完PVC提交之后,即使集群中有相关的PV能与它匹配,也就是说 PV controller 不能马上去做binding,这个时候你就要通过一种手段来告诉PV controller,声明情况下是不能立即做binding。这里的storageClass就是为了起到这个作用,我们可以可以看到 storageClass 里面的 provisioner 指定的是 no-provisioner,其实就是相当于告诉 k8s 它不会去动态创建 PV,它主要用到 storageclassVolumeBindingMode 字段,叫 WaitForFirstConsumer,可以先简单地认为他是延迟绑定。

  1. # 创建一个no-provisioner StorageClass对象,目的是告诉PV
  2. # Controller遇到 .spec.storageClassName 为 local-storage的
  3. # PVC暂不做Binding对象
  4. apiVersion: storage.k8s.io/v1
  5. kind: StorageClass
  6. metadata:
  7. name: local-storage
  8. provisioner: kubernetes.io/no-provisioner
  9. volumeBindingMode: WaitForFirstConsumer # deley binding


当用户开始提交 PVC 的时候,PV Controller在看到这个pvc的时候,它会找到相应的 storageClass,发现这个BindingMode是延迟绑定,它就不会做任何事情。

之后当真正使用这个 pvc 的 pod,在调度的时候,当它恰好调度在符合 PV Nodeaffinity 的 node 的上面后,这个pod里面所使用的PVC才会真正地与PV做绑定,这样就保证我pod调度到这台node上之后,这个PV才与这个PV绑定,最终保证的是创建出来的pod能访问这块Local PV,也就是静态Provisioning` 场景下怎么去满足PV的拓扑限制。

  1. apiVersion: v1
  2. kind: PersistentVolumeClaim
  3. metadata:
  4. name: local-pvc
  5. spec:
  6. storageClassName: local-storage
  7. accessModes:
  8. - ReadWriteOnce
  9. resources:
  10. requests:
  11. storage: 60Gi

限制Dynamic Provisioning PV拓扑示例


动态就是指动态创建 PV 就有拓扑位置的限制,那怎么去指定?

首先在storageclass还是需要指定 BindingMode,就是 WaitForFirstConsumer,就是延迟绑定。

其次特别重要的一个字段就是 allowedTopologies,限制就在这个地方。上图中可用看到拓扑限制是可用区的级别,这里其实有两层意思:

1. 第一层意思就是说我创建PV的时候,创建出来的PV必须是在中国可用区可以访问的;
2. 第二层含义是因为声明的是延迟绑定,那调度器在发现使用它的PVC正好对应的是该 storageclass的时候,调度 pod 就要选择位于该可用区的nodes。

总之,就是要从两方面保证,一是动态创建出来的存储时要能被中国可用区访问的,二是我调度器在选择node的时候,要落在中国可用区内的,这样的话就保证我的存储和我要使用存储的这个 pod 它所对应的 node,它们之间的拓扑域在同一个拓扑域,用户在写 PVC 文件的时候,写法是跟以前的写法是一样的,主要是在 storageclass 中要做一些拓扑限制。

  1. apiVersion: storage.k8s.io/v1
  2. kind: StorageClass
  3. metadata:
  4. name: csi-disk
  5. provisioner: diskplugin.csi.alibabacloud.com
  6. parameters:
  7. regionId: cn-hangzhou
  8. fsType: ext4
  9. type: cloud_ssd
  10. volumeBindingMode: WaitForFirstConsumer
  11. allowedTopologies:
  12. - matchLabelExpressions:
  13. # 拓扑域限制: 动态创建的PV只能在可用区 cn-hangzhou-d被使用
  14. - key: topology.diskplugin.csi.alibabacloud.com/zone
  15. values:
  16. - cn-hangzhou-d
  17. reclaimPolicy: Delete
  1. # 当该PVC对象被创建之后由于对应StorageClass的BindingMode为
  2. # WaitForFirstConsumer并不会马上动态生成PV对象,耳塞要等到使用
  3. # 该PVC对象的第一个Pod调度结果出来之后,而且kube-scheduler在调度
  4. # Pod的时候去选择满足StorageClass.allowedTopologies中指定的
  5. # 拓扑限制的Nodes
  6. apiVersion: v1
  7. kind: PersistentVolumeClaim
  8. metadata:
  9. name: disk-pvc
  10. spec:
  11. accessModes:
  12. - ReadWriteOnce
  13. resources:
  14. requests:
  15. storage: 30Gi
  16. storageClassName: csi-disk

欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

阿里云 Kubernetes

https://help.aliyun.com/document_detail/86759.html 可以有三种计费方式https://ecs-buy.aliyun.com/wizard?spm=5176.13...

Kubernetes Job讲解

kubernetes Job讲解[TOC] 需求来源Job 背景问题我们可以通过Pod来直接运行任务进程吗?这样做将会产生以下几种问题:1. 我...

Kubernetes DaemonSet讲解

Kubernetes DaemonSet讲解[TOC] 需求来源背景问题我们可以让每个集群内的节点都运行一个相同的Pod吗?如果这样做,以下的...

Kubernetes Pod中断预算【PDB】

Kubernetes Pod中断预算【PDB】[TOC] 尽管Deployment或ReplicaSet一类的控制器能够确保相应Pod对象的副本数量不断逼近期...

Kubernetes Velero 备份的运用

Velero 的运用[TOC] Velero简介Velero是一个开源工具,可以安全地备份,恢复和迁移Kubernetes集群和持久卷。它既可以在本...

Kubernetes 应用配置管理

Kubernetes 应用配置管理[TOC] 需求来源背景问题除了依托容器镜像来定义运行的Container,Pod还需要解决如下问题:1. 不可...

Kubernetes 应用存储和持久化数据卷

Kubernetes 应用配置管理[TOC] Volumes介绍Pod Volumes1. 如果一个Pod中某一个容器异常退出,被kubelet拉起如何保证之前的...

Kubernetes网络(IPVLAN与MACVLAN)

Kubernetes网络模型[TOC] 三种网络模型 在k8s中一般常见的网络模型支持三种,虚拟网桥、多路复用和硬件交换。 虚拟网...

Kubernetes IP Address

Kubernetes IP Address[TOC] IP AddressIP地址是在计算机网络中被用来唯一标识设备的一组数字。IPv4地址由32位二进制数值...

Dapr 官方教程第二章(Hello World Kubernetes)

Dapr 官方教程第二章(Hello World Kubernetes)[TOC] 本教程将帮助您在 Kubernetes 集群中使用 Dapr。您将从Hello World部...

Kubernetes 搭建RabbitMq集群环境

Kubernetes 搭建RabbitMq集群环境[TOC] 由于Kubectl RabbitMQ 插件在官方是基于krew进行安装的所以我们首先需要安装krew插...

Kubernetes 删除命名空间

Kubernetes 删除命名空间[TOC] 可以直接通过如下命令删除k8s中命名空间下的所有资源。kubectl delete ns [namespace] ...

Kubernetes top之安装metrics-server

Kubernetes top之安装metrics-server[TOC] 一般我们需要知道kubernetes的pod与node的cpu与内存使用情况时,我们可以通过ku...

Kubernetes ExternalName Service

Kubernetes ExternalName Service[TOC] ExternalName 的服务与普通服务的区别在于:将服务映射到 DNS 名称。如下图所示: ...

Kubernetes 自定义Endpoint资源

Kubernetes 自定义Endpoint资源[TOC] 当pod需要服务发布出去的时候中间所关联的还有一个Endpoint这个资源,它能确定服务关...
这一世以无限游戏为使命!
排名
2
文章
636
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术