1、 NodeSelector:如果需要限制Pod到指定的Node
上运行,则可以给Node打标签并给Pod配置NodeSelector。
2、NodeAffinity节点亲和性,是Pod上定义的一种属性,使Pod能够按我们的要求调度到某个Node上,而Taints则恰恰相反,它可以让Node拒绝运行Pod,甚至驱逐Pod。Taints(污点)是Node的一个属性,设置了Taints(污点)后,因为有了污点,所以Kubernetes是不会将Pod调度到这个Node上的,于是Kubernetes就给Pod设置了个属性Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。因此 Taints(污点)通常与Tolerations(容忍)配合使用。Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,Taint应用于Node上,而toleration则应用于Pod上(Toleration是可选的)
3、 Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
2.1 给节点打标签
# get node的name
$ kubectl get nodes
# 设置Label
$ kubectl label nodes =
# 例如
$ kubectl label nodes node1 disktype=ssd
# 查看Node的Label
$ kubectl get nodes --show-labels
# 删除Node的label
$ kubectl label node -
2.2 给Pod设置NodeSelector
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd # 对应Node的Label
Tips:
hem chart设置NodeSelector案例
$ helm create test-chart && cd test-chart
$ helm install . --set nodeSelector.databases=mysql
# 注意lable中有.的情况
$ helm install --name elasticsearch elastic/elasticsearch --set nodeSelector."beta\\.kubernetes\\.io/os"=linux
3.1 实验环境
实验环境是三节点的集群,采用kubeadm部署,部署请参考我的另一篇文章
3.2 实验流程
1、给节点打上污点
node打上污点(可以想象成一个标签),pod如果不定义容忍这个污点,那么pod就不会被调度器分配到这个node
匹配规则:
一个 toleration 和一个 taint 相“匹配”是指它们有一样的 key 和 effect ,并且:
如果 operator
是 Exists
(此时 toleration 不能指定 value
)
如果 operator
是 Equal
,则它们的 value
应该相等
特殊情况:
如果一个 toleration 的 key
为空且 operator 为 Exists
,表示这个 toleration 与任意的 key 、 value 和 effect 都匹配,即这个 toleration 能容忍任意 taint。
tolerations:
- operator: "Exists"
如果一个 toleration 的 effect
为空,则 key
值与之相同的相匹配 taint 的 effect
可以是任意值。
tolerations:
- key: "key"
operator: "Exists"
一个节点可以设置多个taint,一个pod也可以设置多个toleration。Kubernetes 处理多个 taint 和 toleration 的过程就像一个过滤器:从一个节点的所有 taint 开始遍历,过滤掉那些 pod 中存在与之相匹配的 toleration 的 taint。余下未被过滤的 taint 的 effect 值决定了 pod 是否会被分配到该节点,特别是以下情况:
NoSchedule
的 taint,则 Kubernetes 不会将 pod 分配到该节点。NoSchedule
的 taint,但是存在 effect 值为 PreferNoSchedule
的 taint,则 Kubernetes 会尝试将 pod 分配到该节点。NoExecute
的 taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)。目前支持的 taint 类型(也被称为effect):
NoSchedule:K8S的node添加这个effect类型污点,新的不能容忍的pod不能再调度过来,但是老的运行在node上不受影响
NoExecute:K8S的node添加这个effect类型污点,新的不能容忍的pod不能调度过来,老的pod也会被驱逐
PreferNoSchedule:尽量不要调度到该节点,但pod会尝试将pod分配到该节点
effect 值 NoExecute
,它会影响已经在节点上运行的 pod,即根据策略对Pod进行驱逐。
NoExecute
的 taint,那么 pod 将马上被驱逐NoExecute
的 taint,但是在 toleration 定义中没有指定 tolerationSeconds
,则 pod 还会一直在这个节点上运行。NoExecute
的 taint,而且指定了 tolerationSeconds
,则 pod 还能在这个节点上继续运行这个指定的时间长度。# 查询节点名字
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready master 28d v1.15.4
node2 Ready 28d v1.15.4
node3 Ready 28d v1.15.4
# 给node1节点打上key值为project,value值为ops,驱逐模式为NoSchedule
$ kubectl taint node node1 project=ops:NoSchedule
# 给node2节点打上key值为project,value值为ops,驱逐模式为NoSchedule
$ kubectl taint node node2 project=ops:NoSchedule
# 给node3节点打上key值为project,value值为ops,驱逐模式为NoSchedule
$ kubectl taint node node3 project=ops:NoSchedule
2、deployment设置容忍
apiVersion: apps/v1Beta1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
images: nginx:laste
ports:
- containerPort: 80
tolerations:
- key: "project"
operator: "Equal"
value: "ops"
effect: "NoSchedule"
可以看到 如果pod打上这个污点,那么这个pod就会分配到这个node1,其他pod未打污点无法分配,并且old的pod也被驱赶出这个node。
有时候在master节点上也安装了docker,但是又不想让master既作为主节点又做为node节点,避免让pod调度到master上,方法如下:
# master节点名称为node1
$ kubectl taint node node1 node-role.kubernetes.io/master=node1:NoSchedule
3、删除污点
# kubectl taint node {节点名字} {污点key}-
$ kubectl taint node node1 project-
$ kubectl taint node node2 project-
$ kubectl taint node node3 project-
Affinity 翻译成中文是“亲和性”,它对应的是 Anti-Affinity,我们翻译成“互斥”。这两个词比较形象,可以把 pod 选择 node 的过程类比成磁铁的吸引和互斥,不同的是除了简单的正负极之外,pod 和 node 的吸引和互斥是可以灵活配置的。
Affinity的优点:
目前主要的node affinity:
requiredDuringSchedulingIgnoredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中IgnoreDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,pod也会继续运行。
requiredDuringSchedulingRequiredDuringExecution
表示pod必须部署到满足条件的节点上,如果没有满足条件的节点,就不停重试。其中RequiredDuringExecution表示pod部署之后运行的时候,如果节点标签发生了变化,不再满足pod指定的条件,则重新选择符合要求的节点。
preferredDuringSchedulingIgnoredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。
preferredDuringSchedulingRequiredDuringExecution
表示优先部署到满足条件的节点上,如果没有满足条件的节点,就忽略这些条件,按照正常逻辑部署。其中RequiredDuringExecution表示如果后面节点标签发生了变化,满足了条件,则重新调度到满足条件的节点。
软策略和硬策略的区分是有用处的,硬策略适用于 pod 必须运行在某种节点,否则会出现问题的情况,比如集群中节点的架构不同,而运行的服务必须依赖某种架构提供的功能;软策略不同,它适用于满不满足条件都能工作,但是满足条件更好的情况,比如服务最好运行在某个区域,减少网络传输等。这种区分是用户的具体需求决定的,并没有绝对的技术依赖。
下面是一个官方的示例:
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 同时定义了 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 两种 nodeAffinity。第一个要求 pod 运行在特定 AZ 的节点上,第二个希望节点最好有对应的 another-node-label-key:another-node-label-value 标签。
这里的匹配逻辑是label在某个列表中,可选的操作符有:
如果nodeAffinity中nodeSelector有多个选项,节点满足任何一个条件即可;如果matchExpressions有多个选项,则节点必须同时满足这些选项才能运行pod 。
需要说明的是,node并没有anti-affinity这种东西,因为NotIn和DoesNotExist能提供类似的功能。