K8s 亲和性和非亲和性(Affinity)
概念关于 K8S 对 Pod 的调度,通常情况下Pod被分配到哪些Node是不需要我们操心的,这个过程会由scheduler自动实现。但有时,我们需要让Pod按照我们的预想运行在Node上(例如某些应用 “必须/或者尽量” 跑在具有SSD存储的节点上,有些应用应该跑在同一个节点上等)。为此,k8s提供了这样的策略,我们可以通过使用 “亲和性/非亲和性” 制定一些规则来实现我们的需求。亲和性调度可以
概念
关于 K8S 对 Pod 的调度,通常情况下Pod被分配到哪些Node是不需要我们操心的,这个过程会由scheduler自动实现。但有时,我们需要让Pod按照我们的预想运行在Node上(例如某些应用 “必须/或者尽量” 跑在具有SSD存储的节点上,有些彼此相关的Pod应用应该跑在同一个节点上)。为此,k8s为我们提供了这样的策略,我们可以通过使用 “亲和性/非亲和性” 制定一些规则来实现我们的需求。
亲和性调度可以分成软策略和硬策略两种方式:
- 硬策略:可以理解为必须,就是如果没有满足条件的节点的话,就不断重试直到满足条件为止。对应的配置规则为
requiredDuringSchedulingIgnoredDuringExecution
。 - 软策略:可以理解为尽量,就是如果现在没有满足调度要求的节点的话,pod就会忽略这条规则,继续完成调度的过程,说白了就是满足条件最好了,没有的话也无所谓。对应的配置规则为
preferredDuringSchedulingIgnoredDuringExecution
。
亲和性的配置规则分为 Node亲和性、Pod亲和性、Pod反亲和性
:
- nodeAffinity :节点亲和性,用来控制 Pod 要部署在哪些节点上,以及不能部署在哪些节点上的,这个是
Pod 与 Node 之间
匹配规则的。 - podAffinity :pod 亲和性,这个是
Pod 与 Pod 之间
匹配规则的。 - podAntiAffinity :pod 反亲和性,与 podAffinity 相反。
- 这个亲和性看起来和一直使用的nodeSelector 作用比较重叠,但是你会发现它更的控制更为细致且概念更优。
据说官方将会在后续的版本中废除 nodeSelector,故建议大家使用使用亲和性策略。
- 节点亲和性相较于 nodeSelector 在调度方式上,有几点增强:① 更多的表达式支持,不仅仅是ADD和精确匹配;② 可以设置soft/preference的调度策略,而不是刚性的要求;③ 可以通过Pod的标签进行调度约束,不仅仅是Node的标签。
- podAffinity 处理 Pod 和 Pod 在一起的规则,podAntiAffinity 处理的是 Pod 和 Pod 不能在一起的规则。它俩处理的是Kubernetes集群内部Pod和Pod之间的关系。
- 所有规则终究还是以 Label 为元数据的。
AFFINITY SELECTOR | REQUIREMENTS MET | REQUIREMENTS NOT MET | REQUIREMENTS LOST |
---|---|---|---|
requiredDuringSchedulingIgnoredDuringExecution | Runs Fails | Keeps | Running |
preferredDuringSchedulingIgnoredDuringExecution | Runs Runs | Keeps | Running |
(un-implemented) requiredDuringSchedulingRequiredDuringExecution | Runs | Fails | Fails |
对于 label 的匹配规则,可选的操作符有:
操作符 | 规则说明 |
---|---|
In | label 的值在某个列表中 |
NotIn | label 的值不在某个列表中 |
Exists | 某个 label 存在 |
DoesNotExist | 某个 label 不存在 |
Gt | label 的值大于某个值(字符串比较) |
Lt | label 的值小于某个值(字符串比较) |
如果 nodeAffinity 中 nodeSelectorTerms 有多个选项,则节点满足任何一个条件就可以;
如果 matchExpressions 有多个选项,则只有同时满足这些逻辑选项的节点才能运行 Pod。
实例
- 我们一般通过 Deployment 和 DaemonSet 来部署 Pod,纯粹部署一个 Pod 的情况却不太常见。
- 在 Deployment 和 DaemonSet 的 yaml 中配置的 template 节点以下的内容,顾名思义就是其预部署的 Pod 的模板,在 template 节点这里配置的规则内容最终都会实际落实到具体 Pod 的 yaml 文件配置上。
- 所以,网上看到的一些关于亲和性的示例中
kind: Deployment
和kind: Pod
其实在具体规则上你可以认为是一样的。
apiVersion: apps/v1
kind: Deployment
metadata:
name: affinity-test
labels:
app: affinity-test
spec:
replicas: 8
selector:
matchLabels:
app: affinity-test
template:
metadata:
labels:
app: affinity-test
spec:
containers:
- name: nginx
image: nginx:1.20.2
ports:
- containerPort: 80
name: nginxweb
affinity:
nodeAffinity: # 作用域:Pod和Node之间
requiredDuringSchedulingIgnoredDuringExecution: # Node亲和性-硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node3
preferredDuringSchedulingIgnoredDuringExecution: # Node亲和性-软策略
- weight: 1
preference:
matchExpressions:
- key: customlabel
operator: In
values:
- weblb
podAffinity: # 作用域:Pod和Pod之间
requiredDuringSchedulingIgnoredDuringExecution: # Pod亲和性-硬策略
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- security1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity: # 作用域:Pod和Pod之间
preferredDuringSchedulingIgnoredDuringExecution: # Pod非亲和性-软策略
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- security2
topologyKey: kubernetes.io/hostname
调度域 topologyKey
原则上,topologyKey 可以是任何合法的标签密钥。 但是出于性能和安全性原因,topologyKey 受到以下一些限制:
- 对于亲和关系,以及pod反亲和的硬亲和条件requiredDuringSchedulingIgnoredDuringExecution时,topologyKey不允许为空;
- 由于准入控制器LimitPodHardAntiAffinityTopology的存在,如果计划在pod反亲和的requiredDuringSchedulingIgnoredDuringExecution中使用,则需要修改准入控制器或者直接禁用它;
- 对于pod反亲和中的软亲和:preferredDuringSchedulingIgnoredDuringExecution,如果没指定topologyKey的值,将会使用kubernetes.io/hostname, failure-domain.beta.kubernetes.io/zone和failure-domain.beta.kubernetes.io/region这三个内建的字段值;
- 除上述情况外,topologyKey可以是任何合法的标签密钥。
pod 亲和性调度需要各个相关的pod对象运行于 “同一位置”, 而反亲和性调度则要求他们不能运行于 “同一位置”。
这里指定 “同一位置” 是通过 topologyKey 来定义的,topologyKey 对应的值是 node 上的一个标签名称,比如各别节点 zone=A 标签,各别节点有 zone=B 标签,如果 pod Affinity topologyKey 定义为 zone,那么调度pod的时候就会围绕着A拓扑,B拓扑来调度,而相同拓扑下的node就为 “同一位置”。
如果基于各个节点 kubernetes.io/hostname
标签作为评判标准,那么很明显 “同一位置” 意味着同一节点,不同节点既为不同位置,一般用于:
- 我启动一个pod,希望(亲和性)或不希望(反亲和性)调度一台node上,并且这台node上有service=nginx 标签的 pod
- 我启动一个2个副本控制器,pod标签为 service=tomcat,可以调度到任意node上,不希望两个pod调度到同一个node上
所以,podAffinity
的调度范围为 topology,使用 topologyKey
关键字设定。
(END)
更多推荐
所有评论(0)