内容简介:聊聊Kubernetes计算资源模型(上)——资源抽象、计量与调度
导读:
是时候来缕一缕Kubernetes的资源模型了,它对我们在生产环境中运维Kubernetes至关重要。我们将这个话题分为三个部分,第一部分整体介绍Kubernetes的资源抽象,以及他们的计量方式,初步介绍资源调度;第二部分介绍Pod级别的QoS、实现细节以及资源超卖;第三部分将具体介绍Kubernetes的资源调度和整个调度体系。
1
预热
Kubernetes的资源模型的理解对Kubernetes的使用者至关重要,它不仅关系到基础设施和资源的使用率优化,还关系到生产环境中Kubernetes集群的稳定性。
在介绍资源模型之前,我们先来简单介绍一下Kubernetes的几个主要概念:
-
Node:计算节点,用来提供计算资源实体,可以理解为物理机、云主机、虚拟机等。
-
Pod:Kubernetes调度容器的基本单位,Pod中包含一个或者多个容器,每个Pod最终会被调度到Node上,消费Node上提供的计算资源。
-
Scheduler:Kubernetes将用户创建Pod的请求提交给Scheduler调度器,Scheduler决定Pod最终被调度到哪个Node上。
如下图所示,Pod经过Scheduler调度,绑定到某个Node上,消费该Node提供的计算资源:
2
资源分类、抽象与表示
A
什么是资源
对于一个Kubernetes Node(物理机、虚拟机、云主机)所提供的资源,可分为三大类:计算资源(CPU/内存/GPU)、网络资源(IP地址/带宽),存储资源(磁盘/SSD)。
显然这个粒度的分类对我们使用资源没有帮助,我们需要更加细分和量化这些资源,才能在系统中更好的进行资源分配和调度。
B
资源分类
在计算机体系中,可以被称为"资源"的可以列举很多:
-
CPU
-
内存
-
GPU
-
磁盘空间(Disk space)
-
磁盘时间(Disk time)
-
网络带宽
-
端口号
-
高速缓存
-
IP地址
-
PIDs
-
...
这些资源从另外的角度又可分为两类:可压缩资源和不可压缩资源:
可压缩资源
可压缩资源有如下特性:
-
资源本身无状态
-
申请资源非常快
-
回收资源几乎不会失败
CPU、GPU属于可压缩的资源,磁盘时间(Disk time)也属于可压缩资源。
可压缩资源
不可压缩资源有如下特性:
-
资源本身持有状态
-
申请资源相对比较慢
-
回收资源时可能失败
内存、磁盘空间(Disk space)属于不可压缩资源。
C
资源抽象
不透明整数资源
Kubernetes使用"不透明的整数资源"( Opaque Integer Resources )方式来量化和使用计算资源。
对于上面提到的CPU、GPU、Memory、Disk time...等,Kubernetes将他们抽象成整数,而不用关心它的具体细节。
Kubernetes将CPU每个CPU核的计算能力抽象为整数1或者1000m,如果一个Pod申请了CPU为0.5或者500m,这就代表它申请了0.5CPU核。
关于" Opaque Integer Resources "资源的讨论: stackoverflow/the-opaque-integer-resources
资源的表示
对于用户和Kubernetes组件(Scheduler, Auto-Scaler, Auto-Sizer, Load Balancers)都需要知道Pod的资源需求,Node资源能力和资源的使用率。
Kubernetes将Pod的资源需求和Node资源能力通过设定它们的Spec字段实现,资源的使用率通过设置Status字段来实现。
下面的例子说明了如何定义一个Pod的资源需求:
resourceRequirementSpec: [ request: [ cpu: 2.5, memory: "40Mi" ], limit: [ cpu: 4.0, memory: "99Mi" ], ]
其中:
-
request: request字段是可选的,代表Pod请求资源的数量,或者已请求和已分配的资源数量。Scheduler的调度算法已经request字段的来度量一个Pod是否适合 一个Node(Node上足够提供request的资源)。如果一个容器或者Pod尝试使用比request更多的资源,该服务的SLO将得不到保障,在资源短缺的情况下,这种请求会失败。 如果Request没有设置,那么它默认是limit的值。如果Pod没有设置,那么,request是pod中所有container请求资源的总和。
-
limit: limit字段也是可选的,它代表着容器或者Pod的最大资源使用上限,如果容器或者Pod使用的资源超出这个上限,它会被终止。如果不设置limit,那么意味着Pod 可以无上限使用资源,这种方式非常危险,在实际生产运维过程中,这种不设置limit会导致不确定的行为,特别是对于内存来说,在生产环境中使用Kubernetes的团队一定要重视这个问题。
通过设定request和limit可是实现Kubernetes不同级别的QoS和资源超卖,我们会在后面的文章中详细讨论。
下面的例子说明Node上总体资源能力的定义:
resourceCapacitySpec: [ total: [ cpu: 12, memory: "128Gi" ] ]
其中:
-
total: Node上所有可申请的资源总量。
C
Kubernetes保留的资源定义类型
从上面的例子中可以看出,"cpu", "memory"用来作为CPU资源和内存资源的标识,这两个是被Kubernetes保留的字段,用户定义的定义的第三方资源 不能使用这两个字段。Kubernetes对CPU和Memory两种资源进行了详细的描述:
CPU
-
名称:cpu或者kubernetes.io/cpu
-
单位:Kubernetes Compute Unit(KCU) Seconds/second(CPU核数记为"Kubernetes CPU")
-
内部表示: milli-KCUs
-
是否为可压缩资源:是
Kubernetes未来会支持两个特性用于细化CPU的使用:
-
[future] schedulingLatency: 在 lmctfy (Google开源的虚拟化技术)中设置调度延迟
-
[future] cpuConversionFactor: 作为Node的属性,用于区分不同Node上的CPU性能,用浮点数表示,默认为1.0
需要注意的是,如果CPU请求需要2个KCU,Kubernetes 不保证 真正申请到2个物理的CPU核心(保证相当于两个物理CPU核心的时间片),这方面的控制会在以后的feature中支持。
Memory
-
名称:memory或者kubernetes.io/memory
-
单位:bytes
-
是否为可压缩资源:否
内存的单位支持EB,PB,TB,GB,MB,KB,m的标识方式,也支持2的幂次的标识方式:EiB,PiB,TiB,GiB,MiB,KiB,Kubernetes支持这两种方式是为了照顾用户的使用习惯,两种方式并没有好坏之分。
D
资源的量化
Kubernetes将计算资源抽象以"整数"的方式进行量化,让计算资源更好的管理。
对于内存,Kubernetes将其记为1000Mi或者1024M等,如果Pod是想申请512MB的内存,就在Pod中标记内存申请512M。
下面的例子说明了一个Pod如何申请1个CPU核和2G内存:
{ "kind": "Pod", "apiVersion": "v1" "metadata": { "name": "kafka-1", "labels": { "component": "kafka", "role": "kafka-1" } }, "spec": { "restartPolicy": "Always", "containers": [ { "name": "kafka" "image": "registry.docker:5000/kafka:2.11-0.9.0", "resources": { "limits": { "cpu": "1", -- 申请1个CPU核 "memory": "20480M" -- 申请2G内存 } }, "ports": [ { "containerPort": 9092 } ] } ] } }
Kubernetes将每个Node的计算资源抽象为"Capacity",它代表着这个Node提供CPU/Memory等计算资源的总体能力, Kubelet内置的cAdvisor组件会探测所在节点的计算能力(CPU核数和内存数)。Capacity也是通过整数的形式来描述:
{ "kind": "Node", "apiVersion": "v1", "metadata": { "name": "172.21.1.11", "labels": { "kubernetes.io/hostname": "172.21.1.11" } }, "spec": { "externalID": "172.21.1.11" }, "status": { "capacity": { "cpu": "40", --- 共40个CPU核心 "memory": "98760652Ki", --- 共98G内存 } } }
E
其它资源类型
目前Kubernetes支持对CPU/Memory/GPU三种资源的使用,Kubernetes计划将来支持更多的资源类型,比如
:
[future]网络带宽
-
名称:network-bandwidth或者kubernetes.io/network-bandwidth
-
单位:bytes per second(每秒字节数)
-
是否为可压缩资源:是
[future]存储空间
-
名称:storage-space或者kubernetes.io/storage-space
-
单位:bytes
-
是否为可压缩资源: 否
[future]存储时间
-
名称:storage-time或者kubernetes.io/storage-time
-
单位:seconds per second of disk time(每次硬盘时间的秒数)
-
内部表示:milli-units
-
是否为可压缩资源:是
[future]存储操作
-
名称:storage-iops或者kubernetes.io/storage-iops
-
单位:operations per second
-
是否为可压缩资源:是
3
Node维度的计算资源
A
Node上资源划分划分
Node上除了运行Kubernetes创建的容器,还要运行操作系统和一些默认的守护进程,例如Docker daemon和Kubelet daemon等,"Capacity"不能代表 Kubernetes可以使用计算资源的全部,这就引入了一个新的问题,Kubernetes如何划分Node上的计算资源分配。
如下图所示,Kubernetes将Node上的计算资源分为三大块:
其中:
-
System-Reserved : 系统保留的计算资源,不能被Kubernetes调度和使用,它负责/system下所有进程的资源请求。
-
Kube-Reserved : Kubernetes为docker,kubelet,kube-proxy等保留的计算资源,这部分保证Kubernetes正常工作。
-
Kubelet Allocatable : 能够被Kubernetes调度和使用的计算资源,它的计算方法为:
[Allocatable] = [Node Capacity] - [Kube-Reserved] - [System-Reserved]
Scheduler将使用Allocatable替代Capacity作为调度的依据,kubelet也会根据Allocatable进行接纳检查。
用户可以设置Kube-Reserved使用的计算资源,在kubelet的启动选项中指定:
--kube-reserved=cpu=500m,memory=500Mi
目前,Kube-Reserved只支持CPU和Memory两种资源,未来会支持更多的资源类型,比如硬盘。如果Kube-Reserved没有设置,那么它 默认是0,System-Reserved如果不设置,也默认为零,这中情况下 Allocatable == Capacity
,Scheduler会按照Capacity进行调度。
Kube-Reserved的设定不仅仅是为了保证kubelet等组件正常运行,还有限定kubelet使用资源的用意。在某些情况下,用户会使用第三方的资源调度组件, 比如Mesos,hadoop...等,它们会划分自己的资源范围,这样kubelet和第三方组件可以互不干扰的运行。
System-Reserved默认是Kube-Reserved的值一致,如果Kube-Reserved没有设置,它们默认都为0.
在某些场景下,Kubernetes会出现自相矛盾的状况:Scheduler经过调度算法筛选,将Pod与某个Node绑定,该Node上Kubelet发现自身的资源不能满足Pod的需求,会拒绝运行这个Pod, Scheduler和Kubelet会出现循环依赖的问题,造成Pod永远调度不成功。
Kubernetes(1.3以后)使用"两阶段"的调度策略解决这个问题, 它调度过程分为两个阶段,第一阶段是Schedule经过筛选,选出一些符合的Node,Node根据自身的Capacity对Pod资源请求进行检查,如果满足需求则第一阶段完成,如果不能满足, 会告诉Scheduler将Pod调度到其他Node;第二阶段,Kubelet会根据Node上的Allocatable再次检查是否能够满足Pod的资源请求,如果满足,Scheduler与Kubelet达成共识, Pod会被调度在该Node上,否则,Scheduler会跟其他的Node重复这个过程,直到Pod被成功调度。
B
资源调度与碎片
Node节点经过一段时间的运行,从整体上看计算资源会分成四个区域,如下图所示:
A区域用于Scheduler调度新的Pod,但是A区域是不连续空间,整个节点上会形成很多碎片,就像下图所示:
这时,Node A和Node B不能被Schedule调度资源请求比较大Pod,如果集群中所有的节点都产生碎片后,那么资源请求量大的Pod永远会处于Pending状态, 应用发布过程会失败。
我们来假设一个场景: 所有Pod的request总量有小于所有Node提供的Capacity总量的时候,说明计算资源充足,但是,这是集群中出现了大量"Pending"的Pod,我们将如何处置?
显而易见的方式就是对Node上的计算资源进行重排,理想的情况,经过重排Node A和Node B的资源使用如下图-5所示:
C
碎片整理与重新平衡
Kubernetes集群运行一段时间后,每个Node上产生碎片是必然的,这个问题很难只通过优化Scheduler的调度算法来解决,当然,优化Scheduler算法是必须要做的, 从解决碎片的角度,在合适的时间,对计算做Rebalance,或者在一些Node宕机、升级、重启时发起一定范围的Rescheduler是个明智的选择。
在单一的Kubernetes集群上存在碎片的问题,多Kubernetes集群或者Kubernetes联邦也存在这个问题,什么最优的调度策略,合适触发rebalance和reschedule,目前还有 理论的指导,再加上每个公司的业务特点,很难找到"最优"的解决方案。
实际生产环境中,基础设施的高可用和保证业务稳定运行比提高资源利用率重要的多,即使我们做资源的重新排列,那也是在保证业务稳定性不受影响的情况下进行。 Rebalance是每个Kubernetes的使用者应该考虑和研究的问题,一定程"度"的碎片整理也是业务稳定运行的保证。
注:我们会在本系列(下)篇文章中重点介绍Rescheduler的场景和Rebalance的策略。
3
参考文献及致谢
参考文献:
- 《Everything You Ever Wanted to Know About Resource Scheduling But Were Afraid to Ask》,Tim Hockin,Google, KubeCon Seattle 2016
-
http://doc.kubernetes.cn/docs/concepts/policy/resource-quotas/
-
https://github.com/kubernetes/community/blob/d1160c0c58e45ca980fa0953d3504dcbf7e3f3c9/contributors/design-proposals/resources.md
-
https://github.com/kubernetes/community/blob/d1160c0c58e45ca980fa0953d3504dcbf7e3f3c9/contributors/design-proposals/resource-qos.md
4
加入容器时代
容器时代公众号的目的是希望能够传播容器技术和理念,让更多的人能够享受到这场技术革命带来的好处。虽然我们不是大牛,对容器技术生态的了解和认识也还不够深刻,但是我们乐于分享,乐于交流。不管读者的你是学生,还是工程师,甚至都不是,我们都欢迎你加入进来,可以一起写文章、翻译文章,也可以一起分享经验、聊聊踩过的那些坑!为此特意建立了一个微信群,长按识别下方二维码加入,我们以梦为马,一起前行!
5
架构真经
《架构真经:互联网技术架构的设计原则(原书第2版)》 即将震撼上市,关注容器时代公众号可以 有机会获得 亲笔签名 图书,赶快关注 吧 !!
版权声明:任何转载需全文转载并保留来源(微信公众号容器时代),同时转载容器时代的二维码,否则视作侵权。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- YARN资源调度策略
- kubernetes Pod 资源调度
- Hadoop YRAN 资源调度器
- 分布式资源调度——YARN框架
- haproxy高可用实现 和 动静资源的调度分离
- 京东万台规模Hadoop集群 | 分布式资源管理与作业调度
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
ActionScript 3.0 Cookbook中文版
Joey Lott、Adobe Dev Library / 陈建勋 / 电子工业 / 2007-11-01 / 78.00元
本书讨论了在Flash Player里执行的ActionScript3.0语言,采用问题—解法—讨论的形式讲解开发过程中常见问题的实际解法,例如:检测用户的 Flash Player 版本或操作系统;格式化日期和货币类型;接受用户输入及操作文字字符串;在运行时绘制各种形状;访问音频和视频;使用 Flash Remoting 进行远程过程调用;加载、发送和检索 XML 数据等。 全书涵盖客户端......一起来看看 《ActionScript 3.0 Cookbook中文版》 这本书的介绍吧!