将 Pod 约束在特定的节点上可以使用 nodeSelect 对节点进行标签选择。 但是调度器通常会合理的调度 Pod 到合适的节点,所以除了使用 nodeSelect 进行强制约束外,还可以使用亲和性和反亲和性以及污点和容忍度进行指派 Pod。
nodeSelect nodeSelect 依赖于节点标签,所以首先需要对节点添加上标签。
查看集群节点上所有的标签:
1 2 3 4 5 [vagrant@master01 ~]$ kubectl get nodes --show-labels NAME STATUS ROLES AGE VERSION LABELS master01.example.com Ready control-plane 41d v1.29 .1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master01.example.com,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from -external-load-balancers=,role=ceph worker01.example.com Ready edge 40d v1.29 .1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker01.example.com,kubernetes.io/os=linux,node-role.kubernetes.io/edge=,role=ceph worker02.example.com Ready <none> 40d v1.29 .1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker02.example.com,kubernetes.io/os=linux,role=ceph
为特定的节点添加标签:
1 2 3 4 5 [vagrant@master01 ~]$ kubectl label nodes worker01.example.com env=qa node/worker01.example.com labeled [vagrant@master01 ~]$ kubectl get nodes -l env=qa NAME STATUS ROLES AGE VERSION worker01.example.com Ready edge 40d v1.29 .1
移除 label:
1 2 3 4 [vagrant@master01 ~]$ kubectl label node worker01.example.com env- node/worker01.example.com unlabeled [vagrant@master01 ~]$ kubectl get nodes -l env=qa No resources found
将 Pod 调度到指定的标签的节点上:
1 2 3 4 5 6 7 8 9 10 11 12 13 apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent nodeSelector: env: qa
验证 Pod 已经调度到了 worker01 :
1 2 3 4 5 6 7 [vagrant@master01 ~]$ kubectl get pods/nginx -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx 1 /1 Running 0 59s 10.244 .95 .132 worker01.example.com <none> <none> [vagrant@master01 ~]$ kubectl get nodes -l env=qa NAME STATUS ROLES AGE VERSION worker01.example.com Ready edge 40d v1.29 .1
亲和性和反亲和性 亲和性和反亲和性分为两种:节点亲和性 Pod 之间的亲和性和反亲和性。
节点亲和性 nodeSelector 只能选择拥有所指定标签的节点,可以标明规则是偏好或者软需求,在调度器无法找到匹配的节点时,仍然能够调度该 Pod(nodeSelector 就不行)。
节点亲和性有两种:
requiredDuringSchedulingIgnoredDuringExecution:调度器只有满足规则时才能执行调度。
preferredDuringSchedulingIgnoredDuringExecution:调度器首先寻找满足规则的节点,如果找不到,调度器仍然会执行调度。
IgnoredDuringExecution 代表 Pod 调度到节点后,节点的标签发生了变化,Pod 依旧运行在该节点上。
首先为节点添加标签:
1 2 3 4 5 6 7 [vagrant@master01 ~]$ kubectl label node worker02.example.com node-role.kubernetes.io/worker= node/worker02.example.com labeled [vagrant@master01 ~]$ kubectl get nodes NAME STATUS ROLES AGE VERSION master01.example.com Ready control-plane 41d v1.29 .1 worker01.example.com Ready edge 40d v1.29 .1 worker02.example.com Ready worker 40d v1.29 .1
部署 Pod,并使用亲和性约束:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apiVersion: v1 kind: Pod metadata: name: with -node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: node-role.kubernetes.io/worker operator: Exists preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: env operator: In values: - prod containers: - name: with -node-affinity image: registry.k8s.io/pause:2.0
验证:
1 2 [vagrant@master01 ~]$ kubectl get pods -o wide | grep with -node-affinity with -node-affinity 1 /1 Running 0 32s 10.244 .45 .238 worker02.example.com <none> <none>
虽然 worker02 上没有 env=prod 标签,但还是调度在该节点上了:
1 2 3 4 5 [vagrant@master01 ~]$ kubectl get nodes -l node-role.kubernetes.io/worker NAME STATUS ROLES AGE VERSION worker02.example.com Ready worker 40d v1.29 .1 [vagrant@master01 ~]$ kubectl get nodes -l env=prod No resources found
operator 除了使用 Exists 来验证是否存在的逻辑之外,还可以使用 In 、NotIn 、DoesNotExist 、Gt 和 Lt 之一作为逻辑操作符。 如果使用非 Exist ,需要提供 values 字段来提供逻辑判断的值,例如:
1 2 3 4 5 6 preference: matchExpressions: - key: another-node-label-key operator: In values: - another-node-label-value
节点亲和性可以通过 weight 来定义权重,这个适用于多个规则进行筛选时,满足规则且权重高的节点将被调度。
Pod 间亲和性和反亲和性 调度器在调度 Pod 时,除了有节点的亲和性,还有 Pod 间亲和性和反亲和性。
节点亲和性是基于节点的标签,Pod 间的亲和性和反亲和性是基于当前运行在节点上的 Pod 的标签。
Pod 的亲和性和反亲和性也有两种类型:
requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
在 Pod 亲和性中可以使用 requiredDuringSchedulingIgnoredDuringExecution 来约束两个服务的 Pod 应该放到同一位置,可能是因为它们通信非常频繁。 在 Pod 反亲和性中可以使用 preferredDuringSchedulingIgnoredDuringExecution 来阻止同一个服务的 Pod 放置在同一个位置,避免出现单点故障。
Pod 间亲和性和反亲和性的规则格式为:如果 X 上已经运行了一个或多个满足规则 Y 的 Pod,则这个 Pod 应该运行在 X 上(反亲和性的话就是不应该)。 X 可以是节点、机架、云提供商可用区等类似的拓扑愈,Y 是 Kubernetes 尝试满足的规则。
Pod 亲和性使用 .affinity.podAffinity 字段,Pod 反亲和性使用 .affinity.podAntiAffinity 字段。
参考示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 apiVersion: v1 kind: Pod metadata: name: with -pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: topology.kubernetes.io/zone podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S2 topologyKey: topology.kubernetes.io/zone containers: - name: with -pod-affinity image: registry.k8s.io/pause:2.0
上述例子中,调度器首先会找到有 zone 标签的节点,因为没有指定 zone 的值,所以只判断是否存在该标签,如果该节点上运行了一个带有 security=S1 的标签的 Pod,则会调度到该节点,如果该节点上运行了一个带有 security=s2 的标签,则不会调度到该节点。
测试一下,首先需要在 node 上打上标签:
1 2 3 4 5 6 7 8 [vagrant@master01 ~]$ kubectl label node worker01.example.com zone=cn-1 node/worker01.example.com labeled [vagrant@master01 ~]$ kubectl label node worker02.example.com zone=cn-2 node/worker02.example.com labeled [vagrant@master01 ~]$ kubectl get nodes -l zone NAME STATUS ROLES AGE VERSION worker01.example.com Ready edge 41d v1.29 .1 worker02.example.com Ready worker 41d v1.29 .1
接下来运行一个带有 security=S1 标签的 Pod:
1 2 3 4 5 6 7 8 9 10 11 apiVersion: v1 kind: Pod metadata: name: nginxsecuritys1 labels: security: S1 spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent
检查调度到的节点:
1 2 [vagrant@master01 ~]$ kubectl get pod -o wide | grep nginxsecuritys1 nginxsecuritys1 1 /1 Running 0 22s 10.244 .45 .215 worker02.example.com <none> <none>
使用 Pod 亲和性将第二个 Pod 调度到跟 nginxsecuritys1 相同的节点上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: v1 kind: Pod metadata: name: nginxsecuritys2 spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: zone containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent
验证:
1 2 3 [vagrant@master01 ~]$ kubectl get pods -o wide | grep security nginxsecuritys1 1 /1 Running 0 37m 10.244 .45 .215 worker02.example.com <none> <none> nginxsecuritys2 1 /1 Running 0 10m 10.244 .45 .219 worker02.example.com <none> <none>
定义 Pod 反亲和性规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 apiVersion: v1 kind: Pod metadata: name: nginxsecuritys3 spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: zone containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent
验证:
1 2 3 4 [vagrant@master01 ~]$ kubectl get pods -o wide | grep security nginxsecuritys1 1 /1 Running 0 37m 10.244 .45 .215 worker02.example.com <none> <none> nginxsecuritys2 1 /1 Running 0 10m 10.244 .45 .219 worker02.example.com <none> <none> nginxsecuritys3 1 /1 Running 0 3m41s 10.244 .95 .133 worker01.example.com <none> <none>
nodeName 使用 nodeName 优先级将高于 nodeSelector 和亲和性规则。 示例:
1 2 3 4 5 6 7 8 9 10 apiVersion: v1 kind: Pod metadata: name: nginxnodenameonworker1 spec: nodeName: worker01.example.com containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent
验证:
1 2 3 [vagrant@master01 ~]$ kubectl get pod/nginxnodenameonworker1 -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginxnodenameonworker1 1 /1 Running 0 12s 10.244 .95 .156 worker01.example.com <none> <none>
污点和容忍度 节点亲和性使 Pod 被吸引到一类特定的节点。污点(Taint) 相反,污点应用于节点上使节点排斥一类特定的 Pod 。
容忍度(Toleration)是应用于 Pod 上的。容忍度允许调度器调度带有对应污点的 Pod。容忍度允许调度但不保证调度。
污点和容忍度的相互配合可以避免 Pod 被分配到不合适的节点上。 每个节点上可以应用多个污点,不能容忍这些污点的 Pod 是不会调度到该节点上。
使用 kubectl taint 给节点添加一个污点:
1 kubectl taint nodes worker01 key1=value1:NoSchedule
删除污点:
1 kubectl taint nodes worker01 key1=value1:NoSchedule-
上述的 NoSchedule 对应的是效果,表示只拥有和这个污点想匹配的容忍度的 Pod 才能后被调度到该节点。除此之外 effect 有以下类型:
NoExecute:会影响已在节点上运行的 Pod,如果 Pod 不能容忍这类污点,会马上驱逐。
NoSchedule:需要具有匹配的容忍度 Pod 才会被调度,当前正在节点上运行的 Pod 不会被驱逐。
PreferNoSchedule:软性的 NoSchedule,尝试避免将不能容忍的 Pod 调度到节点上,但不保证完全避免。 在 Pod 上使用容忍度的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: v1 kind: Pod metadata: name: nginx labels: env: test spec: containers: - name: nginx image: nginx imagePullPolicy: IfNotPresent tolerations: - key: "example-key" operator: "Exists" effect: "NoSchedule"
Pod 容忍度也有 operator 参数:
Equal:如果键、值和效果参数匹配,则容忍度和污点匹配,这是默认的行为
Exists:如果键和效果参数匹配,则容忍度和污点匹配,必须将值参数留空
评论· · · · · ·