⑧.kubernetes pod调度

1.kube-scheduler

1.1 什么是调度器

1.2 调度器流程

1.3 预选函数

1.4 优选函数

2.Pod节点选择器

2.1 什么是节点选择器

2.2 节点选择器实践

3.节点亲和调度

3.1 什么是节点亲和

3.2 节点亲和策略

3.3 节点亲和示例

3.4 节点亲和操作符

3.5 节点亲和关系表达式-1

3.6 节点亲和关系表达式-2

3.7 节点亲和关系表达式-3

4. 强制节点亲和实践

4.1 强制节点亲和场景1

4.2 强制节点亲和场景2

5.首选节点亲和实践

5.1 首选节点亲和性示例

5.2 首选节点亲和场景1

5.3 首选节点亲和场景2

6. Pod亲和与反亲和调度

6.1 什么是Pod亲和与反亲和

6.2 为何需要Pod亲和与反亲和

6.3 Pod亲和与反亲和位置拓扑

6.4 Pod间的强制亲和实践

6.5 Pod间的首选亲和实践

6.6 Pod间的反亲和实践

7. Pod亲和与反亲和场景实践

7.1 场景说明

7.2 部署redis

7.3 部署应用

7.4 检查结果

8.nodeName

8.1 nodeName介绍

8.2 nodeName局限

8.3 nodeName实践

9. 污点与容忍度

9.1 什么是污点

9.2 什么是容忍度

9.3 污点与容忍度场景

9.4 如何给节点打污点

9.5 如何给Pod添加容忍度

9.6 污点与容忍度实践-1

9.7 污点与容忍度实践-2

9.8 污点与容忍度实践-3

===============================================

1.kube-scheduler

1.1 什么是调度器

在kubernetes中内置了kube-scheduler,它是集群默认的调度器。在pod规范中有一个nodeName的字段,这个字段指定了该pod要运行在那个节点上,如果直接指定该字段的值,也就是直接指明了Pod要在那个节点运行,kube-scheduler不会工作,如果没指定nodeName的值,也就是nodeName字段为空,kube-scheduler就会通过预选策略,优选策略来选定node节点的名字,填充到nodeName字段。
kube-scheduler它会一直监视着APIServer中所有Pod的NodeName字段,当监控该字段为空时,那么他会为对应的Pod启动调度机制,然后从众多节点上条一个最佳的节点,将选定的节点信息写入到nodeName字段,然后返回给apiserver,存入etcd中,kubelet会监视apiserver中没有运行的pod的NodeName中的值,发现有本节点的pod没有运行则会启动对应的Pod

1.2 调度器流程

一个Pod究竟要调度到那个节点上,是根据调度算法得出,kube-scheduler实现的调度器叫default-scheduler,如果调度器有其他的要求,kubernetes也允许自己写一个调度组件来替换默认的kube-scheduler.
default-scheduler在调度一个Pod时,有三个步骤来完成调度 预选策略 优选策略 绑定

1.预选策略
由于Pod内的每个容器对资源都有不同的需求,所以每个Pod的需求也不同,因此pod在被调度到node上之前,会检查候选node的可用资源是否能满足pod的资源需求。在预选后会得出一个node列表,里面包含了所有可以调度的节点。如果没有任何一个node能满足pod的资源需求,那么这个pod将一直会停留在未调度状态(pending),直到调度器能找到合适的node节点。
2.优选策略
在优选阶段,调度器会为pod从所有可以调度的节点上选取一个最合适的node。根据当前启动的打分规则,调度器会为每一个可调度节点进行打分,并按照综合得分进行排序,如果同时有多个节点得分一致,会随机挑选一个节点。
3.绑定节点
最后调度器会将这个调度决定通知给apiserver,存储到etcd中。这个过程叫绑定。而后由相应节点的代理程序kubelet通过监视apiserver发现未调度的pod字段中nodename的值启动相应的pod。

1.3 预选函数

预选阶段主要排除不符合pod申请规范的节点,所以它会通过所有已经启动的预选函数对所有节点进行逐一筛查,任何一个预选函数否决,都会造成该节点被排除点,反之则会保留进入下一个优选阶段。
1.CheckNodeUnschedulable

检查节点是否被标识为Unschedulable,这个标识标识不可调度,如果Pod能接受此类节点,则保留该节点,否则排除该节点

2.HostNaME

若Pod资源通过spec.nodeName明确指定了要绑定的目标节点,那么该节点会被保留

3.PodFitsHostPorts

若容器定义了ports.hostPort属性,那么该预选函数会检查指定的端口是否已被节点上其他容器或服务所占用,该端口已被占用的节点将被排除掉。

4.MatchNodeSelector

若Pod资源规范定义了spec.nodeSelector节点选择器字段,则将拥有匹配对应标签的节点保留下来,剩余节点全部排除。

5.PodFitsResources

检查节点受否由足够的cpu或内存资源,能够满足pod的运行需求。节点会声明其资源的可用容量,而pod会定义资源需求,于是调度器会判断节点是否由足够的资源来运行对应的pod,如果无法满足则返回失败的原因。(调度器评判节点资源消耗的标准时节点已经分配初期的资源使用量,也就是各个容器的requests之和。)

1.4 优选函数

成功通过预选函数过滤后的节点将生成一个可调度列表,随后对节点进行优先级排序阶段。对于每个节点,调度器会使用优选函数分别为其打分(0-10之间的分数),然后将所有的分数进行相加,即为该节点的总得分,最后得分高者为调度节点。

1.LeastRequestedPriority

通过计算cpu和memory的使用率来决定权重,使用率越低的节点权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点。

2.BalancedResourceAllocation

以cpu和memory资源占有率相近的作为评估标准,二者越接近的节点权重越高,该函数不能单独使用,它需要和LeasRequestedPriorty组合使用来平衡优化节点资源的使用状态,选择在部署当前Pod资源后系统资源更为均衡的节点。

3.NodeAffinityPriority

节点亲和调度机制,它根据Pod资源规范中的spec.nodeSelector对节点进行匹配度检查,成功匹配到的条目越多则节点得分越高。

4、TaintTolerationPriority

基于Pod资源对节点的污点容调度偏好进行优先级评估,它将Pod对象的tolerations列表与节点的污点进行匹配度检查,成功匹配的条目越多,则节点得分越低。

5、ImageLocalityPriority

镜像亲和调度机制,它根据给定的节点列表上是否拥有运行当前Pod的容器所依赖的镜像文件来计算节点的分值,如果没有所依赖的镜像文件节点得分为0,而存在相关镜像文件的各个节点,被Pod依赖到的镜像文件的体积越大,节点得分越高。

6、SelectorSpreadPriority

尽可能将Pod分散到不同节点上的调度插件,它首先查找标签选择器能匹配当前Pod标签的RS、Deployment、StatefulSet等控制器,而后查找可由这类对象的标签选择器匹配的现存各Pod对象及其所在的节点,而运行此类Pod对象越少的节点得分越高。简单来说: 就是将同一标签选择器匹配到的Pod资源打散到不同的节点上运行。
默认调度器能够满足我们绝大多数的要求,能够保证我们的 Pod可以被分配到资源充足的节点上运行。但是在实际的线上项目中可能我们自己会比 kuberhetes 更加了解我们自己的应用,比如我们希望一个 Pod 只能运行在特定的几个节点上,或者这几个节点只能用来运行特定类型的应用,这就需要我们的调度器能够可控

2.Pod节点选择器

2.1 什么是节点选择器

nodeSelector提供了一种简单的方法来讲Pod约束到具有特定标签的节点上。
Pod资源可以使用 .spec.nodeSelector来指定节点标签,过滤出符合条件的节点,作为可用目标节点,而后将Pod调度到拥有标签的节点上,如果没有匹配到对应节点的标签,则会调度失败。该匹配规则属于强制约束。
默认情况,Scheduler会将Pod调度到所有可用的节点。不过有些情况我们希望将Pod部署到指定节点,比如将有大量磁盘IO需求的pod部署到配置了SSD的节点上。

2.2 节点选择器实践

场景描述: Pod分配到具有SSD硬盘
1.给node1节点添加标签

[root@k8s-240 ~]# kubectl label nodes flyfish83 disktype=ssd
[root@k8s-240 ~]# kubectl describe nodes flyfish83
Name:               flyfish83
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    disktype=ssd
                    kubernetes.io/arch=amd64

2.配置Pod清单

cat 01-podnodeselector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-selector
spec:
  nodeSelector:
    disktype: ssd
  containers:
    - name: web
      image: nginx:1.18

3.验证结果

[root@k8s-240 nodeSelector]# kubectl apply -f 01-nodeSelector.yaml 
pod/pod-node-selector created
[root@k8s-240 nodeSelector]# kubectl get pod -o wide 
NAME                  READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod-node-selector     1/1     Running   0          20s   10.244.157.147   flyfish83   <none>           <none>

3.节点亲和调度

3.1 什么是节点亲和

节点亲和是指,Pod自身对期望运行的某类节点的倾向性,倾向于运行指定的节点即为"亲和"关系,否则即为"反亲和"关系。
要想实现亲和调度,首先小在节点上定义标签,而后在pod对象上通过标签选择器来选择对应的节点标签。而支持这种调度机制的有NodeSelector和NodeAffinity调度插件。
但nodeSelector节点选择器,只能选择拥有指定标签的节点,其实现逻辑较为简单,控制粒度不够细。而NodeAffinity节点亲和,提供节点选择的逻辑,更强的控制能力。

3.2 节点亲和策略

在Pod上定义节点亲和(nodeAffinity)时有两类亲和关系;required 强制/硬亲和、preferred 首选/软亲和。
强制亲和: 限定了调度Pod资源时必须满足的规则,如没有可用节点时Pod对象会被置为Pending状态,直到满足规则的节点出现。
首先亲和:相对于强制亲和来说它更加的柔和,它倾向将Pod运行在某类特定的节点上,但无法满足调度需求时,调度器将选择一个无法匹配规则的节点,而非将Pod对象置为Pending状态。

  • requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度,强制策。
  • preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点,软性亲和。

注意: Pod资源基于节点亲和规则调度至某节点之后,因节点标签发生了改变而变得不在符合Pod定义的亲和规则时,调度器也不会将Pod从此节点上移除,因而亲和调度仅在调度执行的过程中进行一次即时的判断,而非持续地监视亲和规则是否能够满足。

3.3 节点亲和示例

你可以使用Pod规约中的 .spec.affinity.nodeaffinity字段来设置节点亲和性

    1. 节点必须包含名为 kubernetes.io/os 的标签,并且取值为linux
    1. 节点最好具有键名为disktype且取值为ssd的标签
      二者条件结合起来的含义是,必须运行在os=linux的节点,且同事最好能够运行在带有ssd标签节点,没有也无所谓。
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  containers:
    - name: web
      image: nginx:1.18
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        # Hard Affinity
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                  - Linux
        # Soft Affinity
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
                - key: disktype
                  operator: In
                  values:
                    - ssd

3.4 节点亲和操作符

可以使用operator字段来为kubernetes设置在解析规则是要使用的逻辑操作符。

操作符 含义
In 如果节点标签的值在给定的值列表中,则匹配。
NotIn 如果节点标签的值不在给定的值列表中,则匹配。
Exists 如果指定的节点标签名存在,则匹配。
DoesNotExist 如果指定的节点标签名不存在,则匹配。
Gt 如果节点标签的值大于指定的值,则匹配。
Lt 如果节点标签的值小于指定的值,则匹配。

3.5 节点亲和关系表达式-1

如果在nodeSelectorTerms中指定了多个matchExpressions的话,只要有一个条件满足,Pod就可以被调度到对应的节点上。

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                  - linux
          - matchExpressions:
              - key: kubernetes.io/arch
                operator: In
                values:
                  - amd64

3.6 节点亲和关系表达式-2

如果在matchExressions中指定了多个条件,则多个条件必须同时满足,Pod才可以被调度到该节点上

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                  - linux
              - key: kubernetes.io/arch
                operator: In
                values:
                  - amd64

3.7 节点亲和关系表达式-3

如果同时指定了nodeSelector和nodeAffinity,两者必须同时满足,才能将Pod调度到候选节点上。

#节点为linux,同时arch必须为amd64,并且disktype为hdd
spec:
  nodeSelector:
    kubernetes.io/os: linux
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/arch
                operator: In
                values:
                  - amd64
              - key: disktype
                operator: In
                values:
                  - hdd
---
# 节点为linux,并且arch必须为amd64 or 节点为linux,并且disktype为hdd
spec:
  nodeSelector:
    kubernetes.io/os: Linux
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/arch
                operator: In
                values:
                  - amd64
          - matchExpressions:
              - key: disktype
                operator: In
                values:
                  - hdd

4. 强制节点亲和实践

4.1 强制节点亲和场景1

场景描述: 将Pod部署到拥有zone=beijing并且disktype=ssd标签的节点上

1、为节点添加标签

[root@master ~]# kubectl label nodes node01zone=beijing disktype=ssd
[root@master ~]# kubectl label nodes node03zone=beijing disktype=ssd
  1. 部署Pod,使用节点硬亲和,匹配对应标签;
cat 02-node-affinity-required.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-affinity-required
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: zone
                    operator: In
                    values:
                      - beijing
                  - key: disktype
                    operator: In
                    values:
                      - ssd

3.检查Pod调度情况

kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   IP               NODE     AGE
node-affinity-required-5f68f8cc97-2pxv21   1/1     Running   0          192.168.1.81     node01   23s
node-affinity-required-5f68f8cc97-csjsm1   1/1     Running   0          192.168.1.80     node01   23s
node-affinity-required-5f68f8cc97-f5tmj1   1/1     Running   0          192.168.1.82     node01   23s
node-affinity-required-5f68f8cc97-gk2Tr1   1/1     Running   0          192.168.1.83     node01   23s
node-affinity-required-5f68f8cc97-zvg551   1/1     Running   0          192.168.3.227    node03   23s

节点硬亲和机制实现的功能与节点选择器相似,但亲和性支持使用标签匹配表达式或字段选择器来挑选节点,提供了灵活且强大的选择机制,因此可被理解为新一代节点选择器.

4.2 强制节点亲和场景2

场景描述: 将所有Pod部署到zone≠beijing 并且disktype≠ssd的节点上;

1.给节点打标签

[root@master ~]# kubectl label nodes node01zone=beijing disktype=ssd
[root@master ~]# kubectl label nodes node03zone=beijing disktype=ssd

2.编写yaml

cat 03-node-affinity-required.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-affinity-required-2
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: zone
                    operator: NotIn
                    values:
                      - beijing
                  - key: disktype
                    operator: NotIn
                    values:
                      - ssd

3.检查Pod,会发现所有Pod都调度到Node2节点上。

kubectl get pod -o wide
NAME                                        READY   STATUS    RESTARTS   IP               NODE     AGE
node-affinity-required-2-664899f99c-4r2941   1/1     Running   0          192.168.2.99     node02   8s
node-affinity-required-2-664899f99c-bpgr51   1/1     Running   0          192.168.2.103    node02   8s
node-affinity-required-2-664899f99c-hg5gk    1/1     Running   0          192.168.2.102    node02   8s
node-affinity-required-2-664899f99c-rtl8j    1/1     Running   0          192.168.2.100    node02   8s
node-affinity-required-2-664899f99c-tzj7q    1/1     Running   0          192.168.2.101    node02   8s

5.首选节点亲和实践

5.1 首选节点亲和性示例

首选节点亲和为节点提供了一种柔性控制逻辑,被调度的Pod对象不再是“必须”,而是“尽量”放置到某些特定节点之上,但当节点不满足Pod调度的条件时,该Pod也能够接受被编排到其他不符合条件的节点之上。
多个软亲和条件并存时,它支持为每个条件定义weight属性以区别他们优先级,取值范围是1~100,数字越大优先级越高。如下清单定义了一条硬亲和条件和两条软亲和条件,并且它们有着不同的权重.

apiVersion: v1
kind: Pod
metadata:
  name: with-affinity-anti-affinity
spec:
  containers:
    - name: with-node-affinity
      image: nginx:1.18
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                  - linux
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 30
          preference:
            matchExpressions:
              - key: zone
                operator: In
                values:
                  - beijing
        - weight: 50
          preference:
            matchExpressions:
              - key: disktype
                operator: In
                values:
                  - ssd

5.2 首选节点亲和场景1

场景描述: 尽量将所有的Pod部署到 拥有gpu标签类型的节点
1、为节点添加标签

[root@master scheduler]# kubectl label nodes node02 gpu=true
node/node02 Tabeled

2.编写Pod

cat 04-node-affinity-preferred.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: node-affinity-preferred
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 50
              preference:
                matchExpressions:
                  - key: gpu
                    operator: In
                    values:
                      - "true"

3.检查Pod运行的节点,会发现优先调度到拥有gpu标签的node2节点上

kubectl get pod -o wide 
NAME                                      READY   STATUS    RESTARTS   IP               NODE     AGE
node-affinity-preferred-6bff67bbfb-4sxh61   1/1     Running   0          192.168.2.129   node02   9s
node-affinity-preferred-6bff67bbfb-jt2bg    1/1     Running   0          192.168.2.130   node02   9s
node-affinity-preferred-6bff67bbfb-qv4gs    1/1     Running   0          192.168.2.110   node02   9s
node-affinity-preferred-6bff67bbfb-tkzrj    1/1     Running   0          192.168.2.111   node02   9s
node-affinity-preferred-6bff67bbfb-z29hg    1/1     Running   0          192.168.2.109   node02   9s

4.给pod资源添加资源申请Reauests,然后重新创建资源

vim 04-node-affinity-preferred.yaml
     resources:
       requests:
         cpu: 300m
         memory: 300Mi

5.会发现,当node2节点无法满足需求时,会将Pod调度至其他节点;

kubectl get pod -o wide
NAME                                         READY   STATUS    RESTARTS   IP               NODE     AGE
pod-affinity-preferred-7cf455c7f-56wWX1      1/1     Running   0          192.168.3.229    node03   35s
pod-affinity-preferred-7cf455c7f-mrbmr1      1/1     Running   0          192.168.3.230    node03   3s
pod-affinity-preferred-7cf455c7f-nmdb91      1/1     Running   0          192.168.2.110    node02   3s
pod-affinity-preferred-7cf455c7f-v7wkv1      1/1     Running   0          192.168.2.111    node02   3s
pod-affinity-preferred-7cf455c7f-xdwp21      1/1     Running   0          192.168.1.85     node01   3s

5.3 首选节点亲和场景2

场景描述: 尽量将Pod调度到拥有gpu的节点,或者拥有zone=foo/bar标签的节点上,其中gpu的权重为68,zone的权重为30

1.给节点添加标签;

[root@master scheduler]# kubectl abel nodesnode01 gpu=true zone=foo
[root@master scheduler]# kubectl label nodesnode02 gpu=true
[root@master scheduler]# kubectl label nodesnode03 zone=bar

2.运行Pod

cat 05-pod-nodeaffinity-preferred-2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-affinity-preferred-2
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
          resources:
            requests:
              memory: 300Mi
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 6
              preference:
                matchExpressions:
                  - key: gpu
                    operator: Exists
            - weight: 30
              preference:
                matchExpressions:
                  - key: zone
                    operator: In
                    values:
                      - foo
                      - bar

3.检查Pod,虽然pod更加倾向node1节点,但当其无法满足pod资源需求时,它将转而使用node02,直到该节点资源也分配完毕后才使用倾向性更低的node3节点

kubectl get pod -o wide 
NAME                                        READY   STATUS    RESTARTS   IP               NODE     AGE
pod-affinity-preferred-2-67f475f468-m6tfk    1/1     Running   0          192.168.1.98     node01   8s
pod-affinity-preferred-2-67f475f468-nxcm7    1/1     Running   0          192.168.1.99     node01   8s
pod-affinity-preferred-2-67f475f468-wf6ld    1/1     Running   0          192.168.2.131    node02   8s
pod-affinity-preferred-2-67f475f468-gd4ht    1/1     Running   0          192.168.2.130    node02   8s
pod-affinity-preferred-2-67f475f468-fmj8z    1/1     Running   0          192.168.3.249    node03   8s

6. Pod亲和与反亲和调度

6.1 什么是Pod亲和与反亲和

pod亲和调度与节点亲和调度很相似,所谓节点亲和是用来判断Pod对节点的倾向性,是更愿意运行在这个节点上,还是不愿意运行在这个节点上。
那Pod亲和指的是Pod彼此之间运行同一位置的倾向性。什么叫做同一位置,我们可以将每个节点都成为一个不同的位置,这就意味着如果两个Pod是亲和的,那就必须运行在同一节点上,如果是反亲和的,就必须运行在不同的节点上。
但位置可以理解为别的概念,比如将位置理解为机架、这就意味着如果两个Pod是亲和的,它们就必须运行在同一机架的服务器上,而同一个机架如果拥有多个服务器,那么它运行在同一个机架上的任意服务器上,我们认为它是同一位置,否则就是不同位置。

6.2 为何需要Pod亲和与反亲和

我们为什么非要限定Pod是否运行在同一节点,或运行在同一机架上面呢,因为我们很多时候考虑更多的是Pod的冗余或容错,比如:我们为了能够让Mysql架构有更改好的容错性,我们定义每个节点为一个不同的位置,然后让它们在不同位置的服务器上,以达到分散运行的效果,实现节点级容灾等;

而有些服务则又需要亲和关系,比如PHP需要调用MySQL的时候,如果我们将PHP与MySQL Master运行在同一位置,我们认为它们彼此之间的交互性能会更好一些。而MySQL Master与 MySQL Slave之间应该又是反亲和的,已达到更好的容错效果。

也就是PHP与MySQL是亲和,MySQL与MySQL之间则是反亲和的。

6.3 Pod亲和与反亲和位置拓扑

定义位置的方法很简单,无外乎就是在节点上选定一个特定的节点标签,可以理解为拓扑标签/位置标签,当我们选择一个节点标签作为位置判定逻辑时,具有同一标签值的就是同一标签,具有不同标签值的就是不同位置。
1.基于节点划分
如果使用节点的 kubernetes.io/hostname 标签作为划分标准

2.基于区域划分
如果基于区域标签划分节点位置,同一位置就标识节点在同一区域,而不同位置则表示在节点在不同的区域;下图node01和node02属于同一位置,而node03和node04属于另一个意义上的同一位置。

假设PodA运行在beijing区域上,PodB与PodA有亲和关系,那么PodB则应该运行在beijing区域,反之则运行在shanghai区域。所以不管是亲和还是反亲和,它应该是有一个参照系,就是参考某个定义好的Pod,只要它在的地方我不在就是反亲和,或者我必须与它在同一位置就是亲和

6.4 Pod间的强制亲和实践

场景说明:

  • 1.首先定义一个被依赖的后端存储应用,redis
  • 2.然后定义一个依赖该redis存储的应用,比如nginx,它必须与redis运行在同一位置。
    为了更接近真实环境来模拟这种约束机制,这里模拟node02和node01位于同一机架rack001,而node03则位于另一个机架rack002上,并以节点标签rack作为位置标签。
    1.给节点添加标签
[root@master ~]# kubectl label nodes node01 rack=rack001
[root@master ~]# kubectl label nodes node02 rack=rack001
[root@master ~]# kubectl label nodes node03 rack=rack002

2.编写redis存储的deployment

cat redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      type: required
  template:
    metadata:
      labels:
        app: redis
        type: required
    spec:
      containers:
      - name: redis
        image: redis:6.0

3.编写nginx的Deployment

cat 06-pod-affinity-required.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webserver
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
        resources:
          requests:
            memory: 600Mi
      affinity:
        podAffinity:  #亲和关系
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values: ["redis"]
              - key: type
                operator: In
                values: ["required"]
            topologyKey: rack     # 使用节点rack标签来划分位置

4.由于redis被调度到flyfish82节点,而该节点位于rack001,因此nginx Pod也必将运行在该rack001的flyfish82、flyfish81节点上

[root@k8s-240 pod-affinity]# kubectl get pod  -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
redis-776f6bcd95-bkptb       1/1     Running   0          74m   10.244.149.146   flyfish82   <none>           <none>
webserver-5bdd8cd445-csbbn   1/1     Running   0          7s    10.244.232.225   flyfish81   <none>           <none>
webserver-5bdd8cd445-mgxfj   1/1     Running   0          7s    10.244.149.147   flyfish82   <none>           <none>
webserver-5bdd8cd445-mlzg8   1/1     Running   0          7s    10.244.149.149   flyfish82   <none>           <none>
webserver-5bdd8cd445-rnjxc   1/1     Running   0          7s    10.244.232.226   flyfish81   <none>           <none>
webserver-5bdd8cd445-vqxhc   1/1     Running   0          7s    10.244.149.148   flyfish82   <none>           <none>

Pod间的亲和调度能够将有着密切关系或密集通信的应用约束在同一位置,通过降低通信延迟来降低性能损耗,但如果flyfish82 flyfish81没有足够的资源支撑Pod的运行,则可能出现部分Pod处于Pending状态。

6.5 Pod间的首选亲和实践

首选亲和则只是尽力满足这种亲和关系,不像强制亲和它是必须满足亲和关系。当无法保证这种亲和关系时,调度器则会将Pod调度置集群中其他位置的节点之上。而对于位置关系要求不是那么严格的应用,在部署时采用首选亲和也是一种选择。
场景说明:

  • 1.首先定义一个被依赖的后端存储应用,redis。
  • 2.然后定义一个依赖该redis存储的应用,比如nginx,需求它尽量与redis Pod运行在同一位置节点(kubernetes.io/hostname标签),当条件无法满足时,则期望运行在同一机架上(rack标签),否则也能接收运行在集群中的其他任何节点之上。

    1.编写yaml文件
cat 07-pod-affinity-oreferred.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-db
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      type: preferred
  template:
    metadata:
      labels:
        app: redis
        type: preferred
    spec:
      nodeSelector:
        kubernetes.io/hostname: node01
      containers:
        - name: cache
          image: redis:6.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-affinity-preferred
spec:
  replicas: 5
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
          resources:
            requests:
              memory: 600Mi
          affinity:
            podAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
                - weight: 100
                  podAffinityTerm:
                    labelSelector:
                      matchExpressions:
                        - key: app
                          operator: In
                          values: ["redis"]
                        - key: type
                          operator: In
                          values: ["preferred"]
                    topologyKey: kubernetes.io/hostname
                - weight: 50
                  podAffinityTerm:
                    labelSelector:
                      matchExpressions:
                        - key: app
                          operator: In
                          values: ["redis"]
                        - key: type
                          operator: In
                          values: ["preferred"]
                    topologyKey: rack

2.当redis被调度到node01节点上,nginx pod同样更倾向运行在该节点,当条件无法满足时,调度器将以该节点所在的rack中的另一个节点node2,最后是node3节点。

[root@k8s-240 ~]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-affinity-preferred-6bfd9cd6bc-cbft6   1/1     Running   0          109m   10.244.232.230   flyfish81   <none>           <none>
pod-affinity-preferred-6bfd9cd6bc-k24rd   1/1     Running   0          109m   10.244.232.232   flyfish81   <none>           <none>
pod-affinity-preferred-6bfd9cd6bc-shjvf   1/1     Running   0          109m   10.244.232.228   flyfish81   <none>           <none>
pod-affinity-preferred-6bfd9cd6bc-ttzgt   1/1     Running   0          109m   10.244.149.157   flyfish82   <none>           <none>
pod-affinity-preferred-6bfd9cd6bc-wcd2m   1/1     Running   0          109m   10.244.232.231   flyfish81   <none>           <none>
redis-db-6cfc9d8447-vqg7j                 1/1     Running   0          109m   10.244.232.229   flyfish81   <none>           <none>

6.6 Pod间的反亲和实践

Pod间的反亲和,它主要目标在于确保存在互斥关系的Pod不会运行在同一位置,这么做有什么好处呢?

  • 1.将一个服务Pod分散在不同的主机或不同的位置中,提高服务本身的稳定性
  • 2。有些Pod需要占用节点特定端口,确保相同Pod不会调度同一节点,这样可以避免端口冲突。
    1、创建4个Pod副本,必须在不同的节点之上
cat 08-pod-antiaffinity-required.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-antiaffinity-required
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web-antiaffinity
  template:
    metadata:
      labels:
        app: web-antiaffinity
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - "web-antiaffinity"
              topologyKey: kubernetes.io/hostname

2.因为示例集群中一共就有3个节点,因此必然有一个Pod对象处于Pending状态。

[root@k8s-240 pod_affinity]# kubectl get pod  -o wide
NAME                                         READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
pod-antiaffinity-required-678dd8c45c-6xq5h   1/1     Running   0          7s    10.244.232.233   flyfish81   <none>           <none>
pod-antiaffinity-required-678dd8c45c-jkfdq   1/1     Running   0          7s    10.244.157.145   flyfish83   <none>           <none>
pod-antiaffinity-required-678dd8c45c-pbqxm   0/1     Pending   0          7s    <none>           <none>      <none>           <none>
pod-antiaffinity-required-678dd8c45c-w7r7x   1/1     Running   0          7s    10.244.149.162   flyfish82   <none>           <none>

当然Pod反亲和调度也支持使用柔性约束机制,调度器会尽量不把位置相斥的Pod对象调度到同一位置,但约束关系无法得到满足时,也可以违反约束规则进行调度,而非将Pod置于Pending状态。

7. Pod亲和与反亲和场景实践

7.1 场景说明

1.redis部署在不同位置的节点上(反亲和),使用hostname作为位置标签;
2.nginx与redis部署在同一位置(亲和)
3.nginx与nginx之间处于不同的位置(反亲和)

7.2 部署redis

  1. 创建Deployment资源,提供redis服务,设置标签app=store,副本数为3;
    2.使用podAntiAffinity规则告诉调度器避免将多个带有app=store标签的副本部署到同一节点上;
    因此,每个独立节点上会创建一个缓存实例
cat redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-server
spec:
  selector:
    matchLabels:
      app: store
  replicas: 3
  template:
    metadata:
      labels:
        app: store
    spec:
      containers:
      - name: redis-server
        image: redis
      affinity:   
        podAntiAffinity:    #反亲和
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - store
              topologyKey: "kubernetes.io/hostname"

7.3 部署应用

1.创建deployment资源,提供web服务,设定标签 app=web,副本数为3;
2.使用podAffinity规则告诉调度器将副本放到运行有标签app=stor Pod的节点上;
3.使用podAntiAffinity规则告诉调度器不要在同一节点上放置多个app=web的服务;

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: nginx
        image: nginx:1.18
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - store
            topologyKey: "kubernetes.io/hostname"
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web
            topologyKey: "kubernetes.io/hostname"

7.4 检查结果

[root@k8s-240 pod_affinity]# kubectl get pod -o wide
NAME                           READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
redis-server-99994f54c-jm4f9   1/1     Running   0          19s   10.244.149.165   flyfish82   <none>           <none>
redis-server-99994f54c-phtp5   1/1     Running   0          19s   10.244.157.152   flyfish83   <none>           <none>
web-server-75678446dd-bgccx    1/1     Running   0          13s   10.244.157.150   flyfish83   <none>           <none>
web-server-75678446dd-bmmts    1/1     Running   0          13s   10.244.149.158   flyfish82   <none>           <none>

8.nodeName

8.1 nodeName介绍

默认新创建的Pod,nodeName字段为空,会由scheduler来完成调度,如果在创建Pod明确指定了nodeName字段对应的值,比如指定为node01,那么调度器会忽略该Pod的调度,而是直接指定由node01节点的kubelet来运行对应的Pod。

  • 首先 nodeName 比 nodeSelector 亲和性更为直接;
  • 其次 nodeName 规则的优先级会高于使用nodeSelector或亲和性与非亲核性的规则。

8.2 nodeName局限

使用 nodeName为Pod选择节点的方式有一些局限性:

  • 1.当指定的节点不存在时 pod不会调度一直处于pending状态。
  • 2.如果所指定的节点无法提供Pod所需的资源,则会失败,失败的原因也会告知是因为内存还是cpu不足而造成的无法运行
  • 3.在云环境中节点名称并不是可预测的,也不总是稳定的。

8.3 nodeName实践

1.创建Pod,使用nodeName字段指定到特定的节点上运行。

cat nodeName-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: flyfish83
  containers:
  - name: nginx
    image: nginx

验证

[root@k8s-240 nodeName]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          38s   10.244.157.151   flyfish83   <none>           <none>

2.创建Pod,如果指定的节点无法提供Pod所需资源;

cat nodeName-resource.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  nodeName: flyfish83
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        cpu: 22
        memory: 2Gi

验证 如果节点资源不够,创建后会有如下提示

Events:
  Type     Reason    Age   From     Message
  ----     ------    ----  ----     -------
  Warning  OutOfcpu  20s   kubelet  Node didn't have enough resource: cpu, requested: 22000, used: 250, capacity: 4000

9. 污点与容忍度

此前我们了解过节点选择器、节点亲和或Pod亲和,都是让Pod选择节点的。就算是Pod亲和也是让Pod选节点的,无非就是Pod所参照系的那组Pod所在的节点,不在的节点,本质上还是Pod选节点的。节点只能被动的等待被挑选。那能不能让节点主动拒绝某类Pod的调度,那我们可以给某类节点打上特点的污点,让Pod无法调度到该类节点上,除非这类Pod他能容忍这些节点上的污点,这就是污点和容忍度概念。

9.1 什么是污点

污点是节点级的属性,我们可以在一个节点上给它设定一组特殊的属性,为了能给加形象的描述这组属性,我们将其称为污点。一旦对应的节点拥有了污点,Pod则无法调度到该节点上,除非它能容忍这些节点的污点,则可以正常调度到拥有污点的节点上。

值得一提的是,我们还可以给节点继续添加污点,如果已调度到该节点的Pod无法容忍新添加的污点,则该Pod会被驱离该节点,而这些需要在节点的五点上添加效用表示来完成。

9.2 什么是容忍度

容忍度(tolerations)是定义在Pod对象上的键值数据,用于配置该Pod可以容忍那些节点的污点以及污点的效用表示,这样就可以将pod调度到那些有污点的节点上。

9.3 污点与容忍度场景

场景1:
使用kubeadm部署的kubernetes集群的主节点默认由污点的,我们给主节点加上污点的主要作用在于避免用用Pod被调度和运行在主节点上面来,因为主节点上运行的APIServer、ControllerManager、Scheduler本身它们的系统压力就比较大,再把其他应用Pod调度到主节点上面来,所以事先为主节点添加了污点,而我们自定义的Pod没有容忍任何污点,所以无法调度到主节点上面来。

[root@master scheduler]# kubectl describe nodes
master
Taints:      node-role.kubernetes.io/master:NoSchedule
# 污点名称: node-role.kubernetes.io/master
# 污点效用标识: NoSchedule

场景2:
集群中由一组机器专门为测试环境的容器应用而设定,这些机器可能随时按需上下线,那就需要给这些机器添加上对应的污点,确保能容忍此污点的测试Pod可以调度上来,而这些生产的Pod则无法容忍这些污点,则不会调度到这些节点上。

9.4 如何给节点打污点

在实际生产环境中,污点通常用于描述具体的部署规划,它们的键名如: node-type、node-role、node-project等。kubectl taint 命令可以管理node对象的污点信息,语法格式如下:

# 语法: kubectl taint nodes <node-name> <key>=<value>:<effect>
# 示例:kubectl taint nodes node01 node-type=prod:NoExecute
  • effect: 污点有效标识,用于定义其对Pod对象的排斥等级
    NoSchedule

不能容忍污点的Pod被调度到当前节点,对现存的Pod无影响,属于强制约束关系;

NoExecute

无法容忍此污点的Pod无法调度至当前节点,同时节点上现存的Pod对象因污点变动或Pod的容忍度无法匹配条件是,Pod对象将会被驱逐,属于强制约束关系;

PreferNoSchedule

尽量确保无法容忍污点的Pod调度至当前节点,属于软性约束关系;

1.为node01节点添加一个污点,它的键名是node-type,键值是prod,效果是NoSchedule,这表示只拥有匹配此节点容忍度的Pod才会被调度至该节点,无此容忍度的Pod不会到此节点;

[root@k8s-240 nodeName]# kubectl taint nodes flyfish81 node-type=prod:NoSchedule
node/flyfish81 tainted

验证

[root@k8s-240 pod]# kubectl get pod -o wide 
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
nginx-dp-hnr55   1/1     Running   0          7s    10.244.149.166   flyfish82   <none>           <none>
nginx-dp-tgtg5   1/1     Running   0          7s    10.244.157.160   flyfish83   <none>           <none>

2.若要移除该节点对应的污点,可执行

[root@k8s-240 pod]# kubectl taint nodes flyfish81 node-type=prod:NoSchedule-
node/flyfish81 untainted

9.5 如何给Pod添加容忍度

Pod的容忍度在PodSpec中定义,根据使用的操作符不同,主要由两种可用形式:

  • 一种是与污点信息完全匹配的等值关系。将operator指定为Equal,怎它们的 key value effect应该相等;
  • 一种是判断污点信息存在性的匹配方式。将operator指定为Exists(此时容忍度无需指定value);
    1.定义一个与节点污点完全相匹配的容忍度Pod,它表示能够容忍键名为node-type,键值为Pord,下过为NoSchedule的污点。
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-dp
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx-container
        image: nginx:1.20
      tolerations:  #Pod能够容忍节点污点名为node-type,值为prod,效用表示为NoSchedule
      - key: "node-type"
        operator: "Equal"
        value: "prod"
        effect: "NoSchedule"

2.定义一个存在判断机制的容忍度,如下示例表示能够容忍以node.kubernetes.io/unreachable为键名的、效果为NoExcute的污点,其中tolerationSeconds用于定义驱逐当前Pod对象的时长。
比如,一个使用了很多本地状态的应用程序在网络断开时,节点控制器会自动给节点添加污点,如果仍然希望停留在当前节点上运行一段时间,等待网络恢复表面被驱逐。在这种情况下,Pod的容忍度可能是下面这样的;

apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
spec:
  containers:
  - name: nginx
    image: nginx:1.18
  tolerations:          #Pod容忍度定义
  - key: "node.kubernetes.io/unreachable"        #节点控制器根据节点情况会自动添加的污点
    operator: "Exists"
    effect: "NoExecute"
    tolerationSeconds: 6000                     #tolerationSeconds仅对效果为NoExecute的标识有效

9.6 污点与容忍度实践-1

此前我们通过daemonset部署的node-exporterm,会发现它无法运行在master节点上。但node-exporter它是用来抓取节点的指标信息,为监控服务提供数据,所以对于master而言,它也需要运行node-exporter,所以我们可以给对应的Pod添加能够容忍master节点的污点信息。
1.查看master节点的污点

kubectl describe nodes master |grep -i taints
Taints:               node-rile.kubernetes.io/master

2.修改node-exports部署的yaml文件,使其能够容忍master节点的污点

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: default
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels: 
        app: node-exporter
    spec:
      hostNetwork: true
      hostPID: true
      containers:
      - name: prometheus-node-exporter
        image: prom/node-exporter:v0.18.0
        ports:
        - name: node-ex-http
          containerPort: 9100
          hostPort: 9100
        livenessProbe:
          tcpSocket:
            port: node-ex-http
          initialDelaySeconds: 5
        readinessProbe:
          httpGet:
            path: '/metrics'
            port: node-ex-http
          initialDelaySeconds: 5
      tolerations:
      - key: "node-role.kubernetes.io/master" #容忍key为 node-role.kubernetes.io/master
        operator: "Exists"
        effect: "NoSchedule"                   #容忍的效用标识为NoSchedule

3.检查是否所有节点都有对应的node-exporters,包括master节点

[root@k8s-240 tain]# kubectl get pod
NAME                  READY   STATUS    RESTARTS   AGE
nginx-dp-69jkx        1/1     Running   0          3h33m
nginx-dp-kp772        1/1     Running   0          3h33m
nginx-dp-nzlmz        1/1     Running   0          3h33m
node-exporter-dmhhz   1/1     Running   0          92s
node-exporter-h2zwc   1/1     Running   0          3m19s
node-exporter-jnpp6   1/1     Running   0          3m19s

9.7 污点与容忍度实践-2

为node1添加node-type=prod的污点,只要能容忍该污点的Pod则为生产环境应用,则允许调度到node01节点。
为node2于node3添加node-type=test的污点,只要能够容忍该污点的Pod则为测试环境应用。则运行调度到node02、node03节点
1.为节点添加污点

[root@k8s-240 ~]# kubectl taint node flyfish81 node-type=prod:NoSchedule
node/flyfish81 tainted
[root@k8s-240 ~]# kubectl taint node flyfish82 node-type=test:NoSchedule
node/flyfish82 tainted
[root@k8s-240 ~]# kubectl taint node flyfish83 node-type=test:NoSchedule
node/flyfish83 tainted

2.创建一个生产环境Pod,配置对应的容忍度,则该Pod理应能正常调度到node01节点

cat 09-pod-tolerations-prod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-demo-prod
spec:
  replicas:  5
  selector:  # Selector for the deployment
    matchLabels:
      app: web
  template:  
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
      tolerations: 
        - key: "node-type"
          operator: "Equal"
          value: "prod"
          effect: "NoSchedule"

验证

[root@k8s-240 tain]# kubectl get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-demo-prod-76d485f4cd-64dnp   1/1     Running   0          103m   10.244.232.242   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-87wdt   1/1     Running   0          103m   10.244.232.236   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-db7jm   1/1     Running   0          103m   10.244.232.241   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-mmtt8   1/1     Running   0          103m   10.244.232.244   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-rpg68   1/1     Running   0          103m   10.244.232.243   flyfish81   <none>           <none>

3.创建一个测试环境Pod,配置对应的容忍度,则该Pod应能正常调度node02或者node03节点;

cat 10-pod-tolerations-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-demo-test
  spec:
    replicas: 5
  selector:  # Selector for the deployment
    matchLabels:
      app: web
  template: 
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.18
      tolerations:  # Tolerations for the deployment
        - key: "node-type"
          operator: "Equal"
          value: "test"
          effect: "NoSchedule"

验证

[root@k8s-240 tain]# kubectl get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-demo-test-57cc66c67f-8qhf4   1/1     Running   0          10s    10.244.157.161   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-d4ck2   1/1     Running   0          10s    10.244.157.162   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-g97hr   1/1     Running   0          10s    10.244.149.168   flyfish82   <none>           <none>
pod-demo-test-57cc66c67f-nrk4g   1/1     Running   0          10s    10.244.157.163   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-zz2ql   1/1     Running   0          10s    10.244.149.164   flyfish82   <none>           <none>

9.8 污点与容忍度实践-3

前面提到过污点的effect值NoExecute会影响已经在节点上运行的Pod

  • 如果Pod不能忍受effect值为NoExecute的污点,那么Pod将马上被驱逐
  • 如果Pod能够忍受effect值为NoExecute的污点,但是在容忍度定义中没有指定tolerationSeconds,则Pod会一直在该节点运行
  • 如果Pod能够忍受effect值为NoExecute的污点,同时指定了tolerationSeconds,则Pod能再这个节点上继续运行指定的时间长度,而后会被驱逐
    1.检查当前环境运行的Pod状态
[root@k8s-240 tain]# kubectl get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-demo-prod-76d485f4cd-64dnp   1/1     Running   0          103m   10.244.232.242   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-87wdt   1/1     Running   0          103m   10.244.232.236   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-db7jm   1/1     Running   0          103m   10.244.232.241   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-mmtt8   1/1     Running   0          103m   10.244.232.244   flyfish81   <none>           <none>
pod-demo-prod-76d485f4cd-rpg68   1/1     Running   0          103m   10.244.232.243   flyfish81   <none>           <none>
pod-demo-test-57cc66c67f-8qhf4   1/1     Running   0          10s    10.244.157.161   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-d4ck2   1/1     Running   0          10s    10.244.157.162   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-g97hr   1/1     Running   0          10s    10.244.149.168   flyfish82   <none>           <none>
pod-demo-test-57cc66c67f-nrk4g   1/1     Running   0          10s    10.244.157.163   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-zz2ql   1/1     Running   0          10s    10.244.149.164   flyfish82   <none>           <none>

2.给node03节点添加污点,如果Pod无法容忍该污点,则会被驱逐到其他节点上继续运行。

kubectl taint nodes flyfish81 node-wh:NoExecute

3.Pod如果无法容忍该节点对应的污点,则会被驱逐此节点
没执行污点标记之前

[root@k8s-240 tain]# kubectl get pods -o wide
NAME                             READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-demo-test-57cc66c67f-8qhf4   1/1     Running   0          150m   10.244.157.161   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-d4ck2   1/1     Running   0          150m   10.244.157.162   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-g97hr   1/1     Running   0          150m   10.244.149.168   flyfish82   <none>           <none>
pod-demo-test-57cc66c67f-nrk4g   1/1     Running   0          150m   10.244.157.163   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-zz2ql   1/1     Running   0          150m   10.244.149.164   flyfish82   <none>           <none>

执行污点标记后

pod-demo-test-57cc66c67f-8qhf4   1/1     Running   0          151m   10.244.157.161   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-blptd   1/1     Running   0          9s     10.244.157.165   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-d4ck2   1/1     Running   0          151m   10.244.157.162   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-nrk4g   1/1     Running   0          151m   10.244.157.163   flyfish83   <none>           <none>
pod-demo-test-57cc66c67f-xv8v5   1/1     Running   0          10s    10.244.157.164   flyfish83   <none>           <none>
posted @ 2021-09-11 09:55  老夫聊发少年狂88  阅读(77)  评论(0编辑  收藏  举报