Kubernetes Pod 调度的高级技术
在 Kubernetes 集群中,合理地调度 Pod 至关重要,它直接影响着资源的利用率和应用的性能。本文将介绍几种高级的 Pod 调度技术,包括
nodeSelector
、
Node affinity
以及
Taints and tolerations
。
1. 使用 nodeSelector 进行 Pod 调度
nodeSelector
是一种基本的 Pod 调度方法,它允许你将 Pod 仅调度到具有特定标签值的节点上。
1.1 nodeSelector 的应用场景
- 混合集群 :通过指定操作系统作为调度标准,确保 Windows 容器在 Windows 节点上运行,Linux 容器在 Linux 节点上运行。
- 资源分配 :将 Pod 调度到具有特定资源(CPU、内存、存储)的节点上,以优化资源利用率。
- 硬件要求 :仅将需要特殊硬件(如 GPU)的 Pod 调度到具备相应能力的节点上。
-
安全区域
:使用标签定义安全区域,并使用
nodeSelector将 Pod 限制在特定区域,以增强安全性。
1.2 默认节点标签
每个 Kubernetes 节点默认都带有一组标签,例如:
-
kubernetes.io/arch
:描述节点的处理器架构,如
amd64
或
arm
。
-
kubernetes.io/os
:值为
linux
或
Windows
。
-
node-role.kubernetes.io/control-plane
:节点在 Kubernetes 集群中的角色。
1.3 操作步骤
以下是使用
nodeSelector
的具体操作步骤:
1. 为集群中的 Node 1 和 Node 2 添加
node-type=superfast
标签:
$ kubectl label nodes minikube-m02 node-type=superfast
node/minikube-m02 labeled
$ kubectl label nodes minikube-m03 node-type=superfast
node/minikube-m03 labeled
- 验证节点标签:
$ kubectl get nodes --show-labels |grep superfast
-
编辑
02_nodeselector/nginx-deployment.yaml文件,设置nodeSelector为node-type: superfast:
# 02_nodeselector/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
...
template:
...
spec:
nodeSelector:
node-type: superfast
- 应用配置文件并检查 Pod 状态和节点分配:
$ kubectl apply -f 02_nodeselector/nginx-deployment.yaml
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
-
若将
nodeSelector设置为node-type: slow(集群中没有节点具有该标签),则 Pod 将无法调度,Deployment 会卡住。
2. 使用 Node affinity 进行 Pod 调度
Node affinity
扩展了
nodeSelector
的功能,提供了更丰富的语言来定义 Pod 对节点的偏好或排斥。
2.1 Node affinity 的优势
-
规则表达更丰富
:可以使用
In、NotIn、Exists、DoesNotExist、Gt和Lt等操作符来匹配节点标签。 - 支持 Pod 间亲和性和反亲和性 :可以定义规则使 Pod 被吸引到或排斥某些节点,有助于减少延迟。
- 支持软亲和性和反亲和性规则 :软规则表示偏好,而不是硬性要求,即使不满足软规则,调度器仍可调度 Pod。
- 软规则可加权 :可以添加多个具有不同权重值的规则,调度器会综合考虑权重和其他参数来做出调度决策。
2.2 示例演示
为了演示
Node affinity
,我们将尝试为 Deployment 建模以下要求:“尝试仅将 Pod 调度到具有
node-type
标签值为
fast
或
superfast
的节点上,但如果无法实现,则使用任何节点,但严格避免
node-type
标签值为
extremelyslow
的节点。”
操作步骤如下:
1. 为节点添加标签:
$ kubectl label nodes --overwrite minikube node-type=slow
node/minikube labeled
$ kubectl label nodes --overwrite minikube-m02 node-type=fast
node/minikube-m02 labeled
$ kubectl label nodes --overwrite minikube-m03 node-type=superfast
node/minikube-m03 not labeled
-
编辑
03_affinity/nginx-deployment.yaml文件,定义软 Node 亲和性规则:
# 03_affinity/nginx-deployment.yaml
...
spec:
...
template:
...
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-type
operator: NotIn
values:
- extremelyslow
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: node-type
operator: In
values:
- fast
- superfast
- 应用配置文件并检查 Pod 状态和节点分配:
$ kubectl apply -f 03_affinity/nginx-deployment.yaml
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
- 重新标记节点并重启 Deployment:
$ kubectl label nodes --overwrite minikube node-type=slow
node/minikube not labeled
$ kubectl label nodes --overwrite minikube-m02 node-type=extremelyslow
node/minikube-m02 labeled
$ kubectl label nodes --overwrite minikube-m03 node-type=extremelyslow
node/minikube-m03 labeled
$ kubectl rollout restart deployment nginx-app
- 再次检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
2.3 Node affinity 流程图
graph TD;
A[开始] --> B[定义 Node affinity 规则];
B --> C[应用规则到 Deployment];
C --> D[检查 Pod 调度结果];
D --> E{是否满足规则};
E -- 是 --> F[调度成功];
E -- 否 --> G[根据软规则调度];
G --> H[检查资源是否充足];
H -- 是 --> F;
H -- 否 --> I[Pod 处于 Pending 状态];
通过以上步骤,我们成功地配置了
Node affinity
,实现了对 Pod 调度的更精细控制。接下来,我们将介绍另一种 Pod 调度技术——
Taints and tolerations
。
3. 使用 Node taints 和 tolerations 进行 Pod 调度
虽然使用 Node 和 Pod 间的亲和性机制进行 Pod 调度非常强大,但有时你需要一种更简单的方法来指定哪些节点应该排斥 Pod。Kubernetes 为此提供了两个稍旧且更简单的功能——污点(Taints)和容忍度(Tolerations)。
3.1 污点和容忍度的概念
- 污点(Taints) :应用于节点,描述节点的某种限制。所有 Pod 都会避免调度到带有污点的节点,除非 Pod 有相应的容忍度。
- 容忍度(Tolerations) :定义在 Pod 规范中,允许 Pod 调度到带有特定污点的节点。
3.2 污点的结构和效果
污点的结构为
<key>=<value>:<effect>
,其中
key
和
value
对标识污点,
effect
表示污点的效果,有以下几种:
-
NoSchedule
:kube-scheduler 不会将 Pod 调度到该节点。
-
PreferNoSchedule
:kube-scheduler 会尽量不将 Pod 调度到该节点。
-
NoExecute
:kube-scheduler 不会将 Pod 调度到该节点,并会驱逐(终止并重新调度)正在该节点上运行的 Pod。
3.3 内置污点
Kubernetes 会自动管理一些
NoExecute
污点,例如:
-
node.kubernetes.io/not-ready
:当节点状态为
Ready
为
false
时添加。
-
node.kubernetes.io/unreachable
:当节点状态为
Ready
为
Unknown
时添加。
-
node.kubernetes.io/memory-pressure
:节点内存压力过大。
-
node.kubernetes.io/disk-pressure
:节点磁盘压力过大。
-
node.kubernetes.io/network-unavailable
:节点网络不可用。
-
node.kubernetes.io/unschedulable
:节点当前不可调度。
-
node.cloudprovider.kubernetes.io/uninitialized
:用于由外部云提供商准备的节点,初始化后该污点会被移除。
3.4 操作步骤
以下是使用污点和容忍度的具体操作步骤:
1. 为节点添加污点:
$ kubectl taint node minikube machine-check-exception=memory:NoExecute
node/minikube tainted
- 检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
此时,所有 Deployment Pod 都会处于
Pending
状态,因为 kube-scheduler 无法找到可以运行它们的节点。
-
编辑
04_taints/nginx-deployment.yaml文件,定义污点容忍度:
# 04_taints/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-app
spec:
...
template:
...
spec:
tolerations:
- key: machine-check-exception
operator: Equal
value: memory
effect: NoExecute
tolerationSeconds: 60
- 应用配置文件并检查 Pod 状态和节点分配:
$ kubectl apply -f 04_taints/nginx-deployment.yaml
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
此时,你会发现 Pod 可以调度到 Node2 和 Node3,但 Node1 上的 Pod 会每 60 秒进入一次驱逐循环。
-
为节点添加
NoSchedule污点:
$ kubectl taint node minikube machine-check-exception=memory:NoSchedule
node/minikube tainted
- 再次检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
此时,Pods 会均匀分布在 Node2 和 Node3 上。
- 移除节点上的污点:
$ kubectl taint node minikube machine-check-exception-
node/minikube untainted
- 重启 Deployment 以重新调度 Pod:
$ kubectl rollout restart deployment nginx-app
deployment.apps/nginx-app restarted
- 再次检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
此时,Pods 会再次均匀分布在所有三个节点上。
-
再次应用
NoSchedule和NoExecute污点:
$ kubectl taint node minikube machine-check-exception=memory:NoSchedule
node/minikube tainted
$ kubectl taint node minikube machine-check-exception=memory:NoExecute
node/minikube tainted
- 观察 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
60 秒后,Pods 会被驱逐,并且不会出现驱逐 - 调度循环。
3.5 污点和容忍度的流程图
graph TD;
A[开始] --> B[为节点添加污点];
B --> C[检查 Pod 调度状态];
C --> D{Pod 是否有容忍度};
D -- 是 --> E{是否有 NoExecute 容忍度};
E -- 是 --> F{是否设置 tolerationSeconds};
F -- 是 --> G[在指定时间内容忍污点];
G --> H[时间到后驱逐 Pod];
F -- 否 --> I[立即驱逐 Pod];
E -- 否 --> J[Pod 可调度到节点];
D -- 否 --> K[Pod 处于 Pending 状态];
通过使用污点和容忍度,我们可以更灵活地控制 Pod 的调度,避免 Pod 被调度到不适合的节点上。
总结
本文介绍了三种高级的 Pod 调度技术:
nodeSelector
、
Node affinity
和
Taints and tolerations
。
nodeSelector
是一种简单的调度方法,适用于基本的调度需求;
Node affinity
提供了更丰富的调度规则,可实现更精细的调度控制;
Taints and tolerations
则允许我们指定节点的限制,使 Pod 能够容忍这些限制。在实际应用中,你可以根据具体需求选择合适的调度技术,以优化资源利用率和应用性能。
Kubernetes Pod 调度的高级技术
4. 三种调度技术对比
为了更清晰地了解
nodeSelector
、
Node affinity
和
Taints and tolerations
这三种调度技术的特点和适用场景,我们可以通过以下表格进行对比:
| 调度技术 | 描述 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| nodeSelector | 允许将 Pod 仅调度到具有特定标签值的节点上 | 简单易懂,易于配置 | 规则表达能力有限,只能进行简单的相等比较 | 基本的调度需求,如根据操作系统、硬件类型等进行调度 |
| Node affinity | 扩展了 nodeSelector 的功能,提供更丰富的语言来定义 Pod 对节点的偏好或排斥 | 规则表达丰富,支持多种操作符,可定义软规则和反亲和性 | 配置相对复杂 | 需要更精细的调度控制,如根据节点资源、Pod 间关系等进行调度 |
| Taints and tolerations | 应用污点到节点,Pod 需要有特定容忍度才能调度到该节点 | 可简单指定节点排斥 Pod,支持多种污点效果 | 理解和配置有一定难度,可能导致 Pod 调度问题 | 需要指定节点的限制,使 Pod 能够容忍这些限制,如隔离特殊节点、处理节点故障等 |
5. 实际应用中的考虑因素
在实际应用中,选择合适的 Pod 调度技术需要考虑以下因素:
5.1 集群规模和复杂度
-
小规模集群
:如果集群规模较小,且调度需求相对简单,
nodeSelector可能是一个不错的选择,因为它配置简单,易于理解和维护。 -
大规模集群
:对于大规模集群,调度需求通常较为复杂,可能需要使用
Node affinity或Taints and tolerations来实现更精细的调度控制。
5.2 资源利用率
-
优化资源分配
:如果希望优化资源利用率,将 Pod 调度到具有合适资源的节点上,可以使用
Node affinity或nodeSelector根据节点的资源标签进行调度。 -
处理资源压力
:当节点出现资源压力(如内存压力、磁盘压力等)时,可以使用
Taints and tolerations来隔离受影响的节点,避免 Pod 被调度到这些节点上。
5.3 应用的特性和需求
-
对延迟敏感的应用
:对于对延迟敏感的应用,可以使用
Node affinity或Pod affinity来确保 Pod 被调度到与相关服务或数据存储在同一节点或同一区域的节点上,以减少网络延迟。 -
特殊硬件需求
:如果应用需要特殊硬件(如 GPU、FPGA 等),可以使用
nodeSelector或Node affinity将 Pod 调度到具有相应硬件的节点上。
6. 常见问题及解决方案
在使用这些调度技术时,可能会遇到一些常见问题,以下是一些解决方案:
6.1 Pod 无法调度
-
原因
:可能是由于
nodeSelector或Node affinity规则设置不合理,导致没有节点满足调度要求;或者是节点上的污点没有对应的容忍度。 -
解决方案
:检查
nodeSelector、Node affinity规则和Taints and tolerations配置,确保规则合理且节点标签和污点设置正确。可以使用kubectl describe pod命令查看 Pod 的调度事件,找出问题所在。
6.2 调度效率低下
- 原因 :可能是由于调度规则过于复杂,导致调度器需要花费大量时间来评估节点;或者是集群中节点资源不均衡,导致调度器难以找到合适的节点。
-
解决方案
:简化调度规则,避免使用过于复杂的
Node affinity规则;对集群中的节点进行资源均衡,确保节点资源分布合理。
6.3 驱逐循环问题
-
原因
:在使用
Taints and tolerations时,如果只设置了NoExecute污点而没有设置NoSchedule污点,可能会导致 Pod 被驱逐后又被重新调度到该节点上,形成驱逐循环。 -
解决方案
:在使用
NoExecute污点时,同时设置NoSchedule污点,避免 Pod 被重新调度到受影响的节点上。
7. 总结与展望
通过本文的介绍,我们了解了三种高级的 Pod 调度技术:
nodeSelector
、
Node affinity
和
Taints and tolerations
。这些技术为我们在 Kubernetes 集群中调度 Pod 提供了更多的灵活性和控制能力。
在实际应用中,我们应该根据具体的需求和场景选择合适的调度技术。对于简单的调度需求,可以使用
nodeSelector
;对于需要更精细控制的场景,可以使用
Node affinity
;而当需要处理节点的特殊限制时,
Taints and tolerations
则是一个很好的选择。
随着 Kubernetes 的不断发展,未来可能会出现更多高级的调度技术和功能,以满足日益复杂的应用需求。我们需要不断学习和掌握这些新技术,以优化我们的集群资源利用率和应用性能。
同时,我们也应该注意在使用这些调度技术时的一些常见问题,并采取相应的解决方案,以确保 Pod 能够稳定、高效地运行在 Kubernetes 集群中。
附录:常用命令总结
为了方便大家在实际操作中使用,以下是本文中涉及的常用命令总结:
| 操作 | 命令 |
|---|---|
| 为节点添加标签 |
kubectl label nodes <nodeName> <labelKey>=<labelValue>
|
| 验证节点标签 |
kubectl get nodes --show-labels
|
| 应用 Deployment 配置文件 |
kubectl apply -f <yamlFile>
|
| 查看 Pod 状态和节点分配 |
kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
|
| 为节点添加污点 |
kubectl taint node <nodeName> <key>=<value>:<effect>
|
| 移除节点上的污点 |
kubectl taint node <nodeName> <key>=<value>:<effect>-
|
| 重启 Deployment |
kubectl rollout restart deployment <deploymentName>
|
超级会员免费看
34

被折叠的 条评论
为什么被折叠?



