k8s服务调度策略NodeSelector、NodeName与Affinity
Kubernetes中默认的部署方式为根据调度算法分析Kubernetes中资源使用情况,进行动态分配的。有时候调度应用时需要设置应用部署到特定的节点上,或者需要将应用部署多个实例,为了保持高可用需要将应用分配到不同的节点上等等,由于有这些特殊情况就有了Kubernetes的多种调度方式
定向调度策略NodeName与NodeSelector
在Kubernetes中有两种定向调度方式,可以通过配置Kubernetes对象的nodeName和NodeSelector两个参数,来使应用部署到特定的节点上
NodeName方式
参数Pod.spec.nodeName可用于强制约束Pod跳过默认的Kubernetes调度规则,直接调度Pod到指定的Node节点上,下面是调度应用Pod到k8s-node-2节点的示例
[root@k8s01 ~]# vim deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 1
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: tutum/hello-world:latest
ports:
- containerPort: 80
nodeName: k8s-node-2 #指定调度节点为 k8s-node-2
[root@k8s01 ~]# kubectl create -f deploy.yaml
[root@k8s01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-768b645b56-wgqp7 1/1 Running 0 17s 10.244.134.228 k8s-node-2
NodeSelector方式
参数spec.selector.matchLabels可以设置应用启动到带有指定Label的节点上。如果该参数指定有多个标签,那么需要存在带有多个Label标签的节点Pod才能够被调度,否则被标记为无法调度状态。下面介绍下如何设置应用Pod调度到带有A=a标签的节点上,可以按如下配置
设置节点添加对应Label标签
对节点设置 Label 标签:
- 格式: kubectl label nodes <Node名称> <标签Key>=<标签Value>
[root@k8s01 ~]# kubectl label nodes k8s-node-2-12 A=a
查看节点的 Label 标签:
[root@k8s01 ~]# kubectl get nodes --show-labels
设置Deployment对象配置nodeSelector参数
[root@k8s01 ~]# vim deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 1
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: tutum/hello-world:latest
ports:
- containerPort: 80
nodeSelector:
A: a #调度到拥有label为A=a的节点
[root@k8s01 ~]# kubectl create -f deploy.yaml
[root@k8s01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-768b645b56-wgqp7 1/1 Running 0 17s 10.244.134.228 k8s-node-2
亲和性Affinity
Affinity介绍
由于上面 NodeName和NodeSelector两种调度方式过于生硬,不能够灵活配置应用能启动在什么节点不启动在什么节点与配置两个相同的实例启动在不同的节点等等规则。所以 Kubernetes 中还有另一种调度方式,那就是 Affinity 亲和性,这种方式可以非常灵活的配置应用的调度规则
Affinity 可以分为三种类
- NodeAffinity: Node 亲和性
- PodAffinity: Pod 亲和性
- PodAntiAffinity: Pod 反亲和性
亲和性调度可以分成软策略和硬策略两种方式
- preferredDuringSchedulingIgnoredDuringExecution(软策略): 如果没有满足调度要求的节点,Pod就会忽略这条规则,继续完成调度过程,即是满足条件最好,没有满足也无所谓的一种策略
- requiredDuringSchedulingIgnoredDuringExecution(硬策略): 比较强硬,如果没有满足条件的节点的话,就不断重试直到满足条件为止,即是必须满足该要求,不然不调度的策略
参数介绍
调度条件参数:
- nodeSelectorTerms:下面有多个选项的话,满足任何一个条件就可以了
- matchExpressions:有多个选项的话,则必须同时满足这些条件才能正常调度 POD
权重 weight 参数:
- 权重范围为 1-100,权重的值涉及调度器的优选打分过程,每个节点的评分都会加上这个weight,最后绑定最高的节点
拓扑域topologyKey参数及可配置选项:
- topologykey的值表示指作用于topology范围内的node上运行的pod,其值可配置为:
- kubernetes.io/hostname(Node)
- failure-domain.beta.kubernetes.io/zone(Zone)
- failure-domain.beta.kubernetes.io/region(Region)
匹配选项operator可用的选项:
- In: label的值在某个列表中
- NotIn: label的值不在某个列表中
- Gt: label的值大于某个值
- Lt: label的值小于某个值
- Exists: 存在某个label标签
- DoesNotExist: 不存在某个label标签
Node亲和性NodeAffinity
NodeAffinity是用于调度应用时候,会根据NodeAffinity参数去跟Node上的Label进行匹配,如果有符合条件的Node则该应用就可与调度到该节点,其功能跟NodeSelector类似,不过设置的条件比其更灵活。例如下面是设置应用必须运行在amd64的节点中,并且设置尽可能启动到k8s-node-2节点上,可以按如下配置
[root@k8s01 ~]# vim deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 1
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: tutum/hello-world:latest
ports:
- containerPort: 80
affinity:
nodeAffinity: #Node亲和性
requiredDuringSchedulingIgnoredDuringExecution: #硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
preferredDuringSchedulingIgnoredDuringExecution: #软策略
- weight: 100 #权重,取值范围为 1-100
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node-2
[root@k8s01 ~]# kubectl create -f deploy.yaml
[root@k8s01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-768b645b56-wgqp7 1/1 Running 0 17s 10.244.134.228 k8s-node-2
NodeAffinity规则设置的注意事项如下:
- 如果nodeAffinity指定了多个nodeSelectorTerms,那么其中任意一个能够匹配成功即可
- 如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能最终运行在指定的Node 上
- 如果在nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有matchExpressions才能运行该 Pod
Pod反亲和性PodAntiAffinity
Pod反亲和性主要是解决Pod不能和哪些Pod部署在同一个拓扑域中的问题,是用于处理Pod之间的关系。比如一个Pod被调度到某一个节点上,新起的Pod不想和这个Pod调度到一起,就可以使用Pod的反亲和性podAntiAffinity。例如设置应用启动在不同节点上,可以按如下配置:
[root@k8s01 ~]# vim deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
labels:
app: hello
spec:
replicas: 2
selector:
matchLabels:
app: hello
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: tutum/hello-world:latest
ports:
- containerPort: 80
affinity:
podAntiAffinity: #Pod反亲和性
requiredDuringSchedulingIgnoredDuringExecution: #硬策略
- topologyKey: kubernetes.io/hostname
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- hello
[root@k8s01 ~]# kubectl create -f deploy.yaml
[root@k8s01 ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
hello-768b645b56-wgqp7 1/1 Running 0 17s 10.244.134.228 k8s-node-2
hello-768b645b56-x67d 1/1 Running 0 17s 10.244.28.278 k8s-node-3