Kubernetes Pod资源调度之全自动调度和定向调度

1、控制器类型

Kubernetes上,很少会直接创建一个Pod,在大多数情况下,会通过RCDeploymentDaemonSetJob等控制器完成对一组Pod副本的创建、调度和整个生命周期的自动化控制。

在最早的Kubernetes版本里没有这么多Pod副本控制器的,只有一 个Pod副本控制器RC(Replication Controller),这个控制器是这样设计 实现的:RC独立于所控制的Pod,并通过Label标签这个松耦合关联关系 控制目标Pod实例的创建和销毁,随着Kubernetes的发展,RC也出现了新的继任者Deployment,用于更加自动地完成Pod副本的部署、版 本更新、回滚等功能。

严谨地说,RC的继任者其实并不是Deployment,而是ReplicaSet, 因为ReplicaSet进一步增强了RC标签选择器的灵活性。之前RC的标签选择器只能选择一个标签,而ReplicaSet拥有集合式的标签选择器,可以选择多个Pod标签,如下所示

    selector:
      matchLables:
        tier: frontend
      matchExpressions:
        - {key: tier, operator: In, values: [frontend]}

RC不同,ReplicaSet被设计成能控制多个不同标签的Pod副本。 一种常见的应用场景是,应用MyApp目前发布了v1v2两个版本,用户 希望MyAppPod副本数保持为3个,可以同时包含v1v2版本的Pod, 就可以用ReplicaSet来实现这种控制,写法如下

    selector:
      matchLables:
        version: v2
      matchExpressions:
        - {key: version, operator: In, values: [v1,v2]}

Kubernetes的滚动升级就是巧妙运用ReplicaSet的这个特性来实现的,同时,Deployment也是通过ReplicaSet来实现Pod副本自动控制功能的。我们不应该直接使用底层的ReplicaSet来控制Pod副本,而应该 使用管理ReplicaSetDeployment对象来控制副本,这是来自官方的建议。

2、全自动调度

全自动调度的控制器是DeploymentRCDeploymentRC的主要功能之一就是自动部署一个容器应用的 份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。

下面是一个Deployment配置的例子,使用这个配置文件可以创建一个ReplicaSet,这个ReplicaSet会创建3Nginx应用的Pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

运行kubectl create命令创建这个Deployment

# kubectl apply -f nginx-deployment.yaml 
deployment.apps/nginx-deployment created

查看DeploymentRSPod的状态

# kubectl get deployment
NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment        3/3     3            3           58s
# kubectl get rs
NAME                               DESIRED   CURRENT   READY   AGE
nginx-deployment-7bffc778db        3         3         3       85s
# kubectl get pods
NAME                                     READY   STATUS    RESTARTS   AGE
nginx-deployment-7bffc778db-j5czg        1/1     Running   0          1m34s
nginx-deployment-7bffc778db-lbpjg        1/1     Running   0          1m34s
nginx-deployment-7bffc778db-zcn6m        1/1     Running   0          1m34s

从调度策略上来说,这3Nginx Pod由系统全自动完成调度。它们各自最终运行在哪个节点上,完全由MasterScheduler经过一系列算法计算得出,用户无法干预调度过程和结果。

# kubectl get pods -o wide
NAME                                     READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
nginx-deployment-7bffc778db-j5czg        1/1     Running   0          3m36s   172.20.3.229   k8s-node-1   <none>           <none>
nginx-deployment-7bffc778db-lbpjg        1/1     Running   0          3m36s   172.20.4.27    k8s-node-2   <none>           <none>
nginx-deployment-7bffc778db-zcn6m        1/1     Running   0          3m36s   172.20.5.203   k8s-node-3   <none>           <none>

3、定向调度

定向调度通过NodeSelector标签实现, Master上的Scheduler服务(kube-scheduler进程)负责实现Pod的调度,整个调度过程通过执行一系列复杂的算法,最终为每个Pod都计算出一个最佳的目标节点,这一过程是自动完成的,通常我们 无法知道Pod最终会被调度到哪个节点上。在实际情况下,也可能需要将Pod调度到指定的一些Node上,可以通过Node的标签(Label)和PodnodeSelector属性相匹配,来达到上述目的。

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

# kubectl label nodes k8s-node-1 zone=north

然后,在Pod的定义中加上nodeSelector的设置,以redismaster-controller.yaml为例

apiVersion: v1
kind: ReplicationController 
metadata:
  name: redis-master
  labels:
    name: redis-master 
spec:
  replicas: 1
  selector:
    name: redis-master
  template:
    metadata:
      labels:
        name: redis-master
    spec:
      containers:
      - name: master
        image: redis
        ports:
        - containerPort: 6379
      nodeSelector:
        zone: north

创建Podscheduler就会将该Pod调度到拥有zone=north标签的Node

如果我们给多个Node都定义了相同的标签(例如zone=north),则scheduler会根据调度算法从这组Node中挑选一个可用的Node进行Pod调度。

通过基于Node标签的调度方式,我们可以把集群中具有不同特点的Node都贴上不同的标签,例 如role=frontendrole=backend``、role=database等标签,在部署应用时就可以根据应用的需求设置NodeSelector来进行指定Node范围的调度。

如果我们指定了PodnodeSelector条件,且在集群中不存在包含相应标签的Node,则即使在集群中还有其他可供使用的Node,这个Pod也无法被成功调度。

除了用户可以自行给Node添加标签,Kubernetes也会给Node预定义 一些标签,包括

  • kubernetes.io/hostname
  • beta.kubernetes.io/os(从1.14版本开始更新为稳定版,到1.18版 本删除)
  • beta.kubernetes.io/arch(从1.14版本开始更新为稳定版,到1.18 版本删除)
  • kubernetes.io/os(从1.14版本开始启用)
  • kubernetes.io/arch(从1.14版本开始启用)

也可以使用这些系统标签进行Pod的定向调度。

NodeSelector通过标签的方式,简单实现了限制Pod所在节点的方法。亲和性调度机制则极大扩展了Pod的调度能力,主要的增强功能如 下。

  • 更具表达力(不仅仅是“符合全部”的简单情况)
  • 可以使用软限制、优先采用等限制方式,代替之前的硬限制, 这样调度器在无法满足优先需求的情况下,会退而求其次,继续运行该Pod
  • 可以依据节点上正在运行的其他Pod的标签来进行限制,而非节点本身的标签。这样就可以定义一种规则来描述Pod之间的亲和或互斥关系

亲和性调度功能包括节点亲和性NodeAffinityPod亲和性PodAffinity两个维度的设置。节点亲和性与NodeSelector类似,增 强了上述前两点优势;Pod的亲和与互斥限制则通过Pod标签而不是节点标签来实现,也就是上面所陈述的方式,同时具有前两点提到的优点。

NodeSelector将会继续使用,随着节点亲和性越来越能够表达nodeSelector的功能,最终NodeSelector会被废弃。

文章参考来源:《kubernetes权威指南-第4版》

posted @ 2020-04-19 15:07  SSgeek  阅读(919)  评论(0编辑  收藏  举报