k8s---pod的调度亲和性和污点容忍、指定调度节点(nodeSelector)
在k8s集群建设过程中,一般情况下我们部署的 Pod 是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均。但是有的时候我们需要能够更加细粒度的去控制 Pod 的调度;有时我们希望对内和对外的两类业务分别跑在不同的节点上,相互有依赖的两个pod跑在同一节点上,等情况;这就需要我们更好的控制pod的部署;k8s给我们提供了亲和性和反亲和性,污点(taint)和Toleration(容忍)等概念。
#示例
[root@k8s-master ~]# kubectl explain pod.spec.affinity
KIND: Pod
VERSION: v1
RESOURCE: affinity <Object>
DESCRIPTION:
If specified, the pod's scheduling constraints
Affinity is a group of affinity scheduling rules.
FIELDS:
nodeAffinity <Object>----------------#node亲和性
Describes node affinity scheduling rules for the pod.
podAffinity <Object>----------------#pod亲和性
Describes pod affinity scheduling rules (e.g. co-locate this pod in the
same node, zone, etc. as some other pod(s)).
podAntiAffinity <Object>--------#pod反亲和性
Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod
in the same node, zone, etc. as some other pod(s)).
节点node亲和性
目前主要的node affinity:
requiredDuringSchedulingIgnoredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
requiredDuringSchedulingRequiredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
preferredDuringSchedulingIgnoredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
preferredDuringSchedulingRequiredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点。
举例说明
pod.spec.affinity.nodeAffinity
- preferredDuringScheculingIgnoredDuringExecution:软策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
requiredDuringSchedulingIgnoredDuringExecution:硬策略
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key:kubernetes.io/hostname
operator:NotIn
values:
- k8s-node01
preferredDuringScheculingIgnoredDuringExecution:软策略
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
preferredDuringScheculingIgnoredDuringExecution:
- weitht:1
preference:
matchExpressions:
- key:source
operator:In
values:
- hahaha
硬策略和软策略一起用
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key:kubernetes.io/hostname
operator:NotIn
values:
- k8s-node01
preferredDuringScheculingIgnoredDuringExecution:
- weitht:1
preference:
matchExpressions:
- key:source
operator:In
values:
- hahaha
键值运算关系
运算符 | 作用 |
---|---|
In | lable的值在某个列表中 |
NotIn | label的值不在某个列表中 |
Gt | label的值大于某个值 |
Lt | label的值小于某个值 |
Exists | 某个label存在 |
DoesNotExist | 某个label不存在 |
Pod亲和性
podAffinity规则
pod affinity 可以这样理解:调度的时候选择(或者不选择)这样的节点 N ,这些节点上已经运行了满足条件 X。条件 X 是一组 label 选择器,它必须指明作用的 namespace(也可以作用于所有的 namespace),因为 pod 是运行在某个 namespace 中的。
这里的X指的是集群中的节点、机架、区域等概念,通过kubernetes内置节点标签中的key来进行声明。这个key的名字为topologyKey,意为表达节点所属的topology范围:
- kubernetes.io/hostname
- failure-domain.beta.kubernetes.io/zone
- failure-domain.beta.kubernetes.io/region
要使用亲和性,在 affinity 下面添加 podAffinity 字段,
要使用互斥性,在 affinity 下面添加 podAntiAffinity 字段,
requiredDuringSchedulingIgnoredDuringExecution,
preferredDuringSchedulingIgnoredDuringExecution,
requiredDuringSchedulingRequiredDuringExecution,
preferredDuringSchedulingRequiredDuringExecution,
意义和nodeAffinity一样。
举例说明
pod.spec.affinity.podAffinity/podAntiAffinity
- preferredDuringSchedulingIgnoredDuringExecution: 软策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
apiVersion:v1
kind:Pod
metadata:
name:pod-3
labels:
app:pod-3
spec:
containers:
- name:pod-3
inamge:nginx:v1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key:app
operator:In
values:
- pod-1
topologyKey:kubernetes.io/hostname
污点配合容忍度(Taint和toleration)
节点亲和性,是pod的一种属性(偏好或硬性要求),它使得pod被吸引到一类特定的节点上。Taint则相反,它使得节点能够排斥一类特定的pod
Taint和toleration(容忍)相互配合,可以用来避免pod被分配到不合适的节点上。每个节点上都可以应用一个或多个taint,这表示这些pod可以(但不要求)被调度到具有匹配taint的节点上。
污点
污点的组成
使用kubectl taint 命令可以给节点node设置污点,node被设置污点后,可以让node拒绝pod的调度执行,甚至可以将本node上已经运行的pod驱逐出去。
任何符合其键值规范要求的字符串均可用于定义污点信息:仅可使用字母、数字、连接符、点号和下划线,且仅能以字母或数字开头,其中键名的长度上限为253个字符,值最长为63个字符。实践中,污点通常用于描述具体的部署规划,它们的键名形如node-tppe、node-role、node-project或node-geo等,因此还可在必要时带上域名以描述其额外的信息,如node-type.linux.io等
通过kubectl查看污点,Taints字段
kubectl describe nodes k8s-master-01
Name: k8s-master-01
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=k8s-master-01
kubernetes.io/os=linux
node-role.kubernetes.io/master=
......
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前taint effect支持如下三种选项
effect类别 | 作用 |
---|---|
NoSchedule | 表示k8s不会将pod调度到具有该污点的Node上 |
PreferNotSchedule | 表示k8s将尽量避免将pod调度到具有该污点的node上 |
NotExecute | 表示k8s将不会将pod调度到具有该污点的node上,同时node上已经存在的pod将驱逐出去 |
污点的设置与去除
#设置污点
kubectl taint nodes <node-name> <key>=<value>:<effect>
#kubectl taint nodes node02 node-type=production:NoSchedule
node "node02" tainted
#去除污点(在添加污点的命令后面加"-")
kubectl taint nodes node02 key=value:NoSchedule-
#查询污点,通过kubectl查看节点说明中的Taints字段
kubectl describe nodes k8s-master-01
Name: k8s-master-01
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=k8s-master-01
kubernetes.io/os=linux
node-role.kubernetes.io/master=
......
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
容忍(Tolerations)
设置了污点的Node将根据taint的effect和pod之间产生互斥关系,pod将在一定程度上不会被调度到该Node上。但是我们可以在pod上设置容忍(Toleration),意思是设置了容忍的pod将可以容忍污点存在,可以被调度到存在污点的node上
举例说明
pod.spec.tolerations
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
#主要有两种可用的形式:一种是与污点信息完全匹配的等值关系;另一种是判断污点信息存在性的匹配方式。
#如果operator是Exists 污点存在性匹配容忍,可以忽略value值;
#如果operator是Equal,污点等值关系匹配容忍,它们的key、value、effect要与node上设置的taint一致。
#tolerationSeconds用于描述pod需要被驱逐时,可以在pod上继续保留运行的时间
#当不指定key值时,表示容忍所有的污点key
tolerations:
- operator:"Exists"
#当不指定effect值时,表示容忍所有的污点effect
tolerations:
- key:"key1"
operator:"Exists"
指定调度节点
pod.spec.nodeName将pod直接调度到指定的node节点上,会跳过scheduler的调度策略,该匹配规则时强制匹配
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:web
spec:
replicas:5
template:
metadata:
labels:
app:web
spec:
nodeName:k8s-node01
containers:
- name:web
image:nginx:v1
ports:
- containerPort:80
pod.spec.nodeSelector:通过kubernetes的label-selector机制选择节点,有调度器策略匹配label,而后调度pod到目标节点,该匹配为强制约束
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:web
spec:
replicas:2
template:
metadata:
labels:
app:web
spec:
nodeSelector:
node-key:node-value
containers:
- name:web
image:nginx:v1
ports:
- containerPort:80
使用kubectl label nodes
[root@k8s-master ~]# kubectl label nodes k8s-master role=master
node/k8s-master labeled
使用kubectl get nodes --show-labels 查询nodes的label
[root@k8s-master ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane,master 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,role=master
k8s-node1 Ready <none> 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux