【考点】CKA 08_Kubernetes工作负载与调度 关系调度 nodeSelector 亲和性和反亲和性 污点 节点驱离与下线

文章目录

  • 考试题目:deployment 扩容(扩容命令)
  • 1. Kubernetes 调度器
    • 1.1 调度概览
    • 1.2 kube-scheduler
    • 1.3 kube-scheduler 调度流程
  • 2. Kubernetes 关系调度
    • 2.1 节点标签
    • 2.2 节点隔离/限制
    • 2.3 nodeName 字段
      • 2.3.1 准备工作
      • 2.3.2 创建使用 nodeName 字段的 Pod
      • 2.3.3 模拟故障
    • 2.4 nodeSelector 标签
      • 2.4.1 创建使用 nodeSelector 的 Pod
      • 2.4.2 模拟故障
    • 2.5 亲和性与反亲和性
    • 2.6 节点亲和性
      • 2.6.1 必须满足
      • 2.6.2 倾向满足
    • 2.7 pod 间亲和性与反亲和性
    • 2.8 pod 亲和性
    • 2.9 pod反亲和性
    • 2.10 污点
      • 2.10.1 NoSchedule
      • 2.10.2 NoExecute
      • 2.10.3 容忍度
    • 2.11 cordon、drain 和 delete
      • 2.11.1 cordon 停止调度
      • 2.11.2 drain 直接驱离
      • 2.11.3 uncordon 上线
      • 2.11.4 delete 节点下线
  • 考试题目:节点 k8s-3 出现问题,master 上显示不可达

考试题目:deployment 扩容(扩容命令)

1. Kubernetes 调度器

官方文档:概念 | 调度,抢占和驱逐 | Kubernetes 调度器

  • 在 Kubernetes 中,调度 是指将 Pod 放置到合适的 Node 上,然后对应 Node 上的 Kubelet 才能够运行这些 pod。

1.1 调度概览

  • 调度器通过 kubernetes 的监测(Watch)机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。 调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。 调度器会依据下文的调度原则来做出调度选择。

1.2 kube-scheduler

  • kube-scheduler 是 Kubernetes 集群的默认调度器,并且是集群 控制面 的一部分。 如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许 你自己写一个调度组件并替换原有的 kube-scheduler。

  • 对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的 Node 去运行这个 Pod。然而,Pod 内的每一个容器对资源都有不同的需求,而且 Pod 本身也有不同的资源需求。因此,Pod 在被调度到 Node 上之前, 根据这些特定的资源调度需求,需要对集群中的 Node 进行一次过滤。

  • 在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为 可调度节点。 如果没有任何一个 Node 能满足 Pod 的资源请求,那么这个 Pod 将一直停留在 未调度状态直到调度器能够找到合适的 Node。

  • 调度器先在集群中找到一个 Pod 的所有可调度节点,然后根据一系列函数对这些可调度节点打分, 选出其中得分最高的 Node 来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做 绑定。

  • 在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、 亲和以及反亲和要求、数据局域性、负载间的干扰等等。

1.3 kube-scheduler 调度流程

  • kube-scheduler 给一个 pod 做调度选择包含两个步骤:

    1. 过滤
    2. 打分
  • 过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。 例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。 在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下, 这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。

  • 在打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。 根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。

  • 最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。 如果存在多个得分最高的 Node,kube-scheduler 会从中随机选取一个。

  • 支持以下两种方式配置调度器的过滤和打分行为:

    1. 调度策略 允许你配置过滤的 断言(Predicates) 和打分的 优先级(Priorities) 。
    2. 调度配置 允许你配置实现不同调度阶段的插件, 包括:QueueSort, Filter, Score, Bind, Reserve, Permit 等等。 你也可以配置 kube-scheduler 运行不同的配置文件。

2. Kubernetes 关系调度

官方文档: 概述 | 调度,抢占和驱逐 | 将 Pod 指派给 节点

将 Pod 指派给节点

  • 你可以约束一个 Pod 只能在特定的节点上运行。 有几种方法可以实现这点,推荐的方法都是用 标签选择算符来进行选择。 通常这样的约束不是必须的,因为调度器将自动进行合理的放置(比如,将 Pod 分散到节点上, 而不是将 Pod 放置在可用资源不足的节点上等等)。但在某些情况下,你可能需要进一步控制 Pod 被部署到的节点。例如,确保 Pod 最终落在连接了 SSD 的机器上, 或者将来自两个不同的服务且有大量通信的 Pods 被放置在同一个可用区。

  • 你可以使用下列方法中的任何一种来选择 Kubernetes 对特定 Pod 的调度:

    • 与节点标签匹配的 nodeSelector
    • 亲和性与反亲和性
    • nodeName 字段

2.1 节点标签

  • 与很多其他 Kubernetes 对象类似,节点也有标签。 你可以手动地添加标签。 Kubernetes 也会为集群中所有节点添加一些标准的标签。

2.2 节点隔离/限制

  • 通过为节点添加标签,你可以准备让 Pod 调度到特定节点或节点组上。 你可以使用这个功能来确保特定的 Pod 只能运行在具有一定隔离性,安全性或监管属性的节点上。

  • 如果使用标签来实现节点隔离,建议选择节点上的 kubelet 无法修改的标签键。 这可以防止受感染的节点在自身上设置这些标签,进而影响调度器将工作负载调度到受感染的节点。

2.3 nodeName 字段

官方文档: 概述 | 调度,抢占和驱逐 | 将 Pod 指派给 节点 | nodeName

2.3.1 准备工作

  • nodeName 是比亲和性或者 nodeSelector 更为直接的形式。nodeName 是 Pod 规约中的一个字段。如果 nodeName 字段不为空,调度器会忽略该 Pod, 而指定节点上的 kubelet 会尝试将 Pod 放到该节点上。 使用 nodeName 规则的优先级会高于使用 nodeSelector 或亲和性与非亲和性的规则。

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

    • 如果所指代的节点不存在,则 Pod 无法运行,而且在某些情况下可能会被自动删除。
    • 如果所指代的节点无法提供用来运行 Pod 所需的资源,Pod 会失败, 而其失败原因中会给出是否因为内存或 CPU 不足而造成无法运行。
    • 在云环境中的节点名称并不总是可预测的,也不总是稳定的。
  • nodeName 是节点选择约束的最简单方法,但一般不推荐

2.3.2 创建使用 nodeName 字段的 Pod

  1. 创建在 k8s-3 主机上运行的 Pod
[root@k8s-1 ~]# vim nodename.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: k8s-3
  1. 生效后,查看状态
[root@k8s-1 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          29s   10.244.2.34   k8s-3   <none>           <none>

2.3.3 模拟故障

  1. 假设要求 Pod 运行在 4 号主机上,实际 4 号主机是不存在的。这个时候,Pod 会一直处于 pending 状态,无法运行。
[root@k8s-1 ~]# vim nodename.yaml
  nodeName: k8s-4

【考点】CKA 08_Kubernetes工作负载与调度 关系调度 nodeSelector 亲和性和反亲和性 污点 节点驱离与下线_第1张图片

  1. 生效后,查看状态
[root@k8s-1 ~]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          6s
  1. 一般很少使用 nodeName 字段指定 Pod 运行在节点上

2.4 nodeSelector 标签

官方文档:概述 | 调度,抢占和驱逐 | nodeSelector

  • nodeSelector 是节点选择约束的最简单推荐形式。你可以将 nodeSelector 字段添加到 Pod 的规约中设置你希望目标节点所具有的节点标签。 Kubernetes 只会将 Pod 调度到拥有你所指定的每个标签的节点上。

2.4.1 创建使用 nodeSelector 的 Pod

  1. 运行 Pod 到有 ssd 标签的 node 上
[root@k8s-1 ~]# vim nodeSelector.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
  1. 给选择的 node k8s-3 主机添加标签 ssd
[root@k8s-1 ~]# kubectl label nodes k8s-3 disktype=ssd
node/k8s-3 labeled
[root@k8s-1 ~]# kubectl get nodes --show-labels 
NAME    STATUS   ROLES                  AGE     VERSION   LABELS
k8s-1   Ready    control-plane,master   4h28m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-2   Ready    <none>                 4h2m    v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-2,kubernetes.io/os=linux
k8s-3   Ready    <none>                 3h56m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-3,kubernetes.io/os=linux
  1. 生效 Pod 配置,查看 Pod 状态。Pod 运行到 k8s-3 主机上
[root@k8s-1 ~]# kubectl apply -f nodeSelector.yaml 
pod/nginx created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          8s    10.244.2.35   k8s-3   <none>           <none>

2.4.2 模拟故障

  1. 删除 k8s-3 主机的标签 ssd
[root@k8s-1 ~]# kubectl label nodes k8s-3 disktype-
node/k8s-3 labeled
  1. 查看 Pod 状态,发现依旧正常处于 running 状态。
  • 因为pod已经在运行中了,数据包已经通过了。现在变更标签没有用
[root@k8s-1 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          46s   10.244.2.35   k8s-3   <none>           <none>
  1. 删除 Pod 后,再次生效 Pod 配置,发现 Pod 的状态处于 Pending
  • 因为所有的主机都没有对应的标签
[root@k8s-1 ~]# kubectl delete -f nodeSelector.yaml --force 
[root@k8s-1 ~]# kubectl apply -f nodeSelector.yaml 
pod/nginx created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
nginx   0/1     Pending   0          3s    <none>   <none>   <none>           <none>
  1. 假设现在选择 k8s-2 主机,给它添加标签 ssd。发现 Pod 恢复运行正常
[root@k8s-1 ~]# kubectl label nodes k8s-2 disktype=ssd
node/k8s-2 labeled
[root@k8s-1 ~]# kubectl get pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          56s   10.244.1.42   k8s-2   <none>           <none>
  1. 最后为了避免出现上述 Pending 的状态,最好多给几个 node 添加上 ssd 标签
[root@k8s-1 ~]# kubectl label nodes k8s-3 disktype=ssd
node/k8s-3 labeled
[root@k8s-1 ~]# kubectl get nodes --show-labels 
NAME    STATUS   ROLES                  AGE     VERSION   LABELS
k8s-1   Ready    control-plane,master   4h32m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-2   Ready    <none>                 4h6m    v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-2,kubernetes.io/os=linux
k8s-3   Ready    <none>                 3h59m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-3,kubernetes.io/os=linux

以上是节点层面的调度,限制 Pod 调度到哪个 node 上

【pod与pod之间的,两个业务之间的通信和调度】

解决pod和node的亲和性

2.5 亲和性与反亲和性

官方文档:概念 | 调度,抢占和驱逐

  • nodeSelector 提供了一种最简单的方法来将 Pod 约束到具有特定标签的节点上。 亲和性和反亲和性扩展了你可以定义的约束类型。使用亲和性与反亲和性的一些好处有:

    • 亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择拥有所有指定标签的节点。 亲和性、反亲和性为你提供对选择逻辑的更强控制能力。
    • 你可以标明某规则是“软需求”或者“偏好”,这样调度器在无法找到匹配节点时仍然调度该 Pod。
    • 你可以使用节点上(或其他拓扑域中)运行的其他 Pod 的标签来实施调度约束, 而不是只能使用节点本身的标签。这个能力让你能够定义规则允许哪些 Pod 可以被放置在一起。

2.6 节点亲和性

  • 节点亲和性概念上类似于 nodeSelector, 它使你可以根据节点上的标签来约束 Pod 可以调度到哪些节点上。 节点亲和性有两种:

    • requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。(必须满足)
    • preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该 Pod。(倾向满足,尽力而为,有最好,没有也没关系)
  • Note:
    在上述类型中,IgnoredDuringExecution 意味着如果节点标签在 Kubernetes 调度 Pod 时发生了变更,Pod 仍将继续运行。

  • nodeaffinity还支持多种规则匹配条件的配置如

    • In:label 的值在列表内
    • NotIn:label 的值不在列表内
    • Gt:label 的值大于设置的值,不支持Pod亲和性
    • Lt:label 的值小于设置的值,不支持pod亲和性
    • Exists:设置的label 存在
    • DoesNotExist:设置的 label 不存在

2.6.1 必须满足

  1. 创建 Pod 设置 “ 必须满足 ”
[root@k8s-1 ~]# vim nodeAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
              - ssd
  1. 生效后,查看状态
  • 注意,2 个 node k8s-2 k8s-3 主机上都有 ssd 标签,Pod 则选择在 k8s-2 上运行
[root@k8s-1 ~]# kubectl apply -f nodeAffinity.yaml 
pod/node-affinity created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          18s   10.244.1.43   k8s-2   <none>           <none>

2.6.2 倾向满足

  1. 创建 Pod 设置 “ 倾向满足 ”
[root@k8s-1 ~]# vim nodeAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
              - ssd
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: zone
            operator: In
            values:
            - v1
  1. 给 k8s-3 主机添加 v1 标签
  • ssd 标签在 k8s-2 和 k8s-3 主机
  • v1 标签在 k8s-3 主机
[root@k8s-1 ~]# kubectl label nodes k8s-3 zone=v1
node/k8s-3 labeled
[root@k8s-1 ~]# kubectl get nodes --show-labels 
NAME    STATUS   ROLES                  AGE     VERSION   LABELS
k8s-1   Ready    control-plane,master   4h43m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-2   Ready    <none>                 4h17m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-2,kubernetes.io/os=linux
k8s-3   Ready    <none>                 4h11m   v1.22.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-3,kubernetes.io/os=linux,zone=v1
  1. 删除之前创建的 Pod
[root@k8s-1 ~]# kubectl delete -f nodeAffinity.yaml --force 
  1. 生效后,创建新的 Pod
[root@k8s-1 ~]# kubectl apply -f nodeAffinity.yaml 
pod/node-affinity created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          27s   10.244.2.37   k8s-3   <none>           <none>
  • 查看 Pod 的状态
[root@k8s-1 ~]# kubectl describe pod node-affinity
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  97s   default-scheduler  Successfully assigned default/node-affinity to k8s-3
  Normal  Pulling    96s   kubelet            Pulling image "nginx"
  Normal  Pulled     90s   kubelet            Successfully pulled image "nginx" in 6.15509625s
  Normal  Created    89s   kubelet            Created container nginx
  Normal  Started    88s   kubelet            Started container nginx

2.7 pod 间亲和性与反亲和性

  • pod 亲和性和反亲和性

    • podAffinity 主要解决POD可以和哪些POD部署在同一个拓扑域中的问题(拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等。)
    • podAntiAffinity主要解决POD不能和哪些POD部署在同一个拓扑域中的问题。它们处理的是Kubernetes集群内部POD和POD之间的关系。
    • Pod 间亲和与反亲和在与更高级别的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用时,它们可能更加有用。可以轻松配置一组应位于相同定义拓扑(例如,节点)中的工作负载。
    • Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。
  • 与节点亲和性类似,Pod 的亲和性与反亲和性也有两种类型:

    requiredDuringSchedulingIgnoredDuringExecution
    preferredDuringSchedulingIgnoredDuringExecution

  • 例如,你可以使用 requiredDuringSchedulingIgnoredDuringExecution 亲和性来告诉调度器, 将两个服务的 Pod 放到同一个云提供商可用区内,因为它们彼此之间通信非常频繁。 类似地,你可以使用 preferredDuringSchedulingIgnoredDuringExecution 反亲和性来将同一服务的多个 Pod 分布到多个云提供商可用区中。

  • 要使用 Pod 间亲和性,可以使用 Pod 规约中的 .affinity.podAffinity 字段。 对于 Pod 间反亲和性,可以使用 Pod 规约中的 .affinity.podAntiAffinity 字段。

2.8 pod 亲和性

  1. 创建 Pod,使用 亲和性 告诉调度器,将 Pod 与具有 nginx 标签的 Pod 运行在一起
[root@k8s-1 ~]# vim podAffinity.yaml
apiVersion: v1
kind: Pod
metadata:
  name: zabbix
  labels:
    app: zabbix
spec:
  containers:
  - name: zabbix
    image: zabbix/zabbix-agent
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname
  1. 因为当前没有具有 nginx 标签的 Pod,生效后发现,Pod 处于 Pending 状态
[root@k8s-1 ~]# kubectl apply -f podAffinity.yaml 
pod/zabbix created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP            NODE     NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          8s    10.244.2.38   k8s-3    <none>           <none>
zabbix          0/1     Pending   0          39s   <none>        <none>   <none>           <none>
  1. 给另一个 Pod 加上 nginx 的标签
[root@k8s-1 ~]# kubectl label pod node-affinity app=nginx
pod/node-affinity labeled
  1. 查看状态,发现 Pod 处于 running 状态,且两个 Pod 运行在同一个 node 上
[root@k8s-1 ~]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          86s    10.244.2.38   k8s-3   <none>           <none>
zabbix          1/1     Running   0          117s   10.244.2.39   k8s-3   <none>           <none>
[root@k8s-1 ~]# kubectl get pod --show-labels 
NAME            READY   STATUS    RESTARTS   AGE     LABELS
node-affinity   1/1     Running   0          2m8s    app=nginx
zabbix          1/1     Running   0          2m39s   app=zabbix
  • 名为 zabbix 的 Pod 发现名为 node-affinity 的 Pod 上有指定的 nginx 标签。于是,zabbix 就会跟着 node-affinity 一起运行在同一个 node 上。

Pod 亲和性解决 Pod 与 Pod 之间的关系
node 亲和性解决 Pod 与 node 之间的关系

2.9 pod反亲和性

  1. 创建 Pod,使用 反亲和性 告诉调度器,将 Pod 与具有 nginx 标签的 Pod 运行在一起
[root@k8s-1 ~]# cp podAffinity.yaml podantiAffinity.yaml 
[root@k8s-1 ~]# vim podantiAffinity.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: zabbix
  labels:
    app: zabbix
spec:
  containers:
  - name: zabbix
    image: zabbix/zabbix-agent
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname
  1. 查看当前运行的 Pod 的标签
[root@k8s-1 ~]# kubectl get pod --show-labels 
NAME            READY   STATUS    RESTARTS   AGE     LABELS
node-affinity   1/1     Running   0          5m20s   app=nginx
  1. 生效后,查看两个 Pod 的运行状态
[root@k8s-1 ~]# kubectl apply -f podantiAffinity.yaml 
pod/zabbix created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME            READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          6m1s   10.244.2.38   k8s-3   <none>           <none>
zabbix          1/1     Running   0          23s    10.244.1.44   k8s-2   <none>           <none>
[root@k8s-1 ~]# kubectl get pod --show-labels 
NAME            READY   STATUS    RESTARTS   AGE    LABELS
node-affinity   1/1     Running   0          6m9s   app=nginx
zabbix          1/1     Running   0          31s    app=zabbix

2.10 污点

官方文档:概念 | 调度,抢占和驱逐 | 污点和容忍度

  • NodeAffinity 节点亲和性,是 Pod 上定义的一种属性,使 Pod 能够按我们的要求调度到某个 Node 上,而 Taints 则恰恰相反,它可以让 Node 拒绝运行 Pod,甚至驱逐 Pod。

  • Taints (污点) 是 Node 的一个属性,设置了 Taints 后,所以 Kubernetes 是不会将 Pod 调度到这个 Node 上的,于是 Kubernetes 就给 Pod 设置了个属性 Tolerations (容忍),只要 Pod 能够容忍 Node 上的污点,那么 Kubernetes 就会忽略 Node 上的污点,就能够(不是必须)把 Pod 调度过去。

  • master 为什么不参与调度?
    因为 master 上有 NoSchedule 的污点

[root@k8s-1 ~]# kubectl describe nodes k8s-1 | grep -i taint
Taints:             node-role.kubernetes.io/master:NoSchedule
  • NoSchedule:POD 不会被调度到标记为 taints 节点。
  • PreferNoSchedule:NoSchedule 的软策略版本。
  • NoExecute:该选项意味着一旦 Taint 生效,如该节点内正在运行的 POD 没有对应 Tolerate 设置,会直接被逐出。

2.10.1 NoSchedule

  1. 给 k8s-2 主机添加 NoSchedule 污点
    (不允许 k8s-2 调度)
[root@k8s-1 ~]# kubectl taint nodes k8s-2 k1=v1:NoSchedule
node/k8s-2 tainted
  1. 修改之前的 Deployment 的 YAML 清单,副本数为3
[root@k8s-1 ~]# vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-example
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
  1. 生效后,查看 Pod 的运行状态

[root@k8s-1 ~]# kubectl apply -f deployment.yaml 
deployment.apps/deployment-example created
  • 发现所有的 Pod 都运行在了 k8s-3 主机上
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-2wz98   1/1     Running   0          32s   10.244.2.40   k8s-3   <none>           <none>
deployment-example-6799fc88d8-skds4   1/1     Running   0          32s   10.244.2.42   k8s-3   <none>           <none>
deployment-example-6799fc88d8-w8s7m   1/1     Running   0          32s   10.244.2.41   k8s-3   <none>           <none>
  • k8s-2 上有 污点,k8s-3 上没有污点
[root@k8s-1 ~]# kubectl describe nodes k8s-2 | grep -i taint
Taints:             k1=v1:NoSchedule
[root@k8s-1 ~]# kubectl describe nodes k8s-3 | grep -i taint
Taints:             <none>

2.10.2 NoExecute

1:
在server3上加NoExectue
get pod
发现3个pod都被驱离,pending

  1. 给 k8s-3 主机上添加 NoExecute 污点
[root@k8s-1 ~]# kubectl taint nodes k8s-3 k1=v1:NoExecute
node/k8s-3 tainted
  1. 查看添加 污点 后,Pod 的运行状态
  • 发现所有的 Pod 处于 Pending 状态,因为两个 node 上都有污点,Pod 不会在它们上运行
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-6xbct   0/1     Pending   0          6s    <none>   <none>   <none>           <none>
deployment-example-6799fc88d8-c9k6f   0/1     Pending   0          7s    <none>   <none>   <none>           <none>
deployment-example-6799fc88d8-jt9t2   0/1     Pending   0          6s    <none>   <none>   <none>           <none>

2.10.3 容忍度

  1. 为了解决上述 Pending 状态的问题,可以删除 k8s-2 上污点

[root@k8s-1 ~]# kubectl taint nodes k8s-2 k1:NoSchedule-
node/k8s-2 untainted
  • 查看 Pod 的状态,发现恢复正常,都处于 running 的状态。
  • 所有的 Pod 都运行在了 k8s-2 主机上了
  • 但是,生产环境下不能随便删除 污点
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-6xbct   1/1     Running   0          103s   10.244.1.47   k8s-2   <none>           <none>
deployment-example-6799fc88d8-c9k6f   1/1     Running   0          104s   10.244.1.45   k8s-2   <none>           <none>
deployment-example-6799fc88d8-jt9t2   1/1     Running   0          103s   10.244.1.46   k8s-2   <none>           <none>
[root@k8s-1 ~]# kubectl describe nodes k8s-2 | grep -i taint
Taints:             <none>
  • 现在恢复 k8s-2 主机的 污点
[root@k8s-1 ~]# kubectl taint nodes k8s-2 k1=v1:NoSchedule
node/k8s-2 tainted
[root@k8s-1 ~]# kubectl describe nodes k8s-2 | grep -i taint
Taints:             k1=v1:NoSchedule
  • 查看 Pod 的运行状态后,发现所有的 Pod 并没有受到影响,依旧处于 running 的正常状态。
  • 这是因为给 k8s-2 主机设置的污点是 NoSchedule,它不会对已经运行的 Pod 产生影响
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-6xbct   1/1     Running   0          3m2s   10.244.1.47   k8s-2   <none>           <none>
deployment-example-6799fc88d8-c9k6f   1/1     Running   0          3m3s   10.244.1.45   k8s-2   <none>           <none>
deployment-example-6799fc88d8-jt9t2   1/1     Running   0          3m2s   10.244.1.46   k8s-2   <none>           <none>
  • 但是,在这种情况下创建新的 Pod 时,就会出现 Pending 的错误
[root@k8s-1 ~]# kubectl scale deployment deployment-example --replicas=6
deployment.apps/deployment-example scaled
[root@k8s-1 ~]# kubectl get pod 
NAME                                  READY   STATUS    RESTARTS   AGE
deployment-example-6799fc88d8-2v8s7   0/1     Pending   0          9s
deployment-example-6799fc88d8-6xbct   1/1     Running   0          3m42s
deployment-example-6799fc88d8-bfn7r   0/1     Pending   0          9s
deployment-example-6799fc88d8-c9k6f   1/1     Running   0          3m43s
deployment-example-6799fc88d8-jt9t2   1/1     Running   0          3m42s
deployment-example-6799fc88d8-mlqr2   0/1     Pending   0          9s
  1. 为了解决上述 Pending 状态的问题,除了删除 污点 的方法外,还可以设置 容忍度
  • 对 deployment 执行 edit 操作,设置 容忍度,要求容忍所有的 污点
[root@k8s-1 ~]# kubectl edit deployments.apps deployment-example 
    spec:
      tolerations:
      - operator: "Exists"
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: nginx

【考点】CKA 08_Kubernetes工作负载与调度 关系调度 nodeSelector 亲和性和反亲和性 污点 节点驱离与下线_第2张图片

  • 查看 Pod 的运行状态,发现处于 running 状态
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-65797dc965-4jdk7   1/1     Running   0          49s   10.244.1.48   k8s-2   <none>           <none>
deployment-example-65797dc965-bxdlx   1/1     Running   0          53s   10.244.2.46   k8s-3   <none>           <none>
deployment-example-65797dc965-jppj6   1/1     Running   0          64s   10.244.2.45   k8s-3   <none>           <none>
deployment-example-65797dc965-twlb2   1/1     Running   0          65s   10.244.2.43   k8s-3   <none>           <none>
deployment-example-65797dc965-xf9cg   1/1     Running   0          41s   10.244.2.47   k8s-3   <none>           <none>
deployment-example-65797dc965-zphk6   1/1     Running   0          65s   10.244.2.44   k8s-3   <none>           <none>
  • 做完这个实验之后需要恢复初始环境
  • 删除 k8s-2 和 k8s-3 主机上的 污点
  • k8s-1 主机的 污点 不要动
[root@k8s-1 ~]# kubectl describe nodes k8s-2 | grep -i taint
Taints:             k1=v1:NoSchedule
[root@k8s-1 ~]# kubectl describe nodes k8s-3 | grep -i taint
Taints:             k1=v1:NoExecute
[root@k8s-1 ~]# kubectl describe nodes k8s-1 | grep -i taint
Taints:             node-role.kubernetes.io/master:NoSchedule
[root@k8s-1 ~]# kubectl taint node k8s-2 k1=v1:NoSchedule-
node/k8s-2 untainted
[root@k8s-1 ~]# kubectl taint node k8s-3 k1=v1:NoExecute-
node/k8s-3 untainted
[root@k8s-1 ~]# kubectl describe nodes k8s-1 | grep -i taint
Taints:             node-role.kubernetes.io/master:NoSchedule
[root@k8s-1 ~]# kubectl describe nodes k8s-2 | grep -i taint
Taints:             <none>
[root@k8s-1 ~]# kubectl describe nodes k8s-3 | grep -i taint
Taints:             <none>

2.11 cordon、drain 和 delete

  • 影响 Pod 调度的指令还有:cordon、drain、delete,后期创建的 pod 都不会被调度到该节点上,但操作的暴力程度不一样。

2.11.1 cordon 停止调度

  • 影响最小,只会将node调为SchedulingDisabled,新创建pod,不会被调度到该节点,节点原有pod不受影响,仍正常对外提供服务。
  1. 修改 deployment 的 YAML 清单,创建 3 个 Pod
[root@k8s-1 ~]# vim deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-example
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
  1. 生效后,查看 Pod 的运行状态
[root@k8s-1 ~]# kubectl apply -f deployment.yaml 
deployment.apps/deployment-example created
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-g4xl7   1/1     Running   0          14s   10.244.2.48   k8s-3   <none>           <none>
deployment-example-6799fc88d8-xn7m6   1/1     Running   0          14s   10.244.1.49   k8s-2   <none>           <none>
deployment-example-6799fc88d8-z5p9b   1/1     Running   0          14s   10.244.2.49   k8s-3   <none>           <none>
  1. 现在将 k8s-2 主机下线
[root@k8s-1 ~]# kubectl cordon k8s-2
node/k8s-2 cordoned
  • 查看当前 node 的状态,发现 k8s-2 处于 SchedulingDisabled 的状态,不接受调度
[root@k8s-1 ~]# kubectl get nodes
NAME    STATUS                     ROLES                  AGE     VERSION
k8s-1   Ready                      control-plane,master   5h16m   v1.22.1
k8s-2   Ready,SchedulingDisabled   <none>                 4h50m   v1.22.1
k8s-3   Ready                      <none>                 4h44m   v1.22.1
  1. 查看 Pod 的状态
  • 发现 k8s-2 上的 Pod 都处于 running 的状态
  • 虽然 k8s-2 下线,但是,这个操作不会影响已经运行的 Pod
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-g4xl7   1/1     Running   0          82s   10.244.2.48   k8s-3   <none>           <none>
deployment-example-6799fc88d8-xn7m6   1/1     Running   0          82s   10.244.1.49   k8s-2   <none>           <none>
deployment-example-6799fc88d8-z5p9b   1/1     Running   0          82s   10.244.2.49   k8s-3   <none>           <none>

2.11.2 drain 直接驱离

  1. 在 cordon k8s-2 的基础上,将 k8s-3 驱离,令其处于 不可调度 的状态
  • 记得 每个 node 上都运行了一个 DaemonSet,需要添加额外的参数 –ignore-daemonsets
  • 还需要注意的是,如果当前节点上有临时存储,出现卡顿,那么除了 --ignore-daemonsets 参数外,还需要添加 –delete-emptydir–date=false 参数
[root@k8s-1 ~]# kubectl drain k8s-3  
node/k8s-3 cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/kube-flannel-ds-74mkz, kube-system/kube-proxy-qc4tt
evicting pod default/deployment-example-6799fc88d8-z5p9b
evicting pod default/deployment-example-6799fc88d8-g4xl7
pod/deployment-example-6799fc88d8-z5p9b evicted
pod/deployment-example-6799fc88d8-g4xl7 evicted
node/k8s-3 evicted
  1. 查看 node 的运行状态
[root@k8s-1 ~]# kubectl get nodes 
NAME    STATUS                     ROLES                  AGE     VERSION
k8s-1   Ready                      control-plane,master   5h18m   v1.22.1
k8s-2   Ready,SchedulingDisabled   <none>                 4h52m   v1.22.1
k8s-3   Ready,SchedulingDisabled   <none>                 4h46m   v1.22.1
  1. 查看 Pod 的运行状态
  • 发现之前在 k8s-3 上运行的 Pod 都处于 Pending 状态,所有的 Pod 被驱离
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-xn7m6   1/1     Running   0          2m34s   10.244.1.49   k8s-2    <none>           <none>
deployment-example-6799fc88d8-xp42n   0/1     Pending   0          5s      <none>        <none>   <none>           <none>
deployment-example-6799fc88d8-zjfg8   0/1     Pending   0          5s      <none>        <none>   <none>           <none>

2.11.3 uncordon 上线

  1. 恢复 k8s-2
[root@k8s-1 ~]# kubectl uncordon k8s-2
node/k8s-2 uncordoned
  1. 查看 node 的状态
[root@k8s-1 ~]# kubectl get nodes
NAME    STATUS                     ROLES                  AGE     VERSION
k8s-1   Ready                      control-plane,master   5h20m   v1.22.1
k8s-2   Ready                      <none>                 4h53m   v1.22.1
k8s-3   Ready,SchedulingDisabled   <none>                 4h47m   v1.22.1
  1. 查看 Pod 的状态,发现所有 Pod 都在被调度到了 k8s-2 上了,running
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE    IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-xn7m6   1/1     Running   0          4m9s   10.244.1.49   k8s-2   <none>           <none>
deployment-example-6799fc88d8-xp42n   1/1     Running   0          100s   10.244.1.51   k8s-2   <none>           <none>
deployment-example-6799fc88d8-zjfg8   1/1     Running   0          100s   10.244.1.50   k8s-2   <none>           <none>
  1. 恢复 k8s-3
[root@k8s-1 ~]# kubectl uncordon k8s-3
node/k8s-3 uncordoned
  • 查看 node 的运行状态
[root@k8s-1 ~]# kubectl get nodes
NAME    STATUS   ROLES                  AGE     VERSION
k8s-1   Ready    control-plane,master   5h20m   v1.22.1
k8s-2   Ready    <none>                 4h53m   v1.22.1
k8s-3   Ready    <none>                 4h47m   v1.22.1
  • 查看 pod 的运行状态
[root@k8s-1 ~]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE     IP            NODE    NOMINATED NODE   READINESS GATES
deployment-example-6799fc88d8-xn7m6   1/1     Running   0          4m39s   10.244.1.49   k8s-2   <none>           <none>
deployment-example-6799fc88d8-xp42n   1/1     Running   0          2m10s   10.244.1.51   k8s-2   <none>           <none>
deployment-example-6799fc88d8-zjfg8   1/1     Running   0          2m10s   10.244.1.50   k8s-2   <none>           <none>

2.11.4 delete 节点下线

  1. 下线 k8s-3 (中途会将其上运行的 Pod 迁移到其他 node)
[root@k8s-1 ~]# kubectl drain k8s-3 --ignore-daemonsets
node/k8s-3 cordoned
WARNING: ignoring DaemonSet-managed Pods: kube-system/kube-flannel-ds-74mkz, kube-system/kube-proxy-qc4tt
node/k8s-3 drained
  1. 节点下线
[root@k8s-1 ~]# kubectl delete nodes k8s-3
node "k8s-3" deleted
  1. 查看 node 的状态
[root@k8s-1 ~]# kubectl get nodes
NAME    STATUS   ROLES                  AGE     VERSION
k8s-1   Ready    control-plane,master   5h22m   v1.22.1
k8s-2   Ready    <none>                 4h55m   v1.22.1

考试题目:节点 k8s-3 出现问题,master 上显示不可达

  • 题目:节点 k8s-3 出现问题,master 上显示不可达

  • 思路:

    • 首先检测 kubelet 的状态,发现 守护进程 kubelet 没有启动;
    • 先 enable kubelet;
    • 再 restart kubelet
    • 这样就恢复正常了,之前的数据也都存在(只要没有做 kubeadm reset)
  • 解决:

    • SSH 登陆 k8s-3 主机
    • 执行下述 2 条命令
[root@k8s-3 ~]# systemctl enable kubelet
[root@k8s-3 ~]# systemctl restart kubelet.service 
  1. 在 k8s-3 上执行了上述 2 条命令后,在 master 上查看 node 的状态
[root@k8s-1 ~]# kubectl get nodes
NAME    STATUS   ROLES                  AGE     VERSION
k8s-1   Ready    control-plane,master   5h24m   v1.22.1
k8s-2   Ready    <none>                 4h57m   v1.22.1
k8s-3   Ready    <none>                 8s      v1.22.1
  • 发现其中一个 flannel (k8s-3 主机的)在几秒前重启过
[root@k8s-1 ~]# kubectl get pod -A
NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE
default       deployment-example-6799fc88d8-xn7m6   1/1     Running   0          8m27s
default       deployment-example-6799fc88d8-xp42n   1/1     Running   0          5m58s
default       deployment-example-6799fc88d8-zjfg8   1/1     Running   0          5m58s
kube-system   coredns-bdc44d9f-ds4cc                1/1     Running   0          5h23m
kube-system   coredns-bdc44d9f-gth5j                1/1     Running   0          5h23m
kube-system   etcd-k8s-1                            1/1     Running   0          5h24m
kube-system   kube-apiserver-k8s-1                  1/1     Running   0          5h23m
kube-system   kube-controller-manager-k8s-1         1/1     Running   0          5h24m
kube-system   kube-flannel-ds-gmpc5                 1/1     Running   0          5h17m
kube-system   kube-flannel-ds-kpw4n                 1/1     Running   0          23s
kube-system   kube-flannel-ds-qcvxs                 1/1     Running   0          4h57m
kube-system   kube-proxy-4vxkp                      1/1     Running   0          4h57m
kube-system   kube-proxy-d4g6h                      1/1     Running   0          23s
kube-system   kube-proxy-dmfq7                      1/1     Running   0          5h23m
kube-system   kube-scheduler-k8s-1                  1/1     Running   0          5h24m

你可能感兴趣的:(kubernetes,kubernetes,docker,容器,运维,云原生)