1.Kubernetes Scheduler简介
Kubernetes 调度器(Scheduler)是Kubernetes的核心组件;用户或者控制器创建Pod之后,调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。调度器会依据下文的调度原则来做出调度选择。
kube-scheduler 给一个 pod 做调度选择包含两个步骤:过滤、打分
过滤阶段:会将所有满足 Pod 调度需求的 Node 选出来。例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下,这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。
我们可以使用多种规则比如:
- 设置cpu、内存的使用要求;
- 增加node的label,并通过pod.Spec.NodeSelector进行强匹配;
- 直接设置pod的nodeName,跳过调度直接下发。
注:k8s 1.2加入了一个实验性的功能:affinity。意为亲和性。这个特性的设计初衷是为了替代nodeSelector,并扩展更强大的调度策略。
2.Scheduler工作原理
- 节点预选(Predicate):排除完全不满足条件的节点,如内存大小,端口等条件不满足。
- 节点优先级排序(Priority):根据优先级选出最佳节点
- 节点择优(Select):根据优先级选定节点
-
首先用户通过 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=””)便会立即触发调度流程进行调度。
-
而这一个创建Pod对象,在调度的过程当中有3个阶段:节点预选、节点优选、节点选定,从而筛选出最佳的节点
-
节点预选:基于一系列的预选规则对每个节点进行检查,将那些不符合条件的节点过滤,从而完成节点的预选
-
节点优选:对预选出的节点进行优先级排序,以便选出最合适运行Pod对象的节点
-
节点选定:从优先级排序结果中挑选出优先级最高的节点运行Pod,当这类节点多于1个时,则进行随机选择
-
3.Pod调度
Kubernetes中,Pod通常是容器的载体,一般需要通过Deployment、DaemonSet、RC、Job等对象来完成一组Pod的调度与自动控制功能。
3.1 Depolyment/RC自动调度
Deployment或RC的主要功能之一就是自动部署一个容器应用的多份副本,以及持续监控副本的数量,在集群内始终维持用户指定的副本数量。
[root@uk8s-m-01 study]# vi nginx-deployment.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment-01 spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 [root@uk8s-m-01 study]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment-01 3/3 3 3 30s [root@uk8s-m-01 study]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-01-5754944d6c 3 3 3 75s [root@uk8s-m-01 study]# kubectl get pod | grep nginx nginx-deployment-01-5754944d6c-hmcpg 1/1 Running 0 84s nginx-deployment-01-5754944d6c-mcj8q 1/1 Running 0 84s nginx-deployment-01-5754944d6c-p42mh 1/1 Running 0 84s
3.2 NodeSelector定向调度
当需要手动指定将Pod调度到特定Node上,可以通过Node的标签(Label)和Pod的nodeSelector属性相匹配。
# kubectl label nodes <node-name> <label-key>=<label-value>
node节点创建对应的label后,可通过在定义Pod的时候加上nodeSelector的设置实现指定的调度。
[root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io node/172.24.9.14 labeled [root@uk8s-m-01 study]# vi nginx-master-controller.yaml kind: ReplicationController metadata: name: nginx-master labels: name: nginx-master spec: replicas: 1 selector: name: nginx-master template: metadata: labels: name: nginx-master spec: containers: - name: master image: nginx:1.7.9 ports: - containerPort: 80 nodeSelector: speed: io [root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml [root@uk8s-m-01 study]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE nginx-master-7fjgj 1/1 Running 0 82s 172.24.9.71 172.24.9.14
3.3 NodeAffinity亲和性调度
- 更具表达力,即更精细的力度控制;
- 可以使用软限制、优先采用等限制方式,即调度器在无法满足优先需求的情况下,会使用其他次条件进行满足;
- 可以依据节点上正在运行的其他Pod的标签来进行限制,而非节点本身的标签,从而实现Pod之间的亲和或互斥关系。
- requiredDuringSchedulingIgnoredDuringExecution:硬规则,必须满足指定的规则,调度器才可以调度Pod至Node上(类似nodeSelector,语法不同)。
- preferredDuringSchedulingIgnoredDuringExecution:软规则,优先调度至满足的Node的节点,但不强求,多个优先级规则还可以设置权重值。
- IgnoredDuringExecution指:如果一个Pod所在的节点在Pod运行期间标签发生了变化,不再符合该Pod的节点亲和性需求,则系统将忽略Node上Label的变化,该Pod能继续在该节点运行。
示例:条件1:只运行在amd64的节点上;尽量运行在ssd节点上。
[root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: with-node-affinity image: gcr.azk8s.cn/google_containers/pause:2.0
NodeAffinity操作语法;In、NotIn、Exists、DoesNotExist、Gt、Lt。NotIn和DoesNotExist可以实现互斥功能。
NodeAffinity规则设置注意事项:
- 若同时定义nodeSelector和nodeAffinity,则必须两个条件都满足,Pod才能最终运行指定在Node上;;
- 若nodeAffinity指定多个nodeSelectorTerms,则只需要其中一个能够匹配成功即可;
- 若nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该Pod。
3.4 PodAffinity亲和性调度
PodAffinity根据节点上正在运行的Pod标签而不是Node标签来判断和调度,要求对节点和Pod两个条件进行匹配。
规则描述为:若在具有标签X的Node上运行了一个或多个符合条件Y的Pod,则Pod应该(或者不应该)运行在这个Node上。
X通常为Node节点的机架、区域等概念,Pod是属于某个命名空间,所以条件Y表达的是一个或全部命名空间中的一个Label Selector。
Pod亲和性定义与PodSpec的affinity字段下的podAffinity字段里,互斥性定义于同一层次的podAntiAffinity子字段中。
[root@uk8s-m-01 study]# vi nginx-flag.yaml #创建名为pod-flag,带有两个标签的Pod apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: gcr.azk8s.cn/google_containers/pause:2.0
[root@uk8s-m-01 study]# vi nginx-affinity-in.yaml #创建定义标签security=S1,对应如上Pod “Pod-flag”。 apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: gcr.azk8s.cn/google_containers/pause:2.0 [root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml [root@uk8s-m-01 study]# kubectl get pods -o wide
提示:由上Pod亲和力可知,两个Pod处于同一个Node上。
[root@uk8s-m-01 study]# vi nginx-affinity-out.yaml #创建不能与参照目标Pod运行在同一个Node上的调度策略 apiVersion: v1 kind: Pod metadata: name: anti-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta.kubernetes.io/zone podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - nginx topologyKey: kubernetes.io/hostname containers: - name: anti-affinity image: gcr.azk8s.cn/google_containers/pause:2.0 [root@uk8s-m-01 study]# kubectl get pods -o wide #验证
3.5 Taints和Tolerations(污点和容忍)
Taint:使Node拒绝特定Pod运行;
Toleration:为Pod的属性,表示Pod能容忍(运行)标注了Taint的Node。
Taint语法:$ kubectl taint nodes node1 key=value:NoSchedule
解释:为node1加上一个Taint,该Taint的键为key,值为value,Taint的效果为NoSchedule。即除非特定声明可以容忍此Taint,否则不会调度至node1上。
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule"
或
tolerations: - key: "key1" operator: "Exists" effect: "NoSchedule"
- operator的值是Exists(无须指定value);
- operator的值是Equal并且value相等;
- 空的key配合Exists操作符能够匹配所有的键和值;
- 空的effect匹配所有的effect。
若不指定operator,则默认值为Equal。
taint说明:系统允许在同一个Node上设置多个taint,也可以在Pod上设置多个toleration。Kubernetes调度器处理多个taint和toleration的逻辑顺序:首先列出节点中所有的taint,然后忽略pod的toleration能够匹配的部分,剩下的没有忽略掉的taint就是对pod的效果。以下是几种特殊情况:
- 若剩余的taint中存在effect=NoSchedule,则调度器不会把该Pod调度到这一节点上;
- 若剩余的taint中没有NoSchedule效果,但有PreferNoSchedule效果,则调度器会尝试不把这个Pod指派到此节点;
- 若剩余taint的效果有NoSchedule,并且这个Pod已经在该节点上运行,则会被驱逐,若没有在该节点上运行,也不会再被调度到该节点上。
$ kubectl taint node node1 key=value1:NoSchedule $ kubectl taint node node1 key=value1:NoExecute $ kubectl taint node node1 key=value2:NoSchedule tolerations: - key: "key1" operator: "Equal" value: "value" effect: "NoSchedule" tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute"
释义:此Pod声明了两个容忍,且能匹配Node1的taint,但是由于没有能匹配第三个taint的toleration,因此此Pod依旧不能调度至此Node。若该Pod已经在node1上运行了,那么在运行时设置了第3个taint,它还能继续在node1上运行,这是因为Pod可以容忍前两个taint。
通常,若node加上effect=NoExecute的taint,那么该Node上正在运行的所有无对应toleration的Pod都会被立刻驱逐,而具有相应toleration的Pod则永远不会被驱逐。同时,系统可以给具有NoExecute效果的toleration加入一个可选的tolerationSeconds字段,表明Pod可以在taint添加到Node之后还能在此Node运行多久。
tolerations: - key: "key1" operator: "Equal" value: "value" effect: "NoSchedule" tolerationSeconds: 3600
释义:若Pod正在运行,所在节点被加入一个匹配的taint,则这个pod会持续在该节点运行3600s后被驱逐。若在此期限内,taint被移除,则不会触发驱逐事件。
- 独占节点:
给特定的节点运行特定应用。
$ kubectl taint nodes 【nodename】 dedicated=groupName:NoSchedule
同时在Pod中设置对应的toleration配合,带有合适toleration的Pod允许同时使用其他节点一样使用有taint的节点。
- 具有特殊硬件设备的节点
集群中部分特殊硬件(如安装了GPU),则可以把不需要占用GPU的Pod禁止在此Node上调度。
1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule 2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule
- 定义Pod驱逐行为
NoExecute的taint对节点上正在运行的Pod有以下影响:
- 没有设置toleration的pod会被立刻驱逐;
- 配置了对应toleration的pod,若没有为tolerationSeconds赋值,则会一直保留在此节点中;
- 配置了对应toleration的pod,且为tolerationSeconds赋值,则在指定时间后驱逐。
3.6 nodeName
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx nodeName: kube-01
注:上面的 pod 将指定运行在 kube-01 节点上。
使用 nodeName
来选择节点的一些限制:
- 如果指定的节点不存在,
- 如果指定的节点没有资源来容纳 Pod,Pod 将会调度失败并且其原因将显示为, 比如 OutOfmemory 或 OutOfcpu。
- 云环境中的节点名称并非总是可预测或稳定的