玩转k8s pod调度之定向调度与全自动调度

在大多数情况下,我们希望Deployment创建的Pod副本被成功调度到集群中的任何一个可用节点,而不关心具体会调度到哪个节点。但是,在真实的生产环境中比如希望将MySQL数据库调度到一个具有SSD磁盘的目标节点上,此时Pod模板中的NodeSelector属性就开始发挥作用了,上述MySQL定向调度案例的实现方式可分为以下两步。

(1)把具有SSD磁盘的Node都打上自定义标签“disk=ssd”。

(2)在Pod模板中设定NodeSelector的值为“disk: ssd”。

如此一来,Kubernetes在调度Pod副本的时候,就会先按照Node的标签过滤出合适的目标节点,然后选择一个最佳节点进行调度。

上述逻辑看起来既简单又完美,但在真实的生产环境中可能面临以下令人尴尬的问题。

(1)如果NodeSelector选择的Label不存在或者不符合条件,比如这些目标节点此时宕机或者资源不足,该怎么办?

(2)如果要选择多种合适的目标节点,比如SSD磁盘的节点或者超高速硬盘的节点,该怎么办?Kubernates引入了NodeAffinity(节点亲和性设置)来解决该需求。

在真实的生产环境中还存在如下所述的特殊需求。

(1)不同Pod之间的亲和性(Affinity)。比如MySQL数据库与Redis中间件不能被调度到同一个目标节点上(反亲和),或者两种不同的Pod必须被调度到同一个Node上(亲和性),以实现本地文件共享或本地网络通信等特殊需求,这就是PodAffinity要解决的问题。

(2)有状态集群的调度。对于ZooKeeper、Elasticsearch、MongoDB、Kafka等有状态集群,虽然集群中的每个Worker节点看起来都是相同的,但每个Worker节点都必须有明确的、不变的唯一ID(主机名或IP地址),这些节点的启动和停止次序通常有严格的顺序。此外,由于集群需要持久化保存状态数据,所以集群中的Worker节点对应的Pod不管在哪个Node上恢复,都需要挂载原来的Volume,因此这些Pod还需要捆绑具体的PV。针对这种复杂的需求,Kubernetes提供了StatefulSet这种特殊的副本控制器来解决问题,在Kubernetes 1.9版本发布后,StatefulSet才可用于正式生产环境中。

(3)在每个Node上调度并且仅仅创建一个Pod副本。这种调度通常用于系统监控相关的Pod,比如主机上的日志采集、主机性能采集等进程需要被部署到集群中的每个节点,并且只能部署一个副本,这就是DaemonSet这种特殊Pod副本控制器所解决的问题。

(4)对于批处理作业,需要创建多个Pod副本来协同工作,当这些Pod副本都完成自己的任务时,整个批处理作业就结束了。这种Pod运行且仅运行一次的特殊调度,用常规的RC或者Deployment都无法解决,所以Kubernates引入了新的Pod调度控制器Job来解决问题,并继续延伸了定时作业的调度控制器CronJob

与单独的Pod实例不同,由RC、ReplicaSet、Deployment、DaemonSet等控制器创建的Pod副本实例都是归属于这些控制器的,这就产生了一个问题:控制器被删除后,归属于控制器的Pod副本该何去何从?在Kubernates 1.9之前,在RC等对象被删除后,它们所创建的Pod副本都不会被删除;在Kubernates 1.9以后,这些Pod副本会被一并删除。如果不希望这样做,则可以通过kubectl命令的--cascade=false参数来取消这一默认特性:

 Deployment或RC:全自动调度

 

NodeSelector:定向调度

首先通过kubectl label命令给目标Node打上一些标签

我们为k8s-node-1节点打上一个zone=north标签,表明它是“北方”的一个节点

[root@master-1 busybox]# kubectl label node node-1 onne=north
node/node-1 labeled
[root@master-1 busybox]# kubectl get node --show-labels
NAME       STATUS   ROLES    AGE   VERSION    LABELS
master-1   Ready    <none>   28d   v1.20.15   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master-1,kubernetes.io/master=true,kubernetes.io/os=linux
node-1     Ready    <none>   28d   v1.20.15   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-1,kubernetes.io/os=linux,onne=north
node-2     Ready    <none>   28d   v1.20.15   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node-2,kubernetes.io/os=linux

在Pod的定义中加上nodeSelector的设置

apiVersion: apps/v1
kind: Deployment
...
    spec:
      restartPolicy: Always
      serviceAccountName: default
      containers:
      - name: nginx-configmap-container
        image: 124.222.68.142:10006/k8s/nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          protocol: TCP
          name: http
        - containerPort: 443
          protocol: TCP
          name: https
...
      nodeSelector:
        onne: north

查看pod

[root@master-1 hostpath]# kubectl  get pod -n app -owide  -w
NAME                               READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
nginx-configmap-6b66d56f59-sncrb   1/1     Running   0          17s   10.244.84.159   node-1   <none>           <none>

如果未匹配到nodeSelector则调度失败

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  27s   default-scheduler  0/3 nodes are available: 3 node(s) didn't match Pod's node affinity. # 3台node没有一个匹配pod亲和性
  Warning  FailedScheduling  27s   default-scheduler  0/3 nodes are available: 3 node(s) didn't match Pod's node affinity.

 nodeName: 指定集群中主机名称调度

      #nodeSelector:
      #  zone: north
      nodeName: node-3

 

posted @ 2024-12-23 10:37  不会跳舞的胖子  阅读(8)  评论(0编辑  收藏  举报