问题描述
该笔记将记录:在 Kuberntes 中,如何调度 Pod 资源,以及常见问题的解决办法;
解决方案
实现 Pod 调度(例如 驱逐、亲和、节点选择 等等),与之相关的技术有如下若干方式
nodeSelector
在 Pod.Spec 中,指定 nodeSelector 属性,然后仅具备特定标签的 Node 才会被放置该 Pod 实例:
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx nodeSelector: gpu: "true" # 调度器将只在包含标签 gpu=true 的节点中选择
我们也可以将 pod 调度到特定节点:
1)每个节点都有个唯一标签,其中键为 kubernetes.io/hostname,值为该节点的实际主机名,因此我们也可以将 pod 调度到某个确定的节点;
2)但是如果节点离线,标签的唯一性会会导致 pod 不可调度;
3)所以,我们避免使用唯一性的标签,而是应该通过标签选择器考虑符合特定标准的逻辑节点组;
但是 nodeSelector 比较简单无法实现复杂的需求,所以引入 nodeAffinity 特性,而 nodeSelector 将来或许会被淘汰;
nodeAffinity(Pod with Node)
其与 nodeSelector 类似,每个 pod 可以定义自己的节点亲缘性规则,控制 Pod 在节点之间的调度;
这些规则可以允许你指定硬性限制或者偏好限制:
1)对于硬性限制:必须匹配标签才能够调度到节点上;
2)对于偏好限制:则将告知 Kubernetes 对于某个特定的 pod,它更倾向于调度到某些节点上,而 Kubernetes 将尽量把这个 pod 调度到这些节点上面。如果无法满足,则 pod 将被调度到其他某个节点上;
硬性限制的案例,节点必须满足 gpu=ture 才会放置该 Pod 实例:
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: # 仅影响创建时的调度;而执行期间,若节点标签被删除,不会被重新调度; nodeSelectorTerms: - matchExpressions: - key: gpu operator: In values: - "true" # 虽然冗长,但是功能强大,表达性更强; ...
偏好限制的案例,优先选择特定节点:
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 80 # 优先调度到 zone-cn 节点; preference: matchExpressions: - key: availability-zone operator: In values: - zone-cn - weight: 20 # 同时优先调度到 dedicated 类型节点; preference: matchExpressions: - key: share-type operator: In values: - dedicated containers: - name: with-node-affinity image: k8s.gcr.io/pause:2.0 # 在这里的优先级: # 最高的节点是同时具有 zone-cn 与 dedicated 的节点; # 然后是,仅具有 zone-cn 的节点; # 再而是,仅具有 dedicated 节点; # 最后是,不具备这两个标签的任何节点; # Q:在实际的实验中,即使存在满足条件的节点,但是并非所有的 Pod 都会调度到符合标签的节点上,这与节点亲和优先级相矛盾? # A:这是因为还存在其他调度函数来影响调度,比如 Selector SpreadPriority(避免 Node 故障而导致所有 Pod 实例失败)等等;
podAffinity(Pod with Pod)
Assigning Pods to Nodes | Kubernetes
控制 Pod 与 Pod 之间的关系:
1)podAffinity,使得 Pod 相互靠近;
2)podAntiAffinity,使得 Pod 相互排除;
apiVersion: apps/v1 kind: Deployment metadata: name: web-server spec: ... podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - store topologyKey: "kubernetes.io/hostname" ...
Taint and Toleration
evict-pod(a kubectl plugin)
rajatjindal/kubectl-evict-pod: This plugin evicts the given pod and is useful for testing pod disruption budget rules
How to evict specific pods on the Kubernetes cluster – DEV Community
通过该插件,能够驱逐特定 Pod 实例,以应对某些特殊场景。
场景:Namespace,选择节点(node-selector)
kubernetes – How to assign a namespace to certain nodes? – Stack Overflow
Taint toleration configured on namespace level · Issue #77687 · kubernetes/kubernetes
我们希望将在 ns-foo 命名空间中的 Pod 全部调度到 hostname 为 hn-foo 的节点上;
这需要使用名为 PodNodeSelector 的 Admission Controller 插件;
实验环境:Kubernetes v1.18.18
第一步,启用 PodNodeSelector 插件
# vim /etc/kubernetes/manifests/kube-apiserver.yaml ... - --enable-admission-plugins=NodeRestriction,PodNodeSelector ... # 注意事项, # 1)我们仅添加 PodNodeSelector 选项,而 NodeRestriction 为原有选项; # 2)kube-apiserver 会自动重启
第二步、命名空间添加注解
apiVersion: v1 kind: ns-foo metadata: name: your-namespace annotations: scheduler.alpha.kubernetes.io/node-selector: kubernetes.io/hostname=hn-foo spec: {} status: {}
补充说明:
1)kubernetes.io/hostname=hn-foo 是节点标签,执行 kubectl get nodes –show-lables 查看;
2)当添加该注解后,新创建的 Pod 都会被自动添加 nodeSelector: kubernetes.io/hostname=hn-foo 属性;
3)此时,具有 nodeSelector 的 Pod 将会被分配到 hostname 为 hn-foo 节点;
第三步、删除 Pod 以测试生效
# kubectl delete --all pods --namespace=ns-foo ... # kubectl describe pod -n ns-foo "<pod name>" ... Node: hn-foo/172.16.159.15 ... Node-Selectors: kubernetes.io/hostname=hn-foo ...
场景:Namespace,专用节点(taint/toleration)
Default Toleration at Namespace Level | by Zhimin Wen | Medium
Using Admission Controllers/PodTolerationRestriction
Taints and Tolerations | Kubernetes
通过 scheduler.alpha.kubernetes.io/node-selector 注解,其虽能够将 Pod 固定在具有特定 Label 节点上,但是其他不具备该 nodeSelector 的 Pod 也会被调度到该节点上。我们希望这些节点仅供给特定 Namespace 使用,其他 Namespace 的 Pod 不要调度到这些节点上;
解决方案:使用 Tain + Tolerantion + PodTolerationRestriction 注解;
第一步、PodTolerationRestriction
首先,修改 API Server 的 Admission Controllers 启用 –enable-admission-plugins=PodTolerationRestriction 插件;
第二步、Taint
然后,为节点添加 Taint 参数:
kubectl taint nodes <node-name> dedicated=myApp:NoSchedule
第三步、defaultTolerantion
最后,在命名空间中,添加 defaultTolerantion 注解:
# kubectl annotate namespace my-namespace \ 'scheduler.alpha.kubernetes.io/defaultTolerations'='[{"operator": "Exists", "effect": "NoSchedule", "key": "reservedFor"}]' # kubectl edit namespace my-namespace kind: Namespace metadata: annotations: scheduler.alpha.kubernetes.io/defaultTolerations: '[{"operator": "Exists", "effect": "NoSchedule", "key": "dedicated-node"}]' ...
关于 Daemonset 行为
Running background tasks on nodes automatically with daemonsets
Kubernetes/DaemonSet
鉴于 Daemonset 机制,在该场景下,需要为 Daemonset 手动添加 Toleration 配置;
参考文献
Assign Pods to Nodes – Kubernetes v1.17
Assign Pods to Nodes – Kubernetes v1.16