kubernetes高级调度特性

Kubernetes的调度在大部分场景下工作良好-例如,它能够确保Pod运行在具有足够空闲资源的节点上,它试图在跨节点的在传播同一集合的PodReplicaSet,StatefulSet,etc),试图平衡节点的资源使用等。

但是有些时候你想过要去控制你的Pods怎么去调度,比如你可能想要保证一些Pod只会在一些特定的硬件的节点上去进行调度,或者你想过要通信频繁的的服务放在一起(co-locate)。或者你想要将一组节点用于一组的特定用户。最终,你能够知道的更多关于你的应用是怎么调度以及部署的。所以Kubernetes1.6提供了四个高级的调度特性:节点的亲和性和反亲和性,taintstolerations, Pod的亲和性以及反亲和性。这些特性当前在Kubernetes1.6中是Beta状态.

节点的亲和性以及反亲和性

Node Affinity/Anti-Affinity是通过在调度器设置规则来确定哪些节点将会被调用。这个特性是nodeSelector特性的泛化,nodeSelector特性从Kubernetes 1.0版本就已经出现,这些规则的定义采用类似的概念:通过在节点上自定义标签和在pods上定义selector,它们可以使必选或者首选的,这取决于你希望调度程序强制执行它们的严格程序。
特定的规则必须满足Pod被调度到特定的节点上。如果没有节点满足该约束(加上所有其他正常的约束,比如有足够的空闲资源来处理该pod对资源的请求),否则该Pod将不会被调度,需要的规则通过nodeAffinity中的requiredDuringSchedulingIgnoredDuringExecution字段来指定需要的规则。

比如,如果你想要调度Pod到使用us-centrall-aGCE zone的节点上,你可以再Pod的规格中指定如下的亲合性规则。

affinity:
 nodeAffinity:
   requiredDuringScheduling IgnoredDuringExecution:
     nodeSelectorTerms:
       - matchExpressions:
         - key: "failure-domain.beta.kubernetes.io/zone"
           operator: In
           values: ["us-central1-a"]

IgnoredDuringExecution字段表示如果node上的标签改变或者亲和性规则永远不可能满足的时候,仍然能够运行Pod.有未来的计划将会提供requiredDuringSchedulingRequiredDuringExecution,他将会从节点中驱赶(evictpod,一旦它们不能满足node的亲和性规则的时候。
更好的规则是如果有节点匹配这些规则,他们将会首先被选中,如果没有更合适的节点可以使用的情况下,非最合适的节点被选择。你如果是更希望而不是必须pod部署到us-central1-a,可以通过稍微修改pod的规则中使用preferredDuringSchedulingIgnoredDuringExecution来达到目的。

affinity:
 nodeAffinity:
   preferredDuringSchedulingIgnoredDuringExecution:
     nodeSelectorTerms:
       - matchExpressions:
         - key: "failure-domain.beta.kubernetes.io/zone"
           operator: In
           values: ["us-central1-a"]

节点的反亲和性是通过使用相反的操作来实现,比如你想要我们的 Pod 创建的时候避免使用 us-centroal1-a 中的节点,我们可以通过如下来实现:

affinity:
 nodeAffinity:
   requiredDuringSchedulingIgnoredDuringExecution:
     nodeSelectorTerms:
       - matchExpressions:
         - key: "failure-domain.beta.kubernetes.io/zone"
           operator: NotIn
           values: ["us-central1-a"]
同样的操作我们可以使用 In, NotIn, Exists DoesNotExist ,以及 Gt Lt.

其它的用户使用场景是根据节点的硬件架构,操作系统版本或者专用硬件来限制调度。在Kubernetes1.6版本中节点的亲和性以及反亲和性处于Beta版本。

Taints and Tolerations污点以及容忍

taints and tolerations的相关功能是允许你标注(taint)节点,那样没有Pods可以调度到这个节点上,除非pod明确的”tolerates”这个”taint”。在节点上标注而不是pos(as innode affinity/anti-affinity)是一些场景下有特殊的使用,比如希望集群中的大部分pods不要调度到某些节点上。比如,你可能想要标注你的master节点值调度运行Kubernetes的系统组件,或者贡献一部分节点给特定的用户组,或者是保持一般的Pods不要调度到特定硬件功能的节点上,这样就能够将这些特定硬件的节点预留空间分配给需要这些硬件的Pods来使用

kubectl命令行允许你在节点上设置taints,比如如下所示:

kubectl taint nodes node1 key=value:NoSchedule

创建一个污点(taint),通过key,value,effect=NoSchedule来标注节点不要被无法容忍污点的pod来调度。其他污点的effect=preferNoSchedule,它可能是NoSchedule更好的选择,NoExecute意味着在节点上运行的任何pods将会被驱逐,除非它们容忍污点。容忍污点你可以再Pod的规格中添加对于的容忍污点的说明,就像下面代码一样:

tolerations:
- key: "key"
 operator: "Equal"
 value: "value"
 effect: "NoSchedule"
除了在 kubernetes1.6 中将 taints tolerations 功能升级到 beta 版本,引入了一个 alpha 功能,允许你使用 taints tolerations 功能来定制当节点遭遇像网络分区这样的问题的时候来隔离 pod 到某个节点的时间,而不是使用默认的五分钟的时间,详细的内容可以参数 this sections.

Pod的亲和性和反亲和性

节点的亲和性和反亲和性允许我们通过node的标签来限制那些节点来运行Pod。但是如果你想要指定规则pods应该相对于其它的Pod来调度,比如比如你想要加速或者包装一个服务中的pods或者是其它服务中相关的pods?在这种场景下,你可以使用pod的亲和性和反亲和性,在kubernetes1.6中该特性处于beta阶段。

让我们来看一个例子,比如你在S1的服务中有一个front-ends,他们需要跟服务S2中的back-ends频繁的进行通信(一个南-北向的通信模式)。所以你想要两个服务协同co-located在通过一个云提供者的分区中,但是你不想要手动的去选择分区如果这个分区失败,你想要pods可以被重新调度到其它的分区。你可以通过pod的亲和性规则来实现该功能,假如你给服务的Pods指定了标签service=S2和其它服务的Pods指定了标签”service=S1”:

affinity:
   podAffinity:
     requiredDuringSchedulingIgnoredDuringExecution:
     - labelSelector:
         matchExpressions:
         - key: service
           operator: In
           values: [“S1”]
       topologyKey: failure-domain.beta.kubernetes.io/zone

跟节点的亲和性/反亲和性一样,也存在一个requiredDuringSchedulingIgnoredDuringExecution变量

Pod的亲和性和反亲和性是很灵活的。想象一下,您已经分析了你的服务的性能,发现来自服务S1的容器在共享相同节点时会干扰来自服务S2的容器,这可能是由于缓存干扰效应或饱和网络链路。或者也许是由于安全性问题,您不想要容器S1S2共享一个节点。要实现这些规则,只需对上述代码段进行两次更改即可更改podAffinitypodAntiAffinity并将topologyKey更改为kubernetes.io/hostname

自定义调度器

如果Kubernetes调度程序的各种功能不能为您的工作负载调度提供足够的控制权,则可以委托将任意子集的pod调度到您自己的自定义调度程序,而不是默认Kubernetes调度程序。多个调度程序在Kubernetes1.6中是beta.

每个新的pod将会被默认的调度器所调用。但是如果我们提供自己的调度器,这个默认的调度器将会忽略这些pod,允许自定义的调度器来调取到节点上,如下面的例子一样.

这里我们创建pod的时候执行schedulerName字段:

apiVersion: v1
kind: Pod
metadata:
 name: nginx
 labels:
   app: nginx
spec:
 schedulerName: my-scheduler
 containers:
 - name: nginx
   image: nginx:1.10

如果我们在不部署自定义调度程序的情况下创建此Pod,则默认调度程序将忽略它,并且它将保持处于挂起状态。因此,我们需要一个自定义调度程序来查找和调度其schedulerName字段为my-schedulerpod

一个自定义的调度器可以使用任何语言来定义,可以根据你的需要来决定它的复杂度。这里一个通过bash来写的简单的调度器的例子,它随机的分配节点。注意到你需要运行kubectl proxy来配合它的工作。

#!/bin/bash
SERVER='localhost:8001'
while true;
do
   for PODNAME in $(kubectl --server $SERVER get pods -o json | jq '.items[] | select(.spec.schedulerName == "my-scheduler") | select(.spec.nodeName == null) | .metadata.name' | tr -d '"')
;
   do
       NODES=($(kubectl --server $SERVER get nodes -o json | jq '.items[].metadata.name' | tr -d '"'))
       NUMNODES=${#NODES[@]}
       CHOSEN=${NODES[$[ $RANDOM % $NUMNODES ]]}
       curl --header "Content-Type:application/json" --request POST --data '{"apiVersion":"v1", "kind": "Binding", "metadata": {"name": "'$PODNAME'"}, "target": {"apiVersion": "v1", "kind"
: "Node", "name": "'$CHOSEN'"}}' http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/
       echo "Assigned $PODNAME to $CHOSEN"
   done
   sleep 1
done
更多知识

Kubernetes 1.6发行说明有关于这些功能的更多信息,包括有关如何更改配置的详细信息,如果您已经使用Alpha版本的一个或多个这些功能(这是必需的,因为从alphabeta的转变是一个突破更改这些功能)

致谢

这里描述的功能,包括AlphaBeta版本,都是真正的社区努力,涉及Google,华为,IBMRed Hat等的工程师。

参与其中

参与每周的 community meeting

·                    Stack Overflow上发布问题 

·                    Twitter @Kubernetesio 上关注最新的更新for latest updates

·                     Slack (room#sig-scheduling)上关注社区

非常感谢你的贡献。

--Ian Lewis, Developer Advocate, and David Oppenheimer, Software Engineer,Google

翻译于  http://blog.kubernetes.io/2017/03/advanced-scheduling-in-kubernetes.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值