3.8 Pod 调度

在上一章中,我们学习了 Label,可以为对象设置标签,并且使用选择器筛选对象,本章中我们将学习节点调度的相关知识,在标签之上控制 Pod 在节点中的部署。

亲和性

亲和性和反亲和性

前面我们学习了 nodeSelector ,Deployment 等可以使用 nodeSelector 选择合适的节点部署 Pod。

例如选择磁盘空间大的节点部署 Pod:

    spec:
      containers:
      - image: nginx:latest
        name: nginx
      nodeSelector:
        disksize: "big"

而节点亲和性类似于 nodeSelector ,可以根据节点上的标签约束 Pod 可以调度到哪些节点。

Pod 亲和性有两种别为:

  • requiredDuringSchedulingIgnoredDuringExecution

    硬需求,将 Pod 调度到一个节点必须满足的规则。

  • preferredDuringSchedulingIgnoredDuringExecution

    尽量满足,尝试执行但是不能保证偏好。

这是从 Kubernetes 官方文档找到的一个例子:

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

这个 YAML 的层级太多,关于亲和性部分的内容抽选如下:

  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
        ... ...
      preferredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions: 
        ... ...

affinity 配置亲密关系;亲和性有多种类型,示例中使用了 nodeAffinity 设置节点亲密关系,最后是亲和性表达式,它们表示必须满足(requiredDuring)和尽量满足( preferredDuring)。

requiredDuring 部分的规则定义如下:

      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2

requiredDuringSchedulingIgnoredDuringExecution 亲和性的约束如果使用标签选择器来表示,相当于:

... ... -l kubernetes.io/e2e-az-name in (e2e-az1,e2e-az2)

如果我们设置了多个 nodeSelectorTerms :

requiredDuringSchedulingIgnoredDuringExecution:
  nodeSelectorTerms:
  ...
  nodeSelectorTerms:

只需要满足其中一种表达式即可调度 Pod 到 节点上

我们再回忆一下,节点选择器叫 nodeSelector,而节点亲和性叫 nodeAffinity,它们都可以让 Deployment 等对象部署 Pod 时选择合适的节点,它们都是使用标签(Label)来完成选择工作。

如果你同时指定了 nodeSelectornodeAffinity ,则两者必须同时满足条件, 才能将 Pod 调度到候选节点上。

除了节点亲和性,也有 Pod 亲和性。

节点亲和性语法支持下面的操作符: InNotInExistsDoesNotExistGtLt

Pod 亲和性与反亲和性的合法操作符有 InNotInExistsDoesNotExist

通过 Affinity 后缀 可以设置亲和性,例如节点亲和性 nodeAffinity。而设置反亲和性使用 AntiAffinity 后缀,例如 nodeAntiAffinity

反亲和性跟亲和性一样,都有 requiredDuringSchedulingIgnoredDuringExecution 硬限制和 preferredDuringSchedulingIgnoredDuringExecution 软限制,只是反亲和性是相反的表示,如果符合条件则不能调度。

关于亲和性和反亲和性的说明就到这里,这两者的配置比较多和复杂,读者可以参考官方文档,这里不再赘述。

亲和性和反亲和性的 YAML 很复杂,所以手写不出来的,只需要努力了解大概的意思和看懂就行,需要使用时查看文档。

https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node

污点和容忍度

污点

前面提到亲和性和反亲和性,我们可以让 Pod 选择合适的 Node(节点亲和性),或者 service 、Deployment 选择合适的 Pod(Pod亲和性),这些拥有 Label 的对象都是被选择的

这里,我们介绍污点和容忍度,Node 和 Pod 它们可以排斥 “被选择” 的命运。

[Info] 提示

节点污点:当节点添加一个污点后,除非 Pod 声明能够容忍这个污点,否则 Pod 不会被调度到这个 节点上。

也就是说,节点也可以 “丑拒” Pod。

如果节点存在污点,那么 Pod 可能不会被分配到此节点上;如果节点一开始没有设置污点,然后部署了 Pod,后面节点设置了污点,节点可能会删除已部署的 Pod,这种行为称为驱逐

节点污点(taint) 可以排斥一类特定的 Pod,而 容忍度(Tolerations)则表示能够容忍这个对象的污点。

节点说自己又笨又丑,但是 Pod 说我不介意,要跟你谈一场轰轰烈烈的恋爱。

Node - taint > 排斥 Pod
Pod  - tolerations -> 我是真爱,我能容忍污点 -> Node

污点有强制和尽量两种,前者完全排斥,后者尽可能排斥,另外某些污点可以将已经在这台节点上部署的 Pod 逐出,这个过程称为 effect。

系统会 尽量避免将 Pod 调度到存在其不能容忍污点的节点上, 但这不是强制的。Kubernetes 处理多个污点和容忍度的过程就像一个过滤器:从一个节点的所有污点开始遍历, 过滤掉那些 Pod 中存在与之相匹配的容忍度的污点。

但是如果你只有一个 Worker,那么设置了污点,那 Pod 也只能选择在这个节点上运行。就好像全世界只剩下一女(Node)一男(Pod),不想在一起也得在一起。

添加污点格式:

kubectl taint node [node] key=value:[effect]

更新污点或覆盖:

kubectl taint node [node] key=value:[effect] --overwrite=true

我们也可以修改节点的 YAML 文件,修改污点:

apiVersion: v1
kind: Node
metadata:
...
...
spec:
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/master
...

我们来实际尝试命令,使用 kubectl taint 给节点增加一个污点。

kubectl taint node instance-2 key1=value1:NoSchedule

移除污点:

kubectl taint node instance-2 key1=value1:NoSchedule-

[Error] 提示

污点生成的键值不是标签,污点生成的是 taint 对象,标签生成的是 label 对象。

给节点设置的污点,不会在 Labels 中出现,而是在 Traints 中。

查看节点的污点:

kubectl get nodes instance-2 -o json | jq '.items[].spec.taints'

使用 apt install jq 安装 json 筛选工具。

[
  {
    "effect": "NoSchedule",
    "key": "key1",
    "value": "value1"
  }
]

或者从 Node 描述文件中获取污点信息:

root@master:~# kubectl describe nodes slave1 | grep Taints
Taints:             key1=value1:NoSchedule

污点的效果称为 effect ,我们在前面设置了 {key1,value1},其默认效果为 NoSchedule。

节点的污点可以设置为以下三种效果:

  • NoSchedule:不能容忍此污点的 Pod 不会被调度到节点上;不会影响已存在的 pod。
  • PreferNoSchedule:Kubernetes 会避免将不能容忍此污点的 Pod 安排到节点上。
  • NoExecute:如果 Pod 已在节点上运行,则会将该 Pod 从节点中逐出;如果尚未在节点上运行,则不会将其调度到此节点上。

当节点设置污点后,无论其效果是哪一种,只要 Pod 没有设置相关的容忍度,Pod 就不会调度到此节点上。

例如节点声明了 smallcpu 污点,只要 Pod 没有声明容忍此 污点,那么 Pod 就不应该被调用到此节点上。除了 smallcpu 污点名称外,还有值也属于规则约束,这点我们后面再解释。

系统默认污点

尽管一个节点上的污点完全排斥 Pod,但是某些系统创建的 Pod 可以容忍所有 NoExecuteNoSchedule 污点,因此不会被逐出。

例如 master 节点是不会被 Deployment 等分配 Pod 的,因为 master 有个污点,表面它只应该运行kube-system 命名空间中的很多系统 Pod,用户 Pod 会被排斥部署到 master 节点上。

root@master:~# kubectl describe nodes master | grep Taints
Taints:             node-role.kubernetes.io/master:NoSchedule

当然我们通过修改污点,可以让用户的 Pod 部署到 master 节点中,本小节我们将学习系统默认污点以及相关驱逐的知识。

查询所有节点的污点:

kubectl describe nodes | grep Taints
# master 输出
Taints:             node-role.kubernetes.io/master:NoSchedule
# worker 输出
Taints:             key1=value1:NoSchedule

master 节点上会有一个 node-role.kubernetes.io/master:NoSchedule 的污点,Kubernetes 部署用户的 Pod 时会检查节点是否存在此污点,如果有,则不会在此节点上部署 Pod。

这里我们做一个实践,去掉 master 节点的污点,使得 用户 Pod 能够在此 节点上部署。

我们去除 master 和 worker 的污点:

kubectl taint node instance-1 node-role.kubernetes.io/master:NoSchedule-
kubectl taint node instance-2 key1=value1:NoSchedule-
# instance-1 是笔者的 master 节点名称
# 有污点就删除,没有就不用管

然后部署通过 Deployment 部署 Nginx,并设置副本集。

kubectl create deployment nginxtaint --image=nginx:latest --replicas=5

查看 Pod 都部署到哪些节点上:

kubectl get pods -o wide

可以看到,master 节点也被部署了 Pod。

无污点节点部署

可以看到,Pod 在笔者的主节点上运行了(instance-1)。

这里只是练手实践,为了保证集群安全,我们需要恢复 master 的污点,驱逐用户 Pod。

kubectl taint node instance-1 node-role.kubernetes.io/master:NoSchedule

除了上面提及的 node-role.kubernetes.io/master ,Kubeenetes 还会在某些情况下,某种条件为真时,节点控制器会自动给节点添加一个污点。当前内置的污点包括:

  • node.kubernetes.io/not-ready:节点未准备好。这相当于节点状态 Ready 的值为 "False"。
  • node.kubernetes.io/unreachable:节点控制器访问不到节点. 这相当于节点状态 Ready 的值为 "Unknown"。
  • node.kubernetes.io/out-of-disk:节点磁盘耗尽。
  • node.kubernetes.io/memory-pressure:节点存在内存压力。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力。
  • node.kubernetes.io/network-unavailable:节点网络不可用。
  • node.kubernetes.io/unschedulable: 节点不可调度。
  • node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个 "外部" 云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。

当节点上的资源不足时,会添加一个污点,排斥后续 Pod 在此 节点上部署,但不会驱逐已存在的 Pod。如果我们的 Pod 对机器资源有要求,可以排斥相关的污点,如果没要求,则需要容忍相关污点。

容忍度

污点和容忍度相互配合,用来避免 Pod 被分配到不合适的节点上;也可以让真正合适的 Pod 部署到有污点的节点上。一个节点可以设置污点,排斥 Pod,但是 Pod 也可以设置 容忍度,容忍节点的污点。

YAML 示例:

tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoSchedule"

此 Pod 能够容忍带有 key1 标签的污点,且无论是什么值。

也可以设置带 value 的容忍。

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"

operator 的默认值是 Equal

只有当污点 key1 的值为 value1 时,才容忍。

可以同时定义多个容忍度:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

一个容忍度和一个污点相 “匹配” 是指它们有一样的键名(key)和效果(effect ),并且:

  • 如果 operatorExists

    此时不需要填写 value 字段;如果存在 key 为 key1 的 label,且污点效果为 NoSchedule,无论是什么值都容忍。

  • 如果 operatorEqual

    则它们的 value 应该相等,如果相同的话,则容忍,如果只不同则容忍。

  • 如果 effect 留空

    则表示只要是 label 为 key1 的节点,都可以容忍。

如果 Pod 的容忍度设置为以下 YAML:

tolerations:
  operator: "Exists"

则表示此 Pod 能够容忍任意的污点,无论节点怎么设置 keyvalueeffect ,此 Pod 都不会介意。

如果要在 master 上也能部署 Pod,则可以修改 Pod 的容忍度:

    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        effect: NoSchedule

下面是一份官方的 Pod 的带有容忍度的 YAML 文件模板:

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"

模板文件地址:

https://raw.githubusercontent.com/kubernetes/website/master/content/zh/examples/pods/pod-with-toleration.yaml

Copyright © 痴者工良 2021 all right reserved,powered by Gitbook文档最后更新时间: 2022-07-30 09:49:42

results matching ""

    No results matching ""