Assigning Pods to Nodes(将Pod分配到Node)

    您可以在 找到这些示例的所有文件。

    是最简单的约束形式。 nodeSelector 是PodSpec的一个字段。它指定键值对的映射。为了使Pod能够在Node上运行,Node必须将每个指定的键值对作为标签(也可有其他标签)。最常见的用法是使用一个键值对。

    下面,我们来来看一下如何使用 nodeSelector

    这个例子假设你对Kubernetes Pod有一个基本的了解,并已经 turned up a Kubernetes cluster

    运行 kubectl get nodes ,获取集群Node的名称。选择要添加Label的Node,然后运行 kubectl label nodes <node-name> <label-key>=<label-value> ,向您所选的Node添加Label。例如,如果我的Node名称是kubernetes-foo-node-1.ca-robinson.internal ,而我想要的标签是disktype=ssd ,那么可使用 kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd

    如果此命令出现“invalid command”的错误,那么你可能使用的是旧版本的kubectl,它没有 label 命令。 在这种情况下,有关如何在Node上手动设置Label的说明,请参阅本指南的 。

    另外请注意,Label的key必须采用DNS标签的格式(如 identifiers doc 所述),这意味着key不允许包含大写字母。

    您可以通过重新运行 kubectl get nodes --show-labels 并检查Node是否已经有你所设的标签标签,来验证Label是否成功添加。

    在任意一个你想运行的Pod的配置文件中添加nodeSelector部分,如下所示。例如,如果我的Pod配置如下:

    需要像这样添加一个nodeSelector:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: nginx
    5. labels:
    6. env: test
    7. spec:
    8. containers:
    9. - name: nginx
    10. image: nginx
    11. imagePullPolicy: IfNotPresent
    12. nodeSelector:
    13. disktype: ssd

    当您运行 kubectl create -f pod.yaml 时 ,该Pod将在您拥有以上标签的Node上调度!您可以通过运行 kubectl get pods -o wide 查看该Pod所在的“NODE”,来验证是否正常工作。

    除你 的Label以外,Node还预设了一组标准的Label。 从Kubernetes v1.4起,这些Label是:

    • kubernetes.io/hostname
    • failure-domain.beta.kubernetes.io/zone
    • failure-domain.beta.kubernetes.io/region
    • beta.kubernetes.io/os
    • beta.kubernetes.io/arch

    nodeSelector 提供了一种非常简单的方式,从而将Pod约束到具有特定Label的Node。目前处于beta阶段的Affinity/Anti-affinity特性极大地扩展了您可以表达的约束类型。关键的改进是:

    1. 语言更具表现力(不仅仅是“使用AND、完全匹配”)
    2. 可指定“soft”/“preference”规则,而非影响要求,因此如果Scheduler不能满足你的要求,则该Pod仍将被安排
    3. 您可以限制在Node(或其他拓扑域)上运行的其他Pod的标签,而非针对Node本身上的标签,这允许设置规则,指定哪些Pod可以并且不能放到一起。

    Affinity特性由两种affinity组成:“node affinity”和“inter-pod affinity/anti-affinity”。Node affinity类似于现有的节点 nodeSelector (但具有上面列出的前两个优点);而inter-pod affinity/anti-affinity约束Pod的Label而非Node的Label,此特性除具有上面列出的前两项性质之外,还有如上述第三项中所述的性质。

    nodeSelector 继续像往常一样工作,但最终将会被废弃,因为Node Affinity可表示 nodeSelector 所能表达的所有内容。

    目前有两种类型的Node Affinity,称为 requiredDuringSchedulingIgnoredDuringExecution and preferredDuringSchedulingIgnoredDuringExecution 。 您可以将它们分别认为是“hard”和“soft”,前者规定了要将Pod调度到Node上时,必须满足的规则(就像nodeSelector ,但使用更具表现力的语法),而后者指定调度程序将尝试强制调度但不能保证的首选项。 名称中的“IgnoredDuringExecution”部分表示,与 nodeSelector 工作方式类似,如果Node上的Label在运行时更改,导致不再满足Pod上的Affinity规则,则该Pod仍将继续在该Node上运行。在未来,我们计划提供 requiredDuringSchedulingRequiredDuringExecution ,它和 requiredDuringSchedulingIgnoredDuringExecution 一样,只是它会从不再满足Pod的Node Affinity要求的Node中驱逐Pod。

    因此, requiredDuringSchedulingIgnoredDuringExecution 的一个示例是“仅在有Intel CPU的Node上运行Pod”,并且一个preferredDuringSchedulingIgnoredDuringExecution 的一个示例是“尝试在可用区XYZ中运行此组Pod,但如果无法做到,则允许在其他地方运行” 。

    Node Affinity被指定nodeAffinity 字段,它是 PodSpecaffinity 字段的子字段。

    以下是一个使用Node Affinity的Pod的示例:

    该Node Affinity规则表示,该Pod只能放在带有 kubernetes.io/e2e-az-name 的Label的Node上,其值为 e2e-az1e2e-az2 。 另外,在符合该标准的Node中,优先使用具有 another-node-label-key ,值为another-node-label-value 的Node。

    在本例中可以看到 In 操作符。新Node Affinity语法支持以下操作符: InNotIn 、 、DoesNotExistGtLt 。没有明确的“node anti-affinity”概念,但 NotInDoesNotExist 提供了这种行为。

    如果同时指定 nodeSelectornodeAffinity , 则必须同时满足,才能将Pod调度到候选Node上。

    如果指定与 nodeAffinity 类型相关联的多个 nodeSelectorTerms ,那么如果满足 nodeSelectorTerms 之一 ,即可将Pod调度到节点上。

    如果指定与 matchExpressions 相关联的多个 matchExpressions ,则只有满足所有 matchExpressions 才能将该Pod调度到Node上。

    如果删除或更改了调度Pod的Node的Label,则该Pod不会被删除。 换句话说,Affinity选择仅在调度Pod时起作用。

    有关Node Affinity的更多信息,请参见 设计文档

    Kubernetes 1.4引入了Inter-pod affinity 和 anti-affinity。Inter-pod affinity和anti-affinity允许您根据已在Node上运行的Pod 上的Label,而非基于Node的Label来约束您的Pod能被调度到哪些Node。规则的形式是“如果X已经运行了一个或多个满足规则Y的Pod,则该Pod应该(或者在anti-affinity的情况下不应该)运行在X中”。Y表示一个与Namespace列表相关联(或“所有”命名空间)的LabelSelector;与Node不同,因为Pod是在Namespace中的(因此Pod上的Label是隐含Namespace的),Pod Label上的Label Selector必须指定选择器要应用的Namespace。 概念上,X是一个拓扑域,如Node、机架、云提供商Zone、云提供商Region等。您可以使用 topologyKey 表示它,该key是系统用来表示拓扑域的Node标签,例如参见上面 中列出的键。

    与Node Affinity一样,目前有两种类型的pod affinity和anti-affinity,称为 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution ,表示“hard”对“soft”需求。请参阅上文Node Affinity部分中的说明。一个 requiredDuringSchedulingIgnoredDuringExecution 的例子是“将同一个Zone中的Service A和Service B的Pod放到一起,因为它们彼此通信很多”,而 preferredDuringSchedulingIgnoredDuringExecution anti-affinity表示“将该Service的Pod跨Zone“(硬性要求没有意义,因为你可能有比Zone更多的Pod)。

    Inter-pod affinity用 podAffinity 字段指定,它是PodSpec中 affinity 字段的子字段。 inter-pod anti-affinity用 podAntiAffinity 指定,它是 affinity 字段的子字段。

    An example of a pod that uses pod affinity:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: with-pod-affinity
    5. spec:
    6. affinity:
    7. podAffinity:
    8. requiredDuringSchedulingIgnoredDuringExecution:
    9. - labelSelector:
    10. matchExpressions:
    11. - key: security
    12. operator: In
    13. values:
    14. - S1
    15. topologyKey: failure-domain.beta.kubernetes.io/zone
    16. podAntiAffinity:
    17. preferredDuringSchedulingIgnoredDuringExecution:
    18. - weight: 100
    19. podAffinityTerm:
    20. labelSelector:
    21. matchExpressions:
    22. - key: security
    23. operator: In
    24. values:
    25. - S2
    26. containers:
    27. - name: with-pod-affinity
    28. image: gcr.io/google_containers/pause:2.0

    本例中,Pod的Affinity定义了一个Pod Affinity规则和一个Pod anti-affinity规则。 在此示例中, podAffinity 在是requiredDuringSchedulingIgnoredDuringExecution ,而podAntiAffinity 是 。Pod Affinity规则表示,只有当相同Zone中的某个Node至少有一个已经运行的、具有key=security、value=S1的Label的Pod时,该Pod才能调度到Node上。 (更准确地说,Pod会运行在这样的Node N上:Node N具有带有 failure-domain.beta.kubernetes.io/zone 的Label key和某些value V,即:集群中至少有一个带有key= failure-domain.beta.kubernetes.io/zone 以及value=V的Node,其上运行了key=security并且value=S1标签的Pod)。pod anti-affinity规则表示该Pod更倾向于不往那些已经运行着Label key=security且value=S2的Pod的Node上调度。(如果 topologyKeyfailure-domain.beta.kubernetes.io/zone ,那么这意味着如果相同Zone中的Node中有Pod的key=security并且value=S2,则该Pod不能调度到该Node上“)。对于pod affinity以及anti-affinity的更多例子,详见 design doc

    原则上, topologyKey 可以是任何合法的标签key。然而,出于性能和安全的原因,对于topologyKey有一些限制:

    1. 对于Affinity以及 RequiredDuringScheduling pod anti-affinity,,不允许使用空(empty)的 topologyKey
    2. 对于 RequiredDuringScheduling pod anti-affinity,引入了admission controller LimitPodHardAntiAffinityTopology ,从而限制到 kubernetes.io/hostnametopologyKey 。如果要使其可用于自定义拓扑,您可以修改admission controller,或者简单地禁用它。
    3. 对于 PreferredDuringScheduling pod anti-affinity,空(empty) topologyKey kubernetes.io/hostname被解释为“所有拓扑”(“所有拓扑”在这里仅限于 kubernetes.io/hostnamefailure-domain.beta.kubernetes.io/region 的组合)。
    4. 除上述情况外, topologyKey 可以是任何合法的标签key。

    labelSelectortopologyKey 外,还可以选择指定 labelSelector 应该匹配的Namespace列表(这与 labelSelectortopologyKey 的定义相同)。如果省略,默认为:定义affinity/anti-affinity了的Pod的Namespace。 如果定义为空(empty),则表示“所有Namespace”。

    所有与requiredDuringSchedulingIgnoredDuringExecution affinity以及anti-affinity相关联的 matchExpressions 必须满足,才会将Pod调度到Node上。

    More Practical Use-cases(更多实用的用例)

    Interpod Affinity和AnitAffinity在与更高级别的集合(例如ReplicaSets、Statefulsets、Deployments等)一起使用时可能更为有用。可轻松配置工作负载应当统统位于同一个拓扑中,例如,同一个Node。

    Always co-located in the same node(始终位于同一个Node)

    在一个有3个Node的集群中,web应用有诸如redis的缓存。我们希望web服务器尽可能地与缓存共存。这是一个简单的redis Deployment的yaml片段,包含3个副本和选择器标签 app=store

    在webserver Deployment的yaml代码片段下面配置了 podAffinity ,它通知scheduler其所有副本将与具有选择器标签 app=store 的Pod共同定位

    1. apiVersion: apps/v1beta1 # for versions before 1.6.0 use extensions/v1beta1
    2. kind: Deployment
    3. metadata:
    4. name: web-server
    5. spec:
    6. replicas: 3
    7. template:
    8. metadata:
    9. labels:
    10. app: web-store
    11. spec:
    12. affinity:
    13. podAffinity:
    14. requiredDuringSchedulingIgnoredDuringExecution:
    15. - labelSelector:
    16. matchExpressions:
    17. - key: app
    18. operator: In
    19. values:
    20. - store
    21. topologyKey: "kubernetes.io/hostname"
    22. containers:
    23. - name: web-app

    如果我们创建上述两个Deployment,我们的三节点集群可能如下所示。

    如您所见, 3个副本将按预期自动与缓存共同定位。

    最佳实践是配置这些高可用的有状态工作负载,例如有AntiAffinity规则的redis,以保证更好的扩展,我们将在下一节中看到。

    Never co-located in the same node(永远不位于同一个Node)

    高可用数据库StatefulSet有一主三从,可能不希望数据库实例都位于同一Node中。

    node-1 node-2 node-3 node-4
    DB-MASTER DB-REPLICA-1 DB-REPLICA-2 DB-REPLICA-3

    是一个Zookeper StatefulSet的例子,为高可用配置了anti-affinity的。

    有关inter-pod affinity/anti-affinity的更多信息,请参阅 here 的设计文档。

    您也可以检查 ,这样可让Node排斥一组Pod。

    https://kubernetes.io/docs/concepts/configuration/assign-pod-node/