开发者学堂课程【企业级运维之云原生与 Kubernets 实战课程:Kubernetes 调度和资源管理 】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/913/detail/14505
Kubernetes 调度和资源管理
摘要:本小节主要内容为 Pod 调度和资源管理,包括 Pod 调度过程、资源源调度和关系调度、调度相关的配置和使用、K8s 组件控制器、SVC 创建及使用、Pod 生命周期管理及 Kubectl 常用命令和使用技巧。
目录
Ÿ Pod 调度过程
Ÿ 资源调度和关系调度
Ÿ 调度相关的配置和使用
Ÿ 优先调度
一、Pod 调度过程
调度过程是把 Pod 放到合适 Node 上:
Ÿ 满足 Pod 资源要求;
Ÿ 满足 Pod 的特殊关系要求;
Ÿ 满足 Node 限制条件要求;
Ÿ 做到集群资源合理利用;
Controllers 副本集控制器 Kube-Scheduler 调度组件,按照预定的调度策略,将Pod 调度到相应的机器上,Kubelet 负责维护容器的生命周期,同时也负责 Volume 和网络的管理。
使用 kubectl 或者在控制台创建 deployment 类型 Pod,向 Apiserver 发送请求,scheduler 监控到 Pod 调度请求后,如何调度呢?
Kubernetes 的默认调度过程
Ÿ 客户端向 api-server 发出控制器 ( deployment,statefulset,job,cronjob ) 创建请求,最终会转化为创建和调度 Pod;
Ÿ kube-scheduler 通过 api-server 获取还未调度的 Pod 列表,通过对应的筛选规则和算法循环遍历为每个 Pod 分配节点,筛选分为两阶段:
ž Predicate:过滤(预选)阶段,将所有节点混在一起,通过一定算法对匹配项进行匹配,将不合格的节点剔出去,留下合格的节点,如果此时没有筛选出合适的节点,则 Pod 会进入 pending 状态,不断重试调度,直到有合适节点为止;
ž Priority:优选阶段,对刚刚通过过滤阶段筛选出来的节点,通过权重和优先级进行计算得出一个最终得分,这个分值范围为(0-10),得分高的为最合适的调度节点。
Ÿ 选举得分最高的主机 binding,结果存储 etcd;
Ÿ 最终选举节点 kubelet 接收指令进行 Pod 的创建。
二、资源调度和关系调度
除了集群默认调度能力外,还有自定义调度,用户可以设置 Pod 的资源限额参数、亲和性、反亲和性、污点等,实现自定义调度策略,使 Pod 能够充分利用资源并且按照业务需求合理调度。
1. Kubernetes 基础调度能力
a. 资源调度:满足 Pod 资源要求
Ÿ Resources:CPU/Memory/Storage/GPU/FGPA (资源大小限制);
Ÿ QoS:Guaranteed/Burstable/BestEffort (服务质量要求);
Ÿ Resource Quota (配额限制);
b. 关系调度:满足 Pod/Node 的特殊关系/条件要求
Ÿ PodAffinity/PodAntiAffinity:Pod 和 Pod 间关系(亲和性和反亲和性);
Ÿ NodeSelector/NodeAffinity:由 Pod 决定适合自己的 Node (节点选择器);
Ÿ Taint/Tolerations:限制调度到某些 Node (污点限制);
如果未做过节点 nodeSelector,亲和性( node affinity ) 或 Pod 亲和、反亲和性 ( Pod affinity/anti-affinity ) 等 Pod 高级调度策略设置,则没有办法指定服务部署到指定节点上,可能会造成 CPU 或内存等密集型的 Pod 同时分配到相同 Node,造成资源竞争;另一方面,如果未对资源进行限制,一些关键的服务可能会因为资源竞争因 OOM (Out of Memory) 等原因被 kill 掉,或者被限制 CPU 使用。
a. Pod 的资源类型,可以对 cpu、内存、存储、gpu 资源的使用量进行限制
Ÿ Cpu
Ÿ Memory
Ÿ ephemeral-storage
Ÿ extended-resource:nvidia.com/gpu
b. 在应用的 container 标签下面增加 resource 标签,即可对 Pod 资源的使用量进行限制;
示例:
apiversion:v1
kind:Pod
metadata:
namespace:demo-ns
namedemo-pod
Spec:
containers:
- image:nginx:latest
name:demo-container
requests:
cpu:2
memory:1Gi
1imits:
cpu:2
memory:1Gi
如上 yaml 文件中,指明了容器信息及资源限制,requests 表示需要请求的资源大小,而 limits 表示容器限制资源的大小,如果容器内使用的内存超过了 limits 设置的内存大小,会发生 OOM(out of memory),导致容器重启;如果容器内 CPU使用超过了 limits 设置的 CPU 大小,并不会导致容器重启。
c. 如何判断请求的内存大小
Ÿ 通过执行命令 kubectl describe node xxx
(xxx为节点名),查看资源使用情况及请求资源统计。
2.如何满足 Pod 资源要求
a. 什么是 PodQoS?
Ÿ Quality of Service
Kubernetes 为了实现资源被有效调度和分配的同时提高资源利用率,Kubernetes针对不同服务质量的预期,通过 QoS (Quality of Service) 来对 Pod 进行服务质量管理,提供了采用 requests 和 limits 两种类型对资源进行分配和使用限制。
b. QoS 的三种类型:
Ÿ Guaranteed-高,保障( CPU/Memory 必须 request==limit ,其余资源可不等);
Ÿ Burstable-中,弹性( CPU/Memory request 和 limit 不相等);
Ÿ BestEffort-低,尽力而为(所有资源 request/limit 必须都不填);
c. 资源回收策略
Ÿ 当 kubernetes 集群中,某个节点上可用资源比较小时,kubernetes 提供了资源回收策略保证被调度到该节点 pod 服务正常运行。当节点上的内存或者 CPU 资源耗尽时,可能会造成该节点上正在运行的 pod 服务不稳定。
Ÿ Kubernetes 通过 kubelet 来进行回收策略控制,保证节点上 Pod 在节点点资源比较小时可以稳定运行。
d. QoS Pods 被 kill 掉场景与顺序
Ÿ Best-effort 类型的 Pods:系统用完了全部内存时,该类型 pods 会最先被 kill 掉;
Ÿ Burstable 类型 Pods:系统用完了全部内存,且没有 Best-Effort container 可以被kill时,该类型 Pods 会被 kill 掉;
Ÿ Guaranteed Pods:系统用完了全部内存,且没有 Burstable 与 Best-Effort container 可以被 kill,该类型的 Pods 会被 kill 掉;
注:如果 Pod 进程因使用超过预先设定的 limites ,而非 Node 资源紧张情况,系统倾向于在其原所在的机器上重启该 container 或本机或其他重新创建一个Pod。
e. ResourceQuota
作用:限制每个 Namespace 资源用量,如对 Pod 内存和 CPU 限制。
用法:
-pernamespace
-Scope
Terminating/NotTerminating BestEffort/NotBestEffort priorityClass
当 Quota 超限后会禁止创建:
-forbidden:exceeded quota
一个 namespace 下面可以创建多个 ResourceQuota( ResourceQuota 本身也可以限制 ResourceQuota 的数量),常规的使用是把计算资源 quota( cpu、mem 等),存储资源 quota( storage、pvc 等),对象数量 quota( Pod、service 等)分别创建在不同的 ResourceQuota 下面,但是各个 ResourceQuota 中的限制项是可以重复的,这时会取最小的值。
如下示例 yaml 文件中,限制 demo-ns Namespace 下非 BestEffort QoS 的Quota ,cpu 只能使用 1000 个、memory 只能使用 200 Gi、Pods 只能创建10个:
kind:ResourceQuota
metadata:
name:demo-quota
namespace:demo-ns
Spec:
hard:
cpu:"1000"
memory:200Gi
pods:"10"
scopeSelector:
#可以不填
matchExpressions:
- operator:Exists
scopeName: NotBestEffort
三. 调度相关的配置和使用
1. 如何满足 Pod 与 Pod 之间的关系要求?— Pod 亲和调度
a. Pod 亲和调度 PodAffinity
Ÿ 必须和某些 Pod 调度到一起
requiredDuringSchedulinglgnoredDuringExecution
Ÿ 优先和某些 Pod 调度到一起
preferredDuringSchedulinglgnoredDuringExecution
b. Pod 反亲和调度 PodAntiAffinity
Ÿ 禁止和某些Pod调度到一起
requiredDuringSchedulingIgnoredDuringExecution
Ÿ 优先不和某些 Pod 调度到一起
preferredDuringSchedulinglgnoredDuringExecution
c. Operator
Ÿ In/NotIn/Exists/DoesNotExist
d. nodeSelector 标签选择器
Ÿ 节点选择约束的最简单推荐形式。可以将 nodeSelector 字段添加到 Pod 的规约中设置你希望目标节点所具有的节点标签。Kubernetes 只会将 Pod 调度到指定的每个标签的节点上。
如下示例中,标签的 Key 为 disktype,Value 为 ssd。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
必须调度到带了 K1=V1 标签的 Pod 所在节点:
apiversion:vl
kind:Pod
metadata:
namespace:demo-ns
name:demo-pod
spec:
containers:
- image: nginx:1atest
name:demo-container
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:matchExpressions:
- key:k1
operator:In
values:
- vl
topologykey:"kubernetes.io/hostname"
禁止调度到带了 K1=V1 标签的 Pod 所在节点:
apiversion:vl
kind:Pod
metadata:
namespace:demo-ns
name:demo-pod
spec:
containers:
- image: nginx:1atest
name:demo-container
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- 1abelSelector:
matchExpressions:
- key:kl
operator:In
values:
- v1
topologykey:"kubernetes.io/hostname"
2. 如何满足 Pod 与 Pod 之间的关系要求?—Node 亲和调度
a. 节点污点 Node Taints
Ÿ 一个 Node 可以有多个 Taints
Ÿ Effect (不能为空)
ž NoSchedule:只是禁止新 Pods 调度上来;
ž PreferNoSchedule:尽量不调度到这台;
ž NoExecute:会驱逐没有对应 toleration 的 Pods ,并且也不会调度新的上来;
b. Pod Tolerations
Ÿ 一个 Pod 可以有多个 Tolerations
Ÿ Effect 可以为空,匹配所有
ž 取值和 Taints 的 Effect 一致
Ÿ Operator
ž Exists/Equal
示例:
Node 上带了 K1=V1 且效果是 NoSchedule 的 Taints:
apiversion:vl
Kind:Node
metadata:
name:demo-node
spec:
taints:
- key:"k1"
value:"v1"
effect:"Noschedule"
Pod 上必须带有 K1=V1 且效果是 NoSchedule 的 Tolerations:
apiversion:v1
kind:Pod
metadata:
namespace:demo-name
spec:
containers:
image:nginx=latest
name:demo-container
tolerations:
-key:"k1"
operatorEqual"
value:"v1"
#当 op=Exists 可为空
effect:"Noschedule"
#可以为空,匹配所有
四、集群资源优先级调度
1. 集群资源不够时怎么办?
Ÿ 先到先得策略( FIFO ):简单、相对公平、上手快;
Ÿ 优先级策略( Priority ):符合日常公司业务特点;
优先级和抢占机制,解决的是 Pod 调度失败时该怎么办的问题。正常情况下,当一个 Pod 调度失败后,它就会被暂时“搁置”起来,直到 Pod 被更新,或者集群状态发生变化,调度器才会对这个 Pod 进行重新调度。
2. 特殊要求的场景:
Ÿ 当一个高优先级的 Pod 调度失败后,该 Pod 并不会被“搁置”,而是会“挤走”某个 Node 上的一些低优先级的 Pod,这样就保证这个高优先级 Pod 的调度成功;
Ÿ 如何使用优先级调度呢?需要创建一个 priorityClass 资源,然后再为每个 Pod 应用指定不同的 priorityClassName ,这样就完成了优先级以及优先级调度的配置。
3. 优先级调度的配置
Ÿ 创建 PriorityClass 优先级资源,声明优先级大小;
Ÿ 为各个 Pod 应用指定不同的 priorityClassName;
Ÿ 内置默认优先级:DefaultPriorityWhenNoDefaultClassExists=0
Ÿ 用户可配置的最大优先级限制 HighestUserDefinablePriority=1000000000
Ÿ 系统级别优先级 SystemCriticalPriority=2000000000
Ÿ 内置系统级别优先级 system-cluster-critical
、system-node-critical
示例:
Ÿ 创建一个名为 high 的 priorityClass,得分为 10000,示例如下:
apiversion:scheduiing.K8s.io/v1
kind:Priorityclass
metadata:
name:high
value:10000
galobalDefault:false
Ÿ 创建一个名为 low 的 priorityClass,得分为100,示例如下:
apiversion:scheduling.k8s.io/v1
kind:Priorityclass
metadata:
name:low
value=100
g1oba1Default:false