一、前言

     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 的吸引和互斥是可以灵活配置的。

二、NodeSelector

2.1 给节点打标签

# get node的name
$ kubectl get nodes

# 设置Label
$ kubectl label nodes <node-name> <label-key>=<label-value>
# 例如
$ kubectl label nodes node1 disktype=ssd

# 查看Node的Label
$ kubectl get nodes --show-labels

# 删除Node的label
$ kubectl label node <node-name> <label-key>-

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

 

三、Taint

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 是否会被分配到该节点,特别是以下情况:

  • 如果未被过滤的 taint 中存在一个以上 effect 值为 NoSchedule 的 taint,则 Kubernetes 不会将 pod 分配到该节点。
  • 如果未被过滤的 taint 中不存在 effect 值为 NoSchedule 的 taint,但是存在 effect 值为 PreferNoSchedule 的 taint,则 Kubernetes 会尝试将 pod 分配到该节点。
  • 如果未被过滤的 taint 中存在一个以上 effect 值为 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进行驱逐。

  • 如果 pod 不能忍受effect 值为 NoExecute 的 taint,那么 pod 将马上被驱逐
  • 如果 pod 能够忍受effect 值为 NoExecute 的 taint,但是在 toleration 定义中没有指定 tolerationSeconds,则 pod 还会一直在这个节点上运行。
  • 如果 pod 能够忍受effect 值为 NoExecute 的 taint,而且指定了 tolerationSeconds,则 pod 还能在这个节点上继续运行这个指定的时间长度。
# 查询节点名字
$ kubectl get nodes
NAME    STATUS   ROLES    AGE   VERSION
node1   Ready    master   28d   v1.15.4
node2   Ready    <none>   28d   v1.15.4
node3   Ready    <none>   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的优点:

  • 匹配有更多的逻辑组合,不只是字符串的完全相等
  • 调度分成软策略(soft)和硬策略(hard),在软策略下,如果没有满足调度条件的节点,pod会忽略这条规则,继续完成调度。

目前主要的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在某个列表中,可选的操作符有:

  • In: label的值在某个列表中
  • NotIn:label的值不在某个列表中
  • Exists:某个label存在
  • DoesNotExist:某个label不存在
  • Gt:label的值大于某个值(字符串比较)
  • Lt:label的值小于某个值(字符串比较)

如果nodeAffinity中nodeSelector有多个选项,节点满足任何一个条件即可;如果matchExpressions有多个选项,则节点必须同时满足这些选项才能运行pod 。

需要说明的是,node并没有anti-affinity这种东西,因为NotIn和DoesNotExist能提供类似的功能。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐