首页 > 编程语言 >不背锅运维:k8s调度之初探nodeSelector和nodeAffinity

不背锅运维:k8s调度之初探nodeSelector和nodeAffinity

时间:2023-03-01 17:12:44浏览次数:63  
标签:调度 背锅 运维 demo goweb nodeSelector test k8s 节点

写在开篇

在k8s的调度中,有强制性的nodeSelector,节点亲和性nodeAffinity、Pod亲和性podAffinity、pod反亲和性podAntiAffinity。本篇先对nodeSelector和nodeAffinity做个初探。

进入主题之前,先看看创建pod的大概过程

图片

  1. kubectl向apiserver发起创建pod请求,apiserver将创建pod配置写入etcd
  2. scheduler收到apiserver有新pod的事件,scheduler根据自身调度算法选择一个合适的节点,并打标记pod=test-b-k8s-node01
  3. kubelet收到分配到自己节点的pod,调用docker api创建容器,并获取容器状态汇报给apiserver
  4. 执行kubectl get查看,apiserver会再次从etcd查询pod信息

k8s的各个组件是基于list-watch机制进行交互的,了解了list-watch机制,以及结合上述pod的创建流程,就可以很好的理解各个组件之间的交互。

关于list-watch机制概念(参考):

list-watch机制是一种比较常用的分布式协调机制,它使得系统中的多个节点能够相互通信并且同步更新状态。list-watch机制的基本原理是:一个节点A将发布一个列表存储到共享内存,然后另一个节点B可以访问该存储列表,当A对该存储列表进行任何变更时,系统会自动通知B节点同步数据。list-watch是一种轻量级的架构,用于在分布式环境中支持和管理系统name-value对模型。首先,它构建一个包含所有name-value对的结构,当name-value发生变化时更新这个结构,然后将其提供给特定的节点。对于每个节点,可以创建一条监视链条,以便检测名称-值的变化,以便节点能够保持最新的数据。如果name-value发生变化,list-watch机制将通知特定节点同步新的name-value。list-watch机制的工作方式非常简单,它不需要复杂的分布式框架。list-watch机制非常适合用于高可用系统,因为它可以自动地进行数据共享和同步,使各个节点能够及时获取最新的信息,从而提升系统的可用性和可靠性。此外,list-watch还可以帮助系统在各个节点上实现一致,这有助于提高系统的可扩展性,改进其可靠性和稳定性。

何为调度

说白了就是将Pod指派到合适的节点上,以便对应节点上的Kubelet能够运行这些Pod。在k8s中,承担调度工作的组件是kube-scheduler,它也是k8s集群的默认调度器,它在设计上就允许编写一个自定义的调度组件并替换原有的kube-scheduler。所以,如果你足够牛逼,就可以自己开发一个调度器来替换默认的了。调度器通过K8S的监测(Watch)机制来发现集群中新创建且尚未被调度到节点上的Pod,调度器会将所发现的每一个未调度的Pod调度到一个合适的节点上来运行。

  • 调度程序会过滤掉任何不满足Pod特定调度需求的节点
  • 创建Pod时也可以手动指定一个节点
  • 如果没有任何一个节点能满足Pod的资源请求, 那么这个Pod将一直停留在未调度状态直到调度器能够找到合适的Node

调度流程

kube-scheduler给一个Pod做调度选择时包含了两个步骤:过滤、打分。

  1. pod开始创建,通知apiserver
  2. kube-scheduler在集群中找出所有满足需求的可调度节点(过滤阶段)
  3. kube-scheduler根据当前打分规则给这些可调度节点打分(打分阶段)
  4. kube-scheduler选择得分最高的节点运行Pod(存在多个得分最高的节点则随机选取)
  5. kube-scheduler通知kube-apiserver

nodeSelector和nodeAffinity

实际工作中,可能会有这样的情况,需要进一步控制Pod被部署到哪个节点。例如,确保某些Pod最终落在具有SSD硬盘的主机上,又需要确保某些pod落在具体部门的主机上运行,这时就可以使用标签选择器来进行选择。

图片

  • nodeSelector:通过它可以将pod指派到具有特定标签的节点上,nodeSelector只能选择指定标签的节点,它属于强制性的,如果标签不小心写错则无法调度
  • nodeAffinity:节点亲和性有以下两种,它的表达能力更强,允许指定软规则,提供了对选择逻辑更强的控制能力,operator字段支持In、NotIn、Exists、DoesNotExist、Gt和Lt,
    • requiredDuringSchedulingIgnoredDuringExecution:调度器只有在规则被满足的时候才能执行调度(硬策略)
    • preferredDuringSchedulingIgnoredDuringExecution:调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会调度该Pod(软策略)

进一步对nodeAffinity的理解:我对亲和性和反亲和性的理解是这样的,亲和性就是希望某些pod在同一个node上,反亲和性是希望某些pod不要在同一个node上。nodeAffinity是亲和性的,它的NotIn和DoesNotExist可用来实现节点反亲和性行为(当然也可以使用节点污点将Pod从特定节点上驱逐,后面专门分享),通过逻辑组合可以控制pod要部署在哪些节点上,以及不能部署在哪些节点上。

注意:

  • 如果同时指定了 nodeSelector 和 nodeAffinity,两者必须都要满足, 才能将Pod调度到候选节点上
  • 如果在与 nodeAffinity 类型关联的 nodeSelectorTerms 中指定多个条件, 只要其中一个 nodeSelectorTerms 满足(各个条件按逻辑或操作组合)的话,Pod 就可以被调度到节点上
  • 如果在与 nodeSelectorTerms 中的条件相关联的单个 matchExpressions 字段中指定多个表达式,则只有当所有表达式都满足(各表达式按逻辑与操作组合)时,Pod才能被调度到节点上

实战案例

1. 节点亲和性案例(nodeAffinity)

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: goweb-demo
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: # 调度器只有在规则被满足的时候才执行调度
        nodeSelectorTerms:
        - matchExpressions:
          - key: team
            operator: In
            values:
            - team-a
            - team-b
      preferredDuringSchedulingIgnoredDuringExecution: # 调度器会尝试寻找满足对应规则的节点(如果找不到匹配的节点,调度器仍然会调度该Pod)
      - weight: 1
        preference:
          matchExpressions:
          - key: hostbrand
            operator: In
            values:
            - ibm
  containers:
  - name: container-goweb-demo
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3

配置node的标签

# 设置标签
kubectl label node test-b-k8s-node01 team=team-a
kubectl label node test-b-k8s-node02 team=team-b
kubectl label node test-b-k8s-node01 hostbrand=ibm

# 查看
kubectl get node --show-labels

# 创建
kubectl create -f pod.yaml 

# 查看Pod
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE                NOMINATED NODE   READINESS GATES
goweb-demo   1/1     Running   0          17s   10.244.240.58   test-b-k8s-node01   <none>           <none>
tantianran@test-b-k8s-master:~/goweb-demo$ 

在上面的案例中,所应用的规则如下:

  • 节点必须包含一个键名为 team 的标签, 并且该标签的取值必须为 team-a 或 team-b
  • 节点最好具有一个键名为 hostbrand 且取值为 ibm 的标签

关于节点亲和性权重的weight字段:

  • preferredDuringSchedulingIgnoredDuringExecution 亲和性类型可以设置 weight 字段,其取值范围是 1 到 100。 当调度器找到能够满足 Pod 的其他调度请求的节点时,调度器会遍历节点满足的所有的偏好性规则, 并将对应表达式的 weight 值加和。
  • 最终的加和值会添加到该节点的其他优先级函数的评分之上。 在调度器为 Pod 作出调度决定时,总分最高的节点的优先级也最高。

2. 节点亲和性+带有权重的例子

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: goweb-demo
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: team
            operator: In
            values:
            - team-a
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
      - weight: 50
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - sas
  containers:
  - name: container-goweb-demo
    image: 192.168.11.247/web-demo/goweb-demo:20221229v3
# 创建
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl create -f pod.yaml 
pod/goweb-demo created

# 查看
tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP              NODE                NOMINATED NODE   READINESS GATES
goweb-demo   1/1     Running   0          35s   10.244.240.18   test-b-k8s-node01   <none>           <none>
tantianran@test-b-k8s-master:~/goweb-demo$ 

上面的例子,存在两个候选节点,都满足 preferredDuringSchedulingIgnoredDuringExecution 规则, 其中一个节点具有标签 disktype:ssd,另一个节点具有标签 disktype:sas,调度器会考察各个节点的weight取值,并将该权重值添加到节点的其他得分值之上。

3. nodeSelector案例

设置节点的标签

# 给节点打标签,key和value:gpu=true
kubectl label node test-b-k8s-node02 gpu=true
node/test-b-k8s-node02 labeled

# 查看指定节点标签
kubectl get node test-b-k8s-node02 --show-labels

# 不指定节点时,查看所有节点标签
kubectl get node --show-labels

添加nodeSelector字段到pod配置

apiVersion: v1
kind: Namespace
metadata:
  name: test-a
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  replicas: 10
  selector:
    matchLabels:
      app: goweb-demo
  template:
    metadata:
      labels:
        app: goweb-demo
    spec:
      nodeSelector:
        gpu: true
      containers:
      - name: goweb-demo
        image: 192.168.11.247/web-demo/goweb-demo:20221229v3
---
apiVersion: v1
kind: Service
metadata:
  name: goweb-demo
  namespace: test-a
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8090
  selector:
    app: goweb-demo
  type: NodePort

提示:刚测了一下,非要取这种标签的话gpu=true,在yaml定义时gpu: true ,true就要加双引号,它是字符串,不加的话,他认为是bool。所以,设置node的标签,value以后尽量不要是true/false,非要的话,指定时加上双引号即可。

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl get pods -n test-a -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP              NODE                NOMINATED NODE   READINESS GATES
goweb-demo-69d79997f7-24862   1/1     Running   0          16m   10.244.222.7    test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-48c62   1/1     Running   0          16m   10.244.222.32   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-76jd9   1/1     Running   0          16m   10.244.222.51   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-dt7sf   1/1     Running   0          16m   10.244.222.21   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-fddpd   1/1     Running   0          16m   10.244.222.60   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-lw2t8   1/1     Running   0          16m   10.244.222.47   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-nwwkg   1/1     Running   0          16m   10.244.222.10   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-v768k   1/1     Running   0          16m   10.244.222.38   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-vgt5w   1/1     Running   0          16m   10.244.222.56   test-b-k8s-node02   <none>           <none>
goweb-demo-69d79997f7-xqhxp   1/1     Running   0          16m   10.244.222.41   test-b-k8s-node02   <none>           <none>

如果创建pod,指派的标签是不存在任何1台节点时,pod会一直处于pending状态,直至进入Terminating状态,pod的重启策略是always(默认策略:当容器退出时,总是重启容器),则一直在pending和Terminating中徘徊,直到有符合条件的标签,就会立马分配节点,从而创建pod。

删除标签

tantianran@test-b-k8s-master:~/goweb-demo$ kubectl label node test-b-k8s-node02 gpu-
node/test-b-k8s-node02 unlabeled
tantianran@test-b-k8s-master:~/goweb-demo$ 

提示:key和小横杠之间不能有空格,否则删除失败。

写在最后

本篇先对节点选择器和节点亲和性暂时做个初探性的分享,后续还会持续分享多几个贴近实际环境的各种场景调度的逻辑组合案例。

本文转载于(喜欢的盆友关注我们):https://mp.weixin.qq.com/s/QffBfGLpguAxSzucnkX-rQ

标签:调度,背锅,运维,demo,goweb,nodeSelector,test,k8s,节点
From: https://www.cnblogs.com/ttropsstack/p/17168930.html

相关文章

  • PG数据库运维工具要覆盖哪些能力
    导读目前的国产数据库中,很多产品都是以PG社区版代码作为研发起点的,还有一些产品是基于openGauss开源项目的。这些数据库的基础特性都和社区版的PG数据库类似,不过也做了......
  • KingbaseES V8R3 集群运维系列 -- 修改数据库服务端口
    ​案例说明:KingbaseESV8R3集群数据库服务端口(默认:54321)的配置在数据库及集群多个配置文件中都存在,修改端口需要更改所有的配置文件,本案例详细描述了数据库服务端口修改......
  • KingbaseES V8R6 运维系列 --单机小版本升级
    ​案例说明:在KingbaseESV8R6版本提供了sys_upgrade的升级工具,本案例描述了KingbaseESV8R6单机环境下数据库的小版本升级操作,案例涉及的版本从‘(Kingbase)V008R006C0......
  • KingbaseES V8R6 集群运维案例 -- 归档失败导致 Switchover 失败
    案例说明:KingbaseESV8R6集群,备库在执行‘repmgrstandbyswitchover’时,切换失败,出现以下故障:经检查发现是主库归档配置错误,主库出现归档失败导致。适用版本:Kingbas......
  • 写给数据库运维的兄弟
    写在前面的故事首先,给看官们讲个故事:最近遇到过一个客户,系统上线三年变的越来越慢,直到前几个月全面爆发,系统前端使用人员不断抱怨,甚至已经达到了不能使用的程度。这个......
  • LinkSLA智能运维技术派-Redis的监控
    Redis是一个开源,内存存储的数据服务器,可用作数据库、高速缓存和消息队列代理等场景。首先我们对内存进行监控,主要指标如下:used_memory:使用内存used_memory_rss:从操作系统......
  • PG数据库运维工具要覆盖哪些能力
    目前的国产数据库中,很多产品都是以PG社区版代码作为研发起点的,还有一些产品是基于openGauss开源项目的。这些数据库的基础特性都和社区版的PG数据库类似,不过也做了一定......
  • Docker运维之容器的日志清理
    在容器运行的过程中,通常会产生大量的日志,尤其是应用程序本身记录了info级别的日志时候,程序的标准输出记录到容器的日志。这样会占用大量的磁盘空间,严重者导致IO异常,最终服......
  • 双人审核制-运维开发巡查制度-三层防护
    双人审核制-运维开发巡查制度-三层防护目录背景线上频繁出问题.主要是两块的问题:1.人工失误.2.老被扫出来漏洞.如何防范杜绝此类情况发生.制度的规范:1.预生产环境......
  • <<运维监控系统实战笔记>> 小记随笔 —— Prometheus 初识
    Prometheus简介Prometheusserver包含时序库、告警引擎、数据展示三大块,体系中最核心的组件Exporters采集数据的客户端,负载采集数据存在内存中,提供http接口,让......