53、Kubernetes Pod 调度的高级技术

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
  1. 验证节点标签:
$ kubectl get nodes --show-labels |grep superfast
  1. 编辑 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
  1. 应用配置文件并检查 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"
  1. 若将 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
  1. 编辑 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
  1. 应用配置文件并检查 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"
  1. 重新标记节点并重启 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
  1. 再次检查 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
  1. 检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"

此时,所有 Deployment Pod 都会处于 Pending 状态,因为 kube-scheduler 无法找到可以运行它们的节点。

  1. 编辑 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
  1. 应用配置文件并检查 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 秒进入一次驱逐循环。

  1. 为节点添加 NoSchedule 污点:
$ kubectl taint node minikube machine-check-exception=memory:NoSchedule
node/minikube tainted
  1. 再次检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"

此时,Pods 会均匀分布在 Node2 和 Node3 上。

  1. 移除节点上的污点:
$ kubectl taint node minikube machine-check-exception-
node/minikube untainted
  1. 重启 Deployment 以重新调度 Pod:
$ kubectl rollout restart deployment nginx-app
deployment.apps/nginx-app restarted
  1. 再次检查 Pod 状态和节点分配:
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"

此时,Pods 会再次均匀分布在所有三个节点上。

  1. 再次应用 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
  1. 观察 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值