乐趣区

关于kubernetes:完事后再聊应用场景K8S调度实战Node-Affinity

写在开篇

Node Affinity(节点亲和性)容许在节点级别上 指定一些条件 来管制 Pod 被调度到哪些节点上。它还有两种策略,本篇通过实战演示如何应用两种策略来管制 Pod 的调度。

测试环境

还是老样子,本次实战持续应用以下 K8S 集群环境进行:

节点 主机名 IP
Master 节点 k8s-b-master 192.168.11.100
工作节点 1 k8s-b-node01 192.168.11.101
工作节点 2 k8s-b-node02 192.168.11.102
工作节点 3 k8s-b-node03 192.168.11.103
工作节点 4 k8s-b-node04 192.168.11.104
工作节点 5 k8s-b-node05 192.168.11.105
工作节点 6 k8s-b-node06 192.168.11.106

开始实战

在本次实战中,应用一个名为 goweb 的测试应用程序来演示 Node Affinity 的应用。goweb 是我用 Golang 开发的简略 Web 应用程序,用于测试和验证 K8S 的调度策略。当然了,你也能够本人开发一个相似的利用,而后应用本人的利用来进行本篇的实战内容。

策略 1

在这个实战案例中,我将应用 requiredDuringSchedulingIgnoredDuringExecution 策略,该策略要求 Pod 只能调度到特定的节点上。  我将创立一个 Node Affinity 规定,要求 goweb 利用只能调度到主机名为 k8s-b-node03 的节点上。

首先,须要创立一个名为 goweb-node-affinity.yaml 的文件,并将以下内容复制到文件中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb
  namespace: goweb-namespace
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      containers:
      - name: goweb
        image: 192.168.11.253/library/goweb:latest
        ports:
        - containerPort: 80
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - k8s-b-node03

保留文件后,应用以下命令利用 goweb 利用的 Node Affinity 规定:

kubectl apply -f goweb-node-affinity.yaml

当初,K8S 调度器将只会将 goweb 利用调度到主机名为 k8s-b-node03 的节点上。

[root@k8s-b-master ~]# kubectl get pod -n goweb-namespace -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
goweb-5559b4bbf5-5mpd8   1/1     Running   0          64s   10.244.199.138   k8s-b-node03   <none>           <none>
goweb-5559b4bbf5-lbq4j   1/1     Running   0          63s   10.244.199.139   k8s-b-node03   <none>           <none>
goweb-5559b4bbf5-lqkzh   1/1     Running   0          70s   10.244.199.137   k8s-b-node03   <none>           <none>

策略 2

在这个实战案例中,我将应用 preferredDuringSchedulingIgnoredDuringExecution 策略,该策略尽量将 Pod 调度到满足条件的节点上,但不是强制要求。  我将创立一个 Node Affinity 规定,优先将 goweb 利用调度到领有标签 app=goweb-node 的节点上。

首先,我创立一个名为 goweb-preferred-node-affinity.yaml 的文件,并将以下内容复制到文件中:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: goweb
  namespace: goweb-namespace
spec:
  replicas: 3
  selector:
    matchLabels:
      app: goweb
  template:
    metadata:
      labels:
        app: goweb
    spec:
      containers:
      - name: goweb
        image: 192.168.11.253/library/goweb:latest
        ports:
        - containerPort: 80
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: app
                operator: In
                values:
                - goweb-node

保留文件后,应用以下命令利用 goweb 利用的 Node Affinity 规定:

kubectl apply -f goweb-preferred-node-affinity.yaml

当初,K8S 调度器将优先将 goweb 利用调度到领有标签 app=goweb-node 的节点上,但如果没有满足条件的节点,它依然能够调度到其余节点上。

查看 node 标签和调度后果:

# 查看 label:[root@k8s-b-master ~]# kubectl get node --show-labels
NAME           STATUS   ROLES           AGE   VERSION   LABELS
k8s-b-master   Ready    control-plane   49d   v1.25.4   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-b-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-b-node01   Ready    <none>          49d   v1.25.4   app=goweb-node,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-b-node01,kubernetes.io/os=linux
k8s-b-node02   Ready    <none>          49d   v1.25.4   app=goweb-node,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-b-node02,kubernetes.io/os=linux
...

# 调度后果:[root@k8s-b-master ~]# kubectl get pod -n goweb-namespace -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
goweb-58799f9b4c-cd5j4   1/1     Running   0          16s   10.244.51.204    k8s-b-node01   <none>           <none>
goweb-58799f9b4c-hpwlt   1/1     Running   0          16s   10.244.232.147   k8s-b-node02   <none>           <none>
goweb-58799f9b4c-ksps5   1/1     Running   0          16s   10.244.232.146   k8s-b-node02   <none>           <none>

删除 app 标签后再次查看调度后果:

# 删除
kubectl label nodes k8s-b-node01 app-
kubectl label nodes k8s-b-node02 app-

# 调度后果:[root@k8s-b-master ~]# kubectl get pod -n goweb-namespace -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
goweb-58799f9b4c-5hr8h   1/1     Running   0          2s    10.244.25.77     k8s-b-node05   <none>           <none>
goweb-58799f9b4c-5vnr9   1/1     Running   0          2s    10.244.232.148   k8s-b-node02   <none>           <none>
goweb-58799f9b4c-hwxjc   1/1     Running   0          2s    10.244.151.4     k8s-b-node06   <none>           <none>

留神到了吧?删除 app 标签后,就没有满足条件的节点了,但它依然能够调度到其余节点上。通过实战,曾经证实了这一点。

应用场景

上面聊聊两种策略在理论工作中可能的应用场景。

1. requiredDuringSchedulingIgnoredDuringExecution

它的特点是:强制要求 Pod 只能调度到特定节点的策略。可能实用的场景:

  • 硬件个性要求:比方对底层硬件有特殊要求的利用,就能够将 Pod 调度到领有特定标签货其它属性的节点上。
  • 数据本地性要求:比方须要拜访特定数据源的利用,将 Pod 调度到与数据源最近的节点上,这样能够缩小网络提早和进步性能。
  • 资源隔离:将特定类型的工作或工作负载隔离到专用的节点上。

举个贴近理论的例子,假如有一组节点,其中几个节点领有牛逼的 CPU 和内存资源。心愿将一些须要较高计算能力的任务调度到这些节点上。这时候就能够应用此策略来指定这些节点的标签或其余属性,就能够将 Pod 限度在这些节点上了。

2. preferredDuringSchedulingIgnoredDuringExecution

它的特点是:优先选择满足条件的节点进行调度的策略。可能实用的场景:

  • 资源利用率优化:比方心愿将 Pod 调度到领有特定资源的节点上,但如果没有满足条件的节点,依然能够将 Pod 调度到其余节点上。
  • 可用性和容错性:为了进步应用程序的可用性和容错性,咱们能够将 Pod 调度到多个节点上,但依然优先将其调度到特定节点上。如果该节点不可用,调度器将抉择 次优节点 进行调度。

举个例子,假如有一组节点,其中一些节点的网卡连贯的是光交换机,网络更快。心愿将网络密集型的利用优先调度到这些节点上,这时候就能够指定这些节点的网络个性标签或其余属性。

再举个例子,假如在具备不同地理位置的多个数据中心中部署利用。就能够优先将 Pod 调度到与利用所服务的区域最近的节点上,以此来达到缩小提早、进步用户体验的成果。

我为什么要用“可能实用的场景”来阐明?因为我感觉,看这篇文章的你应该能够想到更好的利用场景,欢送留言探讨。

最初总结

接下来做个关键性的总结:

  1. Node Affinity 有两种策略:
  • requiredDuringSchedulingIgnoredDuringExecution:调度器只有在规定被满足的时候能力执行调度(硬策略)
  • preferredDuringSchedulingIgnoredDuringExecution:调度器会尝试寻找满足对应规定的节点。如果找不到匹配的节点,调度器依然会调度该 Pod(软策略)
  1. 匹配形式有两种:
  • matchExpressions:基于标签的匹配,能够蕴含一个或多个条件,每个条件由键、运算符和值组成,实用于更简单的标签匹配逻辑的场景。
  • matchFields:容许基于节点的字段抉择节点,而不是基于标签。比方指定节点上的字段名称和值进行匹配。这对于抉择节点的特定属性十分有用,例如节点的操作系统、内存大小等。
  1. operator 属性可能的枚举值:
  • “DoesNotExist”: 用于查看标签或注解不存在的状况。
  • “Exists”: 用于查看标签或注解存在的状况。
  • “Gt”: 用于数字类型的匹配,示意大于指定值。
  • “In”: 用于匹配给定值列表中的任何一个值。
  • “Lt”: 用于数字类型的匹配,示意小于指定值。
  • “NotIn”: 用于匹配不在给定值列表中的任何一个值。

心愿本篇的实战能对你了解和应用 K8S 中的 Node Affinity 个性有所帮忙。你能够依据理论需要和集群环境,灵便利用 Node Affinity 来优化利用的调度行为。好了,本篇就到此结束,有问题能够评论区留言探讨或者私信探讨。


重视运维实战,咱们比谁都拼!日常分享实用干货,助你成为运维大神!摸索技术的魅力,从这里开始!

点击链接,畅读精彩文章,从中获取洞见,为本人的技术之旅注入新的能源!关注我的微信公众号,不错过更多精彩内容。

【K8S(专一于深入研究 K8S 相干的各种技术和常识分享。)】:https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz…

【Go&Py(涵盖了 Go 和 Python 两种风行的编程语言。)】:https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz…

【Ops(运维畛域的探讨和交换。)】:https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz…

退出移动版