一、调度简介
一个容器平台的主要功能就是为容器分配运行时所需要的计算,存储和网络资源。容器调度系统负责选择在最合适的主机上启动容器,并且将它们关联起来。
它必须能够自动的处理容器故障并且能够在更多的主机上自动启动更多的容器来应对更多的应用访问。
目前三大主流的容器平台Swarm, Mesos和Kubernetes具有不同的容器调度系统。
1.Swarm的特点是直接调度Docker容器,并且提供和标准Docker API一致的API。
2.Mesos针对不同的运行框架采用相对独立的调度系统,其中Marathon框架提供了Docker容器的原生支持。
3.Kubernetes则采用了Pod和Label这样的概念把容器组合成一个个的互相存在依赖关系的逻辑单元。相关容器被组合成Pod后被共同部署和调度,形成服务(Service)。
这个是Kubernetes和Swarm,Mesos的主要区别。
相对来说,Kubernetes采用这样的方式简化了集群范围内相关容器被共同调度管理的复杂性。换一种角度来看,Kubernetes采用这种方式能够相对容易的支持更强大,更复杂的容器调度算法。
二、K8S 调度工作方式
Kubernetes调度器作为集群的大脑,在如何提高集群的资源利用率、保证集群中服务的稳定运行中也会变得越来越重要
Kubernetes的资源分为两种属性。
1.可压缩资源(例如CPU循环,Disk I/O带宽)都是可以被限制和被回收的,对于一个Pod来说可以降低这些资源的使用量而不去杀掉Pod。
2.不可压缩资源(例如内存、硬盘空间)一般来说不杀掉Pod就没法回收。未来Kubernetes会加入更多资源,如网络带宽,存储IOPS的支持。
Kubernets调度器
Scheduler调度器做为Kubernetes三大核心组件之一, 承载着整个集群资源的调度功能,其根据特定调度算法和策略,将Pod调度到最优工作节点上,从而更合理与充分的利用集群计算资源。
其作用是根据特定的调度算法和策略将Pod调度到指定的计算节点(Node)上,其做为单独的程序运行,启动之后会一直监听API Server,获取PodSpec.NodeName为空的Pod,对每个Pod都会创建一个绑定。
默认情况下,k8s的调度器采用扩散策略
,将同一集群内部的pod对象调度到不同的Node节点,以保证资源的均衡利用。
- 首先用户通过 Kubernetes 客户端 Kubectl 提交创建 Pod 的 Yaml 的文件,向Kubernetes 系统发起资源请求,该资源请求被提交到Kubernetes 系统中,用户通过命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式发送“POST”请求,即创建 Pod 的请求。
- APIServer 接收到请求后把创建 Pod 的信息存储到 Etcd 中,从集群运行那一刻起,资源调度系统 Scheduler 就会定时去监控 APIServer,通过 APIServer 得到创建 Pod 的信息,Scheduler 采用 watch 机制,一旦 Etcd 存储 Pod 信息成功便会立即通知APIServer。
- APIServer会立即把Pod创建的消息通知Scheduler,Scheduler发现 Pod 的属性中 Dest Node 为空时(Dest Node=””)便会立即触发调度流程进行调度。
在调度的过程当中有3个阶段:节点预选、节点优选、节点选定,从而筛选出最佳的节点。
节点预选:基于一系列的预选规则对每个节点进行检查,将那些不符合条件的节点过滤,从而完成节点的预选
节点优选:对预选出的节点进行优先级排序,以便选出最合适运行Pod对象的节点
节点选定:从优先级排序结果中挑选出优先级最高的节点运行Pod,当这类节点多于1个时,则进行随机选择
Kubernetes调度器使用Predicates和Priorites来决定一个Pod应该运行在哪一个节点上。
Predicates是强制性规则,用来形容主机匹配Pod所需要的资源,如果没有任何主机满足该Predicates, 则该Pod会被挂起,直到有主机能够满足。
Kubernetes中的调度策略主要分为全局调度与运行时调度2种。其中全局调度策略在调度器启动时配置,而运行时调度策略主要包括选择节点(nodeSelector),节点亲和性(nodeAffinity),pod亲和与反亲和性(podAffinity与podAntiAffinity)。
三、污点和容忍
Taint需要与Toleration配合使用,让pod避开那些不合适的node。在node上设置一个或多个Taint后,除非pod明确声明能够容忍这些“污点”,否则无法在这些node上运行。Toleration是pod的属性,让pod能够(注意,只是能够,而非必须)运行在标注了Taint的node上。
- 污点
基本语法:
kubectl taint node [node] key=value[effect]
其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
NoSchedule :一定不能被调度。
PreferNoSchedule:尽量不要调度。
NoExecute:不仅不会调度,还会驱逐Node上已有的Pod。
示例说明:
kubectl taint nodes node1 key=value:NoSchedule
在node1上加一个Taint,该Taint的键为key,值为value,Taint的效果是NoSchedule。这意味着除非pod明确声明可以容忍这个Taint,否则就不会被调度到node1上。
添加污点:
# 添加taint
[root@master ~]# kubectl taint nodes master node-role.kubernetes.io/master=:NoExecute
node/master tainted
# 查看污点
[root@master ~]# kubectl describe nodes master
Name: master
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=master
kubernetes.io/os=linux
node-role.kubernetes.io/master=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
projectcalico.org/IPv4Address: 192.168.247.130/24
projectcalico.org/IPv4IPIPTunnelAddr: 192.168.219.64
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 07 Nov 2019 13:46:21 -0500
Taints: node-role.kubernetes.io/master:NoSchedule
# 去除污点
[root@master ~]# kubectl taint nodes master node-role.kubernetes.io/master=:NoSchedule-
node/master untainted
# 查看污点
[root@master ~]# kubectl describe nodes master
Name: master
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=master
kubernetes.io/os=linux
node-role.kubernetes.io/master=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
projectcalico.org/IPv4Address: 192.168.247.130/24
projectcalico.org/IPv4IPIPTunnelAddr: 192.168.219.64
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Thu, 07 Nov 2019 13:46:21 -0500
Taints: <none>
- 容忍
容忍设置
Toleration设置为可以容忍具有该Taint的Node,使得pod能够被调度到node1上
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
pod的Toleration声明中的key和effect需要与Taint的设置保持一致,并且满足以下条件之一:
operator的值为Exists,这时无需指定value
operator的值为Equal并且value相等
如果不指定operator,则默认值为Equal。
另外还有如下两个特例:
空的key配合Exists操作符能够匹配所有的键和值
空的effect匹配所有的effect
effect说明:
NoSchedule
: 如果一个pod没有声明容忍这个Taint,则系统不会把该Pod调度到有这个Taint的node上
PreferNoSchedule
:NoSchedule的软限制版本,如果一个Pod没有声明容忍这个Taint,则系统会尽量避免把这个pod调度到这一节点上去,但不是强制的。
NoExecute
:定义pod的驱逐行为,以应对节点故障。
NoExecute这个Taint效果对节点上正在运行的pod有以下影响:
1)没有设置Toleration的Pod会被立刻驱逐;
1)配置了对应Toleration的pod,如果没有为tolerationSeconds赋值,则会一直留在这一节点中;
配置了对应Toleration的pod且指定了tolerationSeconds值,则会在指定时间后驱逐。
从kubernetes 1.6版本开始引入了一个alpha版本的功能,即把节点故障标记为Taint(目前只针对node unreachable及node not ready,相应的NodeCondition "Ready"的值为Unknown和False)。激活TaintBasedEvictions功能后(在--feature-gates参数中加入TaintBasedEvictions=true),NodeController会自动为Node设置Taint,而状态为"Ready"的Node上之前设置过的普通驱逐逻辑将会被禁用。
注意,在节点故障情况下,为了保持现存的pod驱逐的限速设置,系统将会以限速的模式逐步给node设置Taint,这就能防止在一些特定情况下(比如master暂时失联)造成的大量pod被驱逐的后果。这一功能兼容于tolerationSeconds,允许pod定义节点故障时持续多久才被逐出。
- 允许将Pod副本调度到Master节点上
让 Master 也当作 Node 使用
(1)如果想让 Pod 也能调度到在 Master(本样例即 localhost.localdomain)上,可以执行如下命令使其作为一个工作节点:
注意:利用该方法,我们可以不使用 minikube 而创建一个单节点的 K8S 集群。
kubectl taint node localhost.localdomain node-role.kubernetes.io/master-
(2)将 Master 恢复成 Master Only 状态
如果想禁止 Master(本样例即:master )部署 pod,则可执行如下命令:
# 第1 个 master 为主机名 第2个master为key
kubectl taint node master node-role.kubernetes.io/master="":NoSchedule