• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Kubernetes 1.6新特性系列 | 高级调度

k8s 搞java代码 3年前 (2022-05-13) 12次浏览 已收录 0个评论
文章目录[隐藏]

作者注:这是深入Kubernetes 1.6特性系列的第四篇。

导读:
Kubernetes 1.6高级调度的新特性主要集中在四个方面:
Node的亲和性和反亲和性(Affinity/Anti-Affinity)
Node的污点和容忍(Taints and Tolerations)
Pod的亲和性和反亲和性(Affinity/Anti-Affinity)
自定义调度器

1、简介

Kubernetes的调度器在大多数情况下能过运行的很好,例如:它能够将Pod调度到有充足资源的Node上;它能够将一组Pod(ReplicaSet, StatefulSet,等)均匀的调度到不同的Node上;它尽力平衡各个节点的资源使用率等。

但有些时候您会想控制您的Pod如何调度,例如:可能您想让一些Pod被确定调度到某些使用特殊硬件的节点上,或者您想让交互频繁的服务一起调度,或者您想让一些Node只给特定的一些用户提供服务等等。最终,您对于应用程序调度和部署的需求永远要比Kubernetes提供的多。因此,Kubernetes 1.6提供了四个高级高级调度功能:节点亲和性和反亲和性,污点和容忍,Pod亲和性/反亲和性和自定义调度。这四个特性在Kubernetes 1.6版本中都是beta版。

2、Node亲和性/反亲和性

Node亲和性/反亲和性是在Node上设置如何被Scheduler选择的规则一种方式。此功能是自Kubernetes 1.0版本以来在Kubernetes中的nodeSelector的功能的通用化。规则是使用在Pod中指定和选择器上自定义的标签等用户熟悉的概念定义的,并且他们是必需的或者首选的,这取决于您希望调度程序强制执行他们的严格程度。

A必需的规则(Required)

只有满足必需的规则的Pod才会被调度到特定的Node上。如果没有Node匹配条件(加上所有其他所有正常的条件,例如为Pod请求提供足够的可用资源),否则Pod不会被调度。必需满足的规则在nodeAffinity的requiredDuringSchedulingIgnoredDuringExecution字段中指定。

例如,如果我们要求在多可用区域(Multiple Zones)的us-central1-a(GCE)区域中的节点上进行调度,则可以将以下的关联规则指定为Pod规范(Spec)的一部分:

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

www#gaodaima.com来源[email protected]搞@^&代*@码)网搞代码

“IgnoredDuringExecution”意味着如果Node上的标签发生更改,并且亲和性的规则不再满足时选择忽略。这个在未来会计划实现。
“requiredDuringSchedulingRequiredDuringExecution”意味着一旦他们不满足节点亲和性规则,将从Node上驱逐不再匹配规则的Pod。

B首选的规则(Preferred)

首选规则意味着如果节点与规则匹配,则将优先选择它们,并且仅当没有优选节点可用时才选择非优选节点。您可以选择使用首选规则,而不是通过必需规则强制将Pod部署到GCE的us-central1-a区域中的节点上。使用首选规则,则需指定preferredDuringSchedulingIgnoredDuringExecution:

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

Node的反亲和性能够使用负操作符(NotIn, DoesNotExist等)来表示。下面的例子说明了如何禁止您的Pod被调度到us-central1-a的区域中:

<span class="">affinity</span>:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      <span class="">nodeSelectorTerms</span>:
      - <span class="">matchExpressions</span>:
        - <span class="">key</span>: <span class="">"failur-domain.beta.kubernetes.io/zone"</span>
          operator: NotIn
          <span class="">values</span>: <span class="">["us-central1-a"]</span>

可以使用的操作符有:In, NotIn, Exists, DoesNotExist, Gt, 和Lt。

这个特性还有一些另外的使用场景,比如需要在调度上严格区别Node上的硬件架构,操作系统版本,或者专用的硬件等。

Node的亲和性和反亲和性在Kubernetes 1.6版本中是Beta版。

3、污点和容忍(Taints and Tolerations)

此功能允许您标记一个Node(“受污染”,“有污点”),以便没有Pod可以被调度到此节点上,除非Pod明确地“容忍”污点。标记的是Node而不是Pod(如节点的亲和性和反亲和性),对于集群中大多数Pod应该避免调度到特定的节点上的功能特别有用,例如,您可能希望主节点(Master)标记为仅可调度Kubernetes系统组件,或将一组节点专用于特定的用户组,或者让常规的Pod远离具有特殊硬件的Node,以便为有特殊硬件需求的Pod留出空间。

使用kubectl命令可以设置节点的“污点”,例如:

kubectl taint nodes node1 key=value:NoSchedule

创建一个污点并标记到Node,那些没有设置容忍的Pod(通过key-value方式设置NoSchedule,这是其中一个选项)不能调度到该Node上。其他污点的选项是PerferredNoSchedule,这是NoSchedule首选版本;还有NoExecute,这个选项意味着在当Node被标记有污点时,该Node上运行的任何没有设置容忍的Pod都将被驱逐。容忍将被添加到PodSpec中,看起来像这样:

tolerations: 
  - <span class="">key</span>: <span class="">"key"</span>
    <span class="">operator</span>: <span class="">"Equal"</span>
    <span class="">value</span>: <span class="">"value"</span>
    effect: "NoSchedule"

除了将污点和容忍(Taints and Tolerations)特性在Kubernetes 1.6中移至Beta版外,我们还引入了一个使用污点和容忍的Alpha的特性:允许用户自定义一个Pod被绑定到Node上后遇到了诸如网络分区的问题时的行为(可能Pod希望长时间允许在这个Node上,或者网络分区会很快恢复),而不是现在默认的等待五分钟超时。更详细的信息,请参阅文档。

4、Pod的亲和性和反亲和性

Node的亲和性和反亲和性允许您基于节点的标签来限制Pod的调度行为。但是,如果您想要指定Pod的亲和关系时这种方法就无法奏效了。例如,如何实现在一个服务或者相关的服务中聚合Pod或将Pod均匀分布?为此,您可以使用Pod的亲和性和反亲和性特性,它在Kubernetes 1.6中也是Beta版。

我们来看一个例子。假设您在服务S1中有个前端应用,它经常与服务S2的后端应用进行通信。因此,您希望这两个服务共同位于同一个云提供商的区域中,但您不需要手动选择区域(如果有些区域暂时不可用),希望将Pod重新调度到另一个(单个的)区域。您可以像这样指定Pod的亲和性和反亲和性规则(假设您将该服务的Pod命名为*”service=S2″,另外一个服务的Pod为”service=S1″):

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

如同Node的亲和性和反亲和性,也有一个preferredDuringSchedulingIgnoredDuringExecution变量。

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

5、自定义调度器

如果Kubernetes Scheduler的这些特性没能足够满足您控制负载的需求,您可以在将任意子集的Pod的调度任务交给您自己的自定义调度器,自定义的调度器可以跟默认的调度器(Kubernetes Scheduler)一起运行,或者替代默认的调度器。多调度器(Multiple schedulers)在Kubernetes 1.6中是Beta版。

在默认的情况下,每个新的Pod都使用默认的调度器进行调度。但是如果您提供了自定义调度器的名称,默认的调度器会忽略Pod的调度请求,允许您的自定义调度器对Pod进行调度。看看下面的例子:
在Pod的规范(Spec)中制定调度器的名字:

<span class="">apiVersion</span>: <span class="">v1
kind</span>: <span class="">Pod
metadata</span>:  <span class="">
  name</span>: <span class="">nginx</span><span class="">    
  labels</span>:    
    <span class="">app</span>: <span class="">nginx
spec</span>:
  schedulerName: my-scheduler
  <span class="">containers</span>:
  - <span class="">name</span>: <span class="">nginx</span>
    <span class="">image</span>: <span class="">nginx:1.10</span>

如果我们在没有部署自定义调度器的情况下创建了这个Pod,结果会是默认的调度器将忽略这个Pod,它将处于Pending状态。因此,我们需要一个自定义调度程序来查找和调度其schedulerName字段为my-scheduler的Pod。

自定义调度语言可以用任何语言编写,调度策略根据需要可以简单也可以复杂。这是一个非常简单的例子,它使用Bash编写,它可以为Pod随机分配一个Node。请注意,您需要让它与kubectl proxy一起运行:

<span class="">#!/bin/bash</span>
SERVER="localhost:8001" # Proxy address for apiServer<span class="">
while</span> <span class="">true;
do</span>
    # Get all pods, and pod"s properties
    <span class="">for</span> <span class="">PODNAME</span> <span class="">in</span> <span class="">$(kubectl --server $SERVER get pods -o json 
            | jq ".items[] 
            | select(.spec.schedulerName == "my-scheduler") 
            | select(.spec.nodeName == null) 
            | .metadata.name" | tr -d """);</span>
    <span class="">do</span>
        # Get all nodes
        NODES=(<span class="">$(kubectl --server $SERVER get nodes -o json 
                | jq ".items[].metadata.name" 
                | tr -d """)</span>)
        NUMNODES=<span class="">${#NODES[@]}</span>
        
        # Choose a node randomly
        CHOSEN=<span class="">${NODES[$[ $RANDOM % $NUMNODES ]]}</span>
        
        # Bind a pod($PODNAME) to a node($CHOSEN)
        curl --header <span class="">"Content-Type:application/json"</span>  
             --request POST 
             --data <span class="">
            "{
                 "apiVersion":"v1",
                 "kind": "Binding",
                 "metadata": {
                     "name": ""$PODNAME""
                 }, 
                 "target": {
                     "apiVersion": "v1", 
                     "kind": "Node", 
                     "name": ""$CHOSEN""
                 }
             }"</span>
             http://<span class="">$SERVER</span>/api/v1/namespaces/default/pods/<span class="">$PODNAME</span>/binding/        <span class="">echo</span> <span class="">"Assigned $PODNAME to $CHOSEN"</span>
    <span class="">done</span>
    sleep 1
<span class="">done</span>

Kubernetes 1.6的release notes关于这个特性有更多的介绍,包括您已经使用了这些(其中一个或者多个)特性的Alpha版本改如何进行配置的细节(这些事必需的,因为对于这些特性,从Alpha到Beta的转变是突破性的)。

6、致谢

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

7、参与其中

参与每周的 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

8、加入容器时代

容器时代公众号的目的是希望能够传播容器技术和理念,让更多的人能够享受到这场技术革命带来的好处。虽然我们不是大牛,对容器技术生态的了解和认识也还不够深刻,但是我们乐于分享,乐于交流。不管读者的你是学生,还是工程师,甚至都不是,我们都欢迎你加入进来,可以一起写文章、翻译文章,也可以一起分享经验、聊聊踩过的那些坑!为此特意建立了一个微信群,长按识别下方二维码加入,我们以梦为马,一起前行!

(微信群已满,请添加k8stimes或者扫下面二维码添加好友,小助手会将您拉入群聊)

 


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Kubernetes 1.6新特性系列 | 高级调度

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址