Assigning Pods to Nodes
可以限制Pods在特定节点上运行,也可以优先调度到特定节点。有几种方式可以实现这个功能,它们都使用选择标签的方式完成。通常情况下这些限制是没必要的,k8s会自动实现合理的调度(例如,pods在集群中调度时,不会被调度到资源不足的节点上)。但是,有些场景下,希望对运行pod的节点进行限制,如需要将pod调度到磁盘为SSD的节点上,或将两个不同的服务但需要经常通信的pod调度到同一个zone。
1.nodeSelector
nodeSelector是最简单的一种实现方式,是podSpec的一个字段,它指定了一个key-value的键值对。为了使pods能够在该节点上运行,该节点必须有所有需要的键值对作为标签(节点也可以有其它的标签)。
第一步:节点打标签
#语法
kubectl label nodes =
#示例,如果节点名称是harmonycloud,需要添加‘disktype=ssd’标签
kubectl lable nodes harmonycloud disktype=ssd
# 验证,使用如下命令查看是否成功给node添加标签
kubectl get nodes --show-labels
第二步:配置文件中添加nodeSelector 字段
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector: #Add this field
disktype: ssd
第三步:验证
#运行以下命令,创建pod
kubectl create -f pod.yaml
#查看pod运行节点
kubectl get pods -o wide
2. Affinity and anti-affinity
nodeSelector 提供了一种简单的方式将pods调度到具有特定标签的节点上。
Affinity and anti-affinity 现在是beta版,大大拓展了可以表达的约束类型。相对于nodeSelector主要有以下几个优点:
- 语法更具表现力(不仅仅支持“与(AND)”完全匹配)
- 可以指明规则是“soft/preference”而不是强制要求,所以如果不满足调度条件,pods依然可以被调度。
- 可以将规则限制在运行在一个节点上的pods(或其他拓扑域),而不仅仅是节点本身,这将允许pods是否可以调度到同一个节点。
Affinity特征有两种类型,“node affinit” 和 “inter-pod affinity/anti-affinity”。 Node affinity跟nodeSelector很像,但有以上两个优点。inter-pod affinity/anti-affinity是对pod的标签进行限制,具有以上三条特性。
nodeSelector可以正常工作,最终将会被弃用,因为node affinity可以表示它可以表示的所有内容。
2.1 Node affinity(beta)
Kubernetes 1.2中,node affinity是alpha版。 Node affinity概念上与nodeSelector相似,通过选择标签的方式,可以限制pod被调度到特定的节点上。
目前支持两种类型的node affinity,requiredDuringSchedulingIgnoredDuringExecution 和preferredDuringSchedulingIgnoredDuringExecution,可以他们看作“hard(强制)”和“soft(非强制)”。某种意义上,前者指定了要将pod调度到节点上必须满足的规则(像nodeSelector,但使用了更具表现力的语法),而后者试图调度到特定的节点但不能保证一定会调度到该节点。其中,“IgnoredDuringExecution”表示如果在pod运行时节点的标签发生改变导致无法满足pods创建时使用的调度规则,pod会继续在该节点上运行,这点与nodeSelector相似。将来会提供requiredDuringSchedulingRequiredDuringExecution,与requiredDuringSchedulingIgnoredDuringExecution一样,但是会迁移节点上的pod以满足其node affinity 的规则。
下面有一个使用node affinity的例子:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: gcr.io/google_containers/pause:2.0
这条规则表示,pod可以被调度到key为“kubernetes.io/e2e-az-name”,值为“e2e-az1”或“e2e-az2”的节点。另外,在满足该条件的节点中,优先使用具有“another-node-label-key”标签,且至为“another-node-label-value”的节点。
上面的例子使用了“In”操作符,node affinity语法支持以下集中操作符:In, NotIn, Exists, DoesNotExist,Gt,Lt。没有明确的“node anti-affinity”概念,但是NotIn和DoesNotExist可以表示该含义。
如果同时指定了nodeSelector和nodeAffinity,要调度的节点必须同时满足这两点规则。
如果指定了与多条与nodeSelector相关的表达式,pod将会被调度到同时满足这几条表达式的节点。
2.2 Inter-pod affinity and anti-affinity(beat)
Kubernetes 1.4中提出了inter-pod和anti-affinity的概念。inter-pod affinity和anti-affinity允许根据已在节点上运行的pod上的标签来限制pod可以调度到哪些节点,而不是基于节点上的标签。
规则的形式是,pod应该(anti-affinity表示不应该)运行在X中,如果X已经运行了一个或多个满足规则Y的pod。Y表示为LabelSelector具有相关namespace的列表(或所有namespace)。与节点不同,pod是属于不同namespace的(因此pod上的标签是隐含的namespace),pod 标签上的label selector必须制定该selector应用到哪个namespace。从概念上来说,X是一个拓扑域,如节点,机架,云提供商域等。
如node affinity,目前支持两种类型的pod affinity和anti-affinity:requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution, requiredDuringSchedulingIgnoredDuringExecution会将service A和service B的pod调度到同一个zone,因为他们彼此通信很多;preferredDuringSchedulingIgnoredDuringExecution,anti-affinity会把同一个service的pods调度到不同的zone(强制要求是没有意义的,因为pod的数量要大于zone)。
下面有一个使用pod affinity的例子:
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: gcr.io/google_containers/pause:2.0
这个例子中定义了affinity和anti-affinity规则。podAffinity是requiredDuringSchedulingIgnoredDuringExecution,podAntiaffinity是preferredDuringSchedulingIgnoredDuringExecution。pod affinity 规则表示,该pod只能运行在集群中的特定节点上,这些节点已经至少运行一个具有”security=S1“标签的pod,并且和这些节点在同一个zone(更确切的说,这个pod可以运行在节点N上,如果节点N有key为failure-domain.beta.kubernetes.io/zone和值为V的标签,同时该节点上运行着一个具有“security=S1”标签的pod)。pod anti-affinity规则表示,如果该节点已经运行着具有“security=S2”标签的pod,将不会优先调度到该节点。(如果topologyKey是failure-domain.beta.kubernetes.io/zone,该pod也不会被优先调度到具有“security=S2”标签的节点所在的zone)。
和node affinity 一样,pod affinity 合法的操作符有In, NotIn, Exists, DoesNotExist, Gt, Lt。
原则上,topologyKey可以是任意标签,为了性能考虑只允许一些有限的topologyKey,默认情况下,有以下几个:
- kubernetes.io/hostname
- failure-domain.beta.kubernetes.io/zone
- failure-domain.beta.kubernetes.io/region
除了labelSelector和topologyKey,也可以选择性的指定一些labelSelector需要匹配的namespace。如果忽略namespace,默认匹配affinity/anti-affinity定义的规则指定的namespace。如果定义了namespace,意味着所有namespace都可以。
必须满足所有与requiredDuringSchedulingIgnoredDuringExecution 相关的表达式才能将pod调度到某个节点。
3. 设计文档
node affinity/anti-affinity 设计文档
inter-pod affinity/anti-affinity设计文档