亲和性
- https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
- https://kuboard.cn/learning/k8s-intermediate/config/affinity.html#%E8%8A%82%E7%82%B9%E4%BA%B2%E5%92%8C%E6%80%A7
你可以约束 pod 只能或倾向于 在哪些节点上面运行。有好几种方法可以达到此效果,推荐使用的 标签选择器 来进行选择。
1. nodeSelector⚓
nodeSelector
是推荐的最简单的节点选择约束形式。它是 PodSpec 的一个字段。要使 pod 有资格在一个节点上运行,该节点必须有每个指定的键值对作为标签(它还可以有其他标签)。
1.向节点附加标签
kubectl label nodes <node-name> <label-key>=<label-value>
2.向 pod 添加 nodeSelector 部分
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
2. 节点 隔离/限制(Node isolation/restriction)⚓
当你使用 nodeSelector 时,在某些情况下 kubelet 可能会改变节点的标签值,从而导致意外的结果。现在你可以使用 NodeRestriction
插件来禁止 kubelet 修改带有 node-restriction.kubernetes.io/
前缀的标签:
- 确保你使用了 Node authorizer ,并且启用了 NodeRestriction admission plugin。
- 在 node 与 pod 中使用带有
node-restriction.kubernetes.io/
前缀的标签。例如example.com.node-restriction.kubernetes.io/fips=true
。
3. 亲和性与反亲和性⚓
nodeSelector
提供了一种将 pod 约束到特定节点的方法,亲和性与反亲和性
(affinity/anti-affinity)则功能极大地扩展了可以表达的约束类型。关键的增强是:
affinity/anti-affinity
语法更富有表达力。语法不只有“与”操作;- 可以将规则声明为 “软”/“偏好” 的,而不是硬性要求;
- 可以根据在节点上面运行的其它 pod 的标签来约束 pod,而不是只根据自身的标签,这可以让一些 pod 要/不要 共处一地。
根据上述的描述,亲和性功能包含两个部分:
- pod 与 node 间的亲和性(node affinity);
- pods 之间的亲和性(inter-pod affinity)。
3.1 node affinity⚓
节点亲和性与 nodeSelector
类似,通过 node 的标签来约束 pod。
当前(v1.18)版本有两中类型的 node affinity :
requiredDuringSchedulingIgnoredDuringExecution
:硬性要求,但是比nodeSelector
有更多的语法。preferredDuringSchedulingIgnoredDuringExecution
:偏好要求。
在 PodSpec 中的 affinity
下的 nodeAffinity
下面定义 node affinity ,例子:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/pause:2.0
这个规则定义了:该 pod 只能在带有 key=kubernetes.io/e2e-az-name
且 value
是 e2e-az1
或 e2e-az2
的node上面运行。另外,在满足这些约束的 nodes 中,偏向选择那个 key=another-node-label-key
且 value=another-node-label-value
的那个节点。
操作符(operator)有以下几种:
In
NotIn
Exists
DoesNotExist
Gt
Lt
可以使用NotIn
与DoesNotExist
来表达 反亲和性。
下面有几点要注意的地方:
- 若同时指定了
nodeSelector
与nodeAffinity
,则两者都要满足; - 若在
nodeAffinity
下面指定了多个nodeSelectorTerms
,若 node 满足任意一个nodeSelectorTerms
,那么 pod 可以被调度; - 若在
nodeSelectorTerms
下面指定了多个matchExpressions
,则 node 必须满足所有的matchExpressions
, pod 才可以被调度; - 亲和性功能只适用于 pod 被调度的时候,在调度完成之后不会被驱逐。
preferredDuringSchedulingIgnoredDuringExecution
下的 weight
字段的范围是 1~100。
3.2 Inter-pod affinity and anti-affinity⚓
规则的形式是 “如果 X 已经运行了一个或多个满足规则 Y 的 pod,那么这个 pod 应该(或者,在反亲和性的情况下,不应该)运行在一个 X 中”。
Y 表示为 labelSelector
,并带有一个可选的命名空间关联列表;与节点不同,因为 pod 是属于命名空间的(因此 pod 上的标签是隐式命名空间的),所以 pod 标签上的标签选择器必须指定选择器应该应用于哪些名称空间。
从概念上讲,X 是一个拓扑域,例如节点,机架,云提供商区域等。可以使用 topologyKey
来表示它,它是系统用来表示这种拓扑域的节点标签的键。
与节点亲和性一样,当前(v1.18)版本有两中类型的 inter-pod affinity :
requiredDuringSchedulingIgnoredDuringExecution
:硬性要求。preferredDuringSchedulingIgnoredDuringExecution
:偏好要求。
表达的意思也是类似的,不再赘述。
在 PodSpec 中的 affinity
下面:
podAffinity
表示亲和性podAntiAffinity
表示反亲和性
例子:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: failure-domain.beta.kubernetes.io/zone
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
该 pod 只能运行在含有 failure-domain.beta.kubernetes.io/zone
标签的 node (且该 node 上有符合规则的 pod )的上面。
操作符(operator)有以下几种:
In
NotIn
Exists
DoesNotExist
理论上讲, topologyKey
可以是任何合法的 标签键,但是为了性能和安全着想,下面有几条约束:
- 不允许为空
- 对于 pod 反亲和性的
requiredDuringSchedulingIgnoredDuringExecution
,可以引入 admission 控制器LimitPodHardAntiAffinityTopology
来限制topologyKey
到kubernetes.io/hostname
。
上面说到 pod 之间的亲和性需要指定 命名空间,命名空间列表位于配置文件中与 labelSelector
and topologyKey
同级别的位置,若为空或没有指定,那么是该 pod 的命名空间。
所有与requiredDuringSchedulingIgnoredDuringExecution
关联的matchExpressions
都必须同时满足。
4. nodeName⚓
nodeName
是最简单的节点选择约束了,但限制性很大:
- 若节点不存在,pod 不会运行,并且在某些情况下会被自动删除。
- 若节点没有足够的资源,pod 会失败并给出原因,例如 OutOfmemory or OutOfcpu。
- 云环境中的节点名称并不总是可预测或稳定的。
例子:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: kube-01