3 深入掌握Pod(4)
3.9 玩转Pod调度
kubernetes 上,在大多数情况下会通过RC、Deployment、DaemonSet、Job等控制器完成对一组Pod副本的创建、调度及全生命周期的自动控制任务。
副本控制器的阶段:
a). Replication Controller
早起的RC独立于所控制的Pod,并通过Label标签这个松耦合关联关系控制目标Pod实例的创建和销毁。
b). ReplicaSet
ReplicaSet进一步增强了RC标签选择器的灵活性。之前RC的标签选择器只能选择一个标签,而ReplicaSet拥有集合式的标签选择器,可以选择多个Pod标签。
c). Deployment
用于更加自动地完成Pod副本的部署、版本更新、回滚等功能
应用场景:
(1)NodeAffinity(节点亲和性设置)
- 如果NodeSelector选择的Label不存在或者不符合条件,比如这些目标节点此时宕机或者资源不足,该怎么办?
如果要选择多种合适的目标节点,比如SSD磁盘的节点或者超高速硬盘的节点,该怎么办?
(2)不同Pod之间的亲和性(Affinity)。
比如MySQL数据库与Redis中间件不能被调度到同一个目标节点上,或者两种不同的Pod必须被调度到同一个Node上,以实现本地文件共享或本地网络通信等特殊需求,这就是PodAffinity要解决的问题。
(3)有状态集群的调度。
- 对于ZooKeeper、Elasticsearch、MongoDB、Kafka等有状态集群。
a) 每个worker看起来相同,但是多有明确的、不变的唯一ID(主机名或IP地址),这些节点的启动和停止通常有严格的顺序
b) 由于集群需要持久化保存状态数据,所以集群中的Worker节点对应的Pod不管在哪个Node上恢复,都需要挂载原来的Volume,因此这些Pod还需要捆绑具体的PV。
针对这种复杂的需求,Kubernetes提供了StatefulSet这种特殊的副本控制器来解决问题,在Kubernetes 1.9版本发布后,StatefulSet才可用于正式生产环境中。
(4)在每个Node上调度并且仅仅创建一个Pod副本。
这种调度通常用于系统监控相关的Pod,比如主机上的日志采集、主机性能采集等进程需要被部署到集群中的每个节点,并且只能部署一个副本,这就是DaemonSet这种特殊Pod副本控制器所解决的问题。
(5)对于批处理作业,需要创建多个Pod副本来协同工作,当这些Pod副本都完成自己的任务时,整个批处理作业就结束了。这种Pod运行且仅运行一次的特殊调度,用常规的RC或者Deployment都无法解决,所以Kubernates引入了新的Pod调度控制器Job来解决问题,并继续延伸了定时作业的调度控制器CronJob。
3.9.1 Deployment或RC:全自动调度
Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。
除了使用系统自动调度算法完成一组Pod的部署,Kubernetes也提供了多种丰富的调度策略,用户只需在Pod的定义中使用NodeSelector、NodeAffinity、PodAffinity、Pod驱逐等更加细粒度的调度策略设置,就能完成对Pod的精准调度。下面对这些策略进行说明。
3.9.2 NodeSelector:定向调度
a. 对node进行打标
kubectl label nodes <node-name> <label-key>=<label-value>
b. pod使用nodeselector定向调度
image.png
如果我们指定了Pod的nodeSelector条件,且在集群中不存在包含相应标签的Node,则即使在集群中还有其他可供使用的Node,这个Pod也无法被成功调度。
NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法。
亲和性调度机制则极大扩展了Pod的调度能力,
- 主要的增强功能如下。
◎ 更具表达力(不仅仅是“符合全部”的简单情况)。
◎ 可以使用软限制、优先采用等限制方式,代替之前的硬限制,这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该Pod。
◎ 可以依据节点上正在运行的其他Pod的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述Pod之间的亲和或互斥关系。
NodeSelector将会继续使用,随着节点亲和性越来越能够表达nodeSelector的功能,最终NodeSelector会被废弃。
3.9.3 NodeAffinity:Node亲和性调度
image.png如上图:
Node 亲和性调度有两种,
一种是硬调度,固定满足条件才调度(如1), requiredDuringSchedulingIgnoredDuringExecution
另一种是软限制,优先级调度。(如2)
preferredDuringSchedulingIgnoredDuringExecution
注意:
NodeAffinity规则设置的注意事项如下。
◎ 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node上。
◎ 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中一个能够匹配成功即可。
◎ 如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod。
3.9.4 PodAffinity:Pod亲和与互斥调度策略
Pod亲和与互斥Pod 亲和与互斥调度策略:都采用如下两种
requiredDuringSchedulingIgnoredDuringExecution: 满足
preferredDuringSchedulingIgnoredDuringExecution: 优先
1. Pod 亲和性调度策略:
上图 PodAffinity 是亲和性调度,第二个podAnticAffinity是互斥调度。
含义是: 在zone内,满足label: security in['S1'] 的允许调度
在hostname内, 满足app in ['nginx'] 的不允许调度。
即使在topologyKey是X label的node上,才允许(或拒绝)label 满足Y条件的Pod执行。
其中label 条件包括In、NotIn、Exists、DoesNotExist、Gt、Lt等。
topologyKey的限制
原则上,topologyKey可以使用任何合法的标签Key赋值,但是出于性能和安全方面的考虑,对topologyKey有如下限制。
◎ 在Pod亲和性和RequiredDuringScheduling的Pod互斥性的定义中,不允许使用空的topologyKey。
◎ 如果Admission controller包含了LimitPodHardAntiAffinityTopology,那么针对RequiredDuringScheduling的Pod互斥性定义就被限制为kubernetes.io/hostname,要使用自定义的topologyKey,就要改写或禁用该控制器。
◎ 在PreferredDuringScheduling类型的Pod互斥性定义中,空的topologyKey会被解释为kubernetes.io/hostname 、 failure-domain.beta.kubernetes.io/zone及failure-domain.beta.kubernetes.io/region的组合。
◎ 如果不是上述情况,就可以采用任意合法的topologyKey了。
podAffinity限制
PodAffinity规则设置的注意事项如下。
◎ 除了设置Label Selector和topologyKey,用户还可以指定Namespace列表来进行限制,同样,使用Label Selector对Namespace进行选择。Namespace的定义和Label Selector及topologyKey同级。省略Namespace的设置,表示使用定义了affinity/anti-affinity的Pod所在的Namespace。如果Namespace被设置为空值(""),则表示所有Namespace。
◎ 在所有关联requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都满足之后,系统才能将Pod调度到某个Node上。
3.9.5 Taints和Tolerations(污点和容忍)
Taints 是让Pod拒绝在该node上执行。
Tolerations 是指在Pod上配置,容忍Node上的Taints。从而能够在该node上执行。
在Node上设置一个或多个Taint之后,除非Pod明确声明能够容忍这些污点,否则无法在这些Node上运行。Toleration是Pod的属性,让Pod能够(注意,只是能够,而非必须)运行在标注了Taint的Node上。
针对Node的taints
kubectl taints nodes <nodename> <key>=<value>:NoSchedule
针对Pod的tolerations
tolerations:
- key : "key"
operator: "Equal"
value: "value"
effects: "NoSchedule"
tolerationSeconds: "300s" #如果在这个宽限期内Taint被移除,则不会触发驱逐事件。
或者
tolerations:
- key : "key"
operator: "Exists"
effects: "NoSchedule"
Pod的Toleration声明中的key和effect需要与Taint的设置保持一致,并且满足以下条件之一。
◎ operator的值是Exists(无须指定value)。
◎ operator的值是Equal并且value相等。如果不指定operator,则默认值为Equal。
另外,有如下两个特例。
◎ 空的key配合Exists操作符能够匹配所有的键和值。
◎ 空的effect匹配所有的effect。
effect的取值为NoSchedule,还可以取值为PreferNoSchedule,这个值的意思是优先,也可以算作NoSchedule的软限制版本——一个Pod如果没有声明容忍这个Taint,则系统会尽量避免把这个Pod调度到这一节点上,但不是强制的。
系统允许在同一个Node上设置多个Taint,也可以在Pod上设置多个Toleration。Kubernetes调度器处理多个Taint和Toleration的逻辑顺序为:
首先列出节点中所有的Taint,然后忽略Pod的Toleration能够匹配的部分,剩下的没有忽略的Taint就是对Pod的效果了。
下面是几种特殊情况。
◎ 如果在剩余的Taint中存在effect=NoSchedule,则调度器不会把该Pod调度到这一节点上。
◎ 如果在剩余的Taint中没有NoSchedule效果,但是有PreferNoSchedule效果,则调度器会尝试不把这个Pod指派给这个节点。
◎ 如果在剩余的Taint中有NoExecute效果,并且这个Pod已经在该节点上运行,则会被驱逐;如果没有在该节点上运行,则也不会再被调度到该节点上。
应用举例
Taint和Toleration是一种处理节点并且让Pod进行规避或者驱逐Pod的弹性处理方式。
1.独占节点
只有带有合适Toleration的Pod才会被允许同使用其他节点一样使用有Taint的节点。
2.具有特殊硬件设备的节点
在集群里可能有一小部分节点安装了特殊的硬件设备(如GPU芯片),用户自然会希望把不需要占用这类硬件的Pod排除在外,以确保对这类硬件有需求的Pod能够被顺利调度到这些节点。
3.定义Pod驱逐行为,以应对节点故障(为Alpha版本的功能)
!!! TODO
◎ 没有设置Toleration的Pod会被立刻驱逐。
◎ 配置了对应Toleration的Pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中。
◎ 配置了对应Toleration的Pod且指定了tolerationSeconds值,则会在指定时间后驱逐。
◎ Kubernetes从1.6版本开始引入一个Alpha版本的功能,即把节点故障标记为Taint(目前只针对node unreachable及node not ready,相应的NodeCondition "Ready"的值分别为Unknown和False)。激活TaintBasedEvictions功能后(在--feature-gates参数中加入TaintBasedEvictions=true),NodeController会自动为Node设置Taint,而在状态为Ready的Node上,之前设置过的普通驱逐逻辑将会被禁用。注意,在节点故障的情况下,为了保持现存的Pod驱逐的限速(rate-limiting)设置,系统将会以限速的模式逐步给Node设置Taint,这就能避免在一些特定情况下(比如Master暂时失联)大量的Pod被驱逐。这一功能兼容于tolerationSeconds,允许Pod定义节点故障时持续多久才被逐出。