Author:rab
Kubernetes 中的 Affinity(亲和性)和 AntiAffinity(反亲和性)是用于 Pod 调度的关键概念,它们允许我们控制 Pod 在集群中的分布以满足不同的需求。这些概念分为两类:NodeAffinity
(节点亲和性)和PodAffinity
(Pod亲和性),以及它们的反对应概念,NodeAntiAffinity
(节点反亲和性)和PodAntiAffinity
(Pod反亲和性)。
首先我们要明白:Kubernetes 中的调度策略可以大致分为两种:
接下来,我们将对 Affinity 与 AntiAffinity 分别进行案例分析。
1、功能
NodeAffinity
允许我们定义 Pod 应该调度到具有特定节点标签或标签选择器匹配的节点上。通过使用 requiredDuringSchedulingIgnoredDuringExecution
和 preferredDuringSchedulingIgnoredDuringExecution
字段,我们可以设置节点亲和性规则,要求或首选 Pod 与特定节点条件匹配。通常用于确保 Pod 在特定类型的节点上运行,以满足硬件、软件或其他特定的要求。
2、案例(片段)
...
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "gpu"
operator: In
values:
- "true"
...
因此,定义节点亲和性规则有 2 种:硬亲和性(Hard Node Affinity)和软亲和性(Soft Node Affinity)。
requiredDuringSchedulingIgnoredDuringExecution
;preferredDuringSchedulingIgnoredDuringExecution
。接下来分别看看这两种亲和性的具体应用。
1、功能
硬亲和性是一种强制性规则,要求 Pod 只能在满足特定条件的节点上运行。如果硬亲和性规则不满足,Pod 将不被调度,这意味着 Pod 可能无法运行。硬亲和性适用于需要绝对满足特定硬件或软件要求的情况,例如只在带有 GPU 的节点上运行。
2、案例
apiVersion: apps/v1
kind: Deployment
metadata:
name: hard-affinity-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "gpu"
operator: In
values:
- "true"
containers:
- name: my-container
image: my-image:latest
在这个示例中,我们创建了一个名为 hard-affinity-deployment
的 Deployment 对象。在 Pod 模板中,我们设置了硬亲和性规则,要求 Pod 只能在带有 “gpu=true” 标签的节点上运行,如果没有满足此条件的节点可用,Pod将无法被调度。
这里需要注意的是:在 Pod 资源基于节点亲和性规则调度到某个节点之后,如果节点的标签发生了改变,调度器不会将 Pod对象从该节点上移除,因为该规则仅对新建的Pod对象有效。
1、功能
软亲和性是一种容忍性规则,它提供了一个首选条件,但不强制要求 Pod 在特定条件下运行。如果条件不满足,Pod 仍然可以被调度到不满足条件的节点上(但它会优先考虑满足条件的节点)。软亲和性适用于需要首选条件,但允许有一定的灵活性的情况。它可以用于提高性能或可用性,但不会阻止 Pod 的调度。
2、案例
apiVersion: apps/v1
kind: Deployment
metadata:
name: soft-affinity-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: "rack"
operator: In
values:
- "rack-1"
weight: 50
containers:
- name: my-container
image: my-image:latest
在这个示例中,我们创建了一个名为 soft-affinity-deployment
的 Deployment。在 Pod 模板中,我们设置了软亲和性规则,优先在带有 “rack=rack-1” 标签的节点上运行(且权重为 50,数值越大则权重越高,则越优先匹配)。如果没有满足此条件的节点可用,Pod 仍然可以被调度到其他节点上,但它会优先考虑满足条件的节点。
那 Node 软硬亲和性是否可以结合使用呢?
答案是可以的
,我们可以将上面的两个案例联合起来,具体 yaml 文件如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: combined-affinity-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "gpu"
operator: In
values:
- "true"
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: "rack"
operator: In
values:
- "rack-1"
weight: 50
containers:
- name: my-container
image: my-image:latest
我们设置了硬亲和性规则和软亲和性规则:
这个示例演示了如何同时使用硬亲和性和软亲和性规则,以控制 Pod 的调度行为,确保它们在满足硬性要求的节点上运行,并在有多个选择时优先考虑软亲和性要求(从而避免了 Pod 无法调度的问题)。这种配置可以用于更复杂的调度策略,以满足不同的需求。
1、功能
NodeAntiAffinity
允许我们定义 Pod 不应该调度到带有特定节点标签或标签选择器匹配的节点上。通常用于提高容错性,防止相同应用的多个实例在同一节点上运行。应用也很简单,将 yaml 文件中的 nodeAffinity
改为 nodeAntiAffinity
即可,这里不再演示。通常用于提高容错性,防止相同应用的多个实例在同一节点上运行。
2、案例(片段)
...
affinity:
nodeAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "app"
operator: In
values:
- "my-app"
...
1、功能
PodAffinity
允许我们定义 Pod 应该一起调度在相同节点上的规则。同样通过使用 requiredDuringSchedulingIgnoredDuringExecution
和 preferredDuringSchedulingIgnoredDuringExecution
字段,我们可以设置 Pod 亲和性规则,要求或首选 Pod 与其他具有特定标签的 Pod 一起调度。通常用于确保相关的服务或应用实例在相同节点上运行,以减少网络延迟或提高性能。
2、案例(片段)
...
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "gpu"
operator: In
values:
- "true"
...
因此,与 Node 亲和性一样,Pod 亲和性也分为硬性
和软性
。
1、首先我们要定义一些我们即将规划用于部署服务的 Node 标签
为什么要给节点定义标签?
原因:为了组建拓扑域,让满足要求的 Pod 被调度到你指定的拓扑域节点中。
# node1 节点
kubectl label nodes k8s-node01 zone=www
kubectl label nodes k8s-node01 disk=ssd
# node2 节点
kubectl label nodes k8s-node02 zone=www
kubectl label nodes k8s-node02 disk=hdd
# node3 节点
kubectl label nodes k8s-node03 zone=www-test
kubectl label nodes k8s-node03 disk=hdd
...
2、定义 Pod 亲和性
apiVersion: apps/v1
kind: Deployment
metadata:
name: hard-affinity-pod
spec:
replicas: 3
selector:
matchLabels:
app: hard-affinity-pod
template:
metadata:
labels:
app: hard-affinity-pod
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- hard-affinity-pod
topologyKey: "zone"
containers:
- name: my-container
image: my-image
ports:
- containerPort: 80
这里说一下上面案例中 topologyKey
字段:这里会涉及到拓扑域(Topology Domain)
的概念。
topologyKey 是亲和性和反亲和性中的一个关键字段,用于定义节点的拓扑域(Topology Domain)。拓扑域是指 Kubernetes 集群中的节点分组,可以根据节点的标签或其他属性进行定义。常见的拓扑域包括节点所在的区域(Region)、可用区(Availability Zone)或机架(Rack)等。
说白了,若多个 Node 节点具有相同的标签信息(即 Node 节点标签键/值均相同),则表示这些 Node 节点就在同一拓扑域。
因此,在上述示例中,我们定义了一个 Deployment 资源,其中 Pod 具有硬亲和性。并指定了拓扑域为 zone
,这意味着只有满足 Pod 标签为 app: hard-affinity-pod
的 Pod 才会被调度到 zone
域中的节点上(不满足要求则无法调度)。那 zone
域中有哪些节点呢?我们说了,根据 Node 节点标签来划分,很明显,zone
域中的节点有 k8s-node01
和 k8s-node02
。
apiVersion: apps/v1
kind: Deployment
metadata:
name: soft-affinity-pod
spec:
replicas: 3
selector:
matchLabels:
app: soft-affinity-pod
template:
metadata:
labels:
app: soft-affinity-pod
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- soft-affinity-pod
topologyKey: "disk"
containers:
- name: my-container
image: my-image
ports:
- containerPort: 80
与 Node 软亲和性类似,满足 Pod 标签为 app: hard-affinity-pod
的 Pod 会优先被调度到 disk
域中的节点上,如果发现没有满足的条件,依然可正常部署与其他节点上。
1、功能
PodAntiAffinity
允许我们定义 Pod 不应该一起调度在相同节点上的规则,即要求或首选 Pod 不与其他具有特定标签的 Pod 一起调度。通常用于提高容错性,防止相同应用的不同实例在同一节点上运行。
2、案例(片段)
...
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- "my-app"
topologyKey: "kubernetes.io/hostname"
...
—END