天天看点

运维实战 容器部分 Kubernetes调度需求简介具体调度方法Taints

运维实战 容器部分 Kubernetes调度

  • 需求简介
  • 具体调度方法
    • nodeName
    • nodeSelector
    • 亲和与反亲和
      • 节点亲和
      • Pod亲和
  • Taints
    • Taints设置的取值
    • Tolerations相关设置

需求简介

  • 生产环境有对

    Pod

    调度规划的真实需求, 比如端口冲突的业务不能部署在同一物理机如何实现, 比如某些业务尽可能部署在同一物理机如何实现
  • 调度器通过

    K8S

    watch

    机制来发现集群中新创建且尚未被调度到

    Node

    上的

    Pod

    . 调度器会将发现的每一个未调度的

    Pod

    调度到一个合适的

    Node

    上来运行.
  • 集群默认使用

    kube-scheduler

    作为调度器, 可以自行编写调度组件替换原有的

    kube-scheduler

  • 也可以在资源清单中指定使用的调度策略
  • 做调度分配时需要考虑许多要素, 如: 单独和整体的资源请求, 硬件/软件/策略限制, 亲和以及反亲和要求, 数据局限性, 负载间的干扰等等

具体调度方法

nodeName

  • nodeName

    是最简单的节点约束方法, 通常来说不推荐使用
  • 通过在资源清单中指定

    Node

    ,

    Pod

    会被自动部署到该

    Node

    上, 但如果

    Node

    不存在, 集群也会尝试这么做, 因而导致

    Pending

局限性

  • 指定的节点不存在时不会只能解决
  • 节点存在, 但不满足物理需求(如资源/空间不足), 调度也会失败
  • 在生产环境中

    Node

    的名称并不总是稳定/可预测的
  • nodeName.yaml

    文件内容
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: server3
           
  • 测试结果
[[email protected] Schedule]# kubectl apply -f nodeName.yaml 
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          10s   10.244.141.226   server3   <none>           <none>
           
  • 如果集群中没有符合条件的

    Node

    , 比如上面的

    server3

    改成

    server10

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: server10
           
  • 则会出现调度失败, 并不会只能解决
  • 因为集群中不存在

    server10

    而你又要求调度到

    server10

    上, 就会一直

    Pending

[[email protected] Schedule]# kubectl delete Pod nginx 
Pod "nginx" deleted
[[email protected] Schedule]# kubectl get Pod -o wide
No resources found in default namespace.
[[email protected] Schedule]# kubectl apply -f nodeName.yaml 
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP       NODE       NOMINATED NODE   READINESS GATES
nginx   0/1     Pending   0          1s    <none>   server10   <none>           <none>
           

nodeSelector

想必你也注意到了,

nodeName

并不能指定一类机器, 而只能指定固定机器

如果我们想定义一类具有同样特点的机器, 如这些机器都使用固态硬盘, 可以通过对节点打

tag

的方式来实现

与之对应,

nodeSelector

是通过

tag

进行调度筛选的机制, 也是节点选择约束的最简单推荐形式

  • nodeSelector.yaml

    文件内容
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
           
  • 测试流程
[[email protected] Schedule]# kubectl apply -f nodeSelector.yaml 
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
nginx   0/1     Pending   0          9s    <none>   <none>   <none>           <none>
           
  • 此时, 所有结点上都没有

    disktype: ssd

    标签所以

    Pending

  • server3

    附加

    disktype=ssd

    的标签后, 调度正确实现
[[email protected] Schedule]# kubectl label nodes server3 disktype=ssd
node/server3 labeled
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          67s   10.244.141.227   server3   <none>           <none>
           

亲和与反亲和

  • 实现了 “硬要求” 和 “软需求” 并存, 如"必须满足A, 尽量满足B(B不满足也可以)"这类需求, 这极大扩展了表达约束的类型
  • 亲和和反亲和不止支持节点标签, 也支持

    Pod

    标签, 如

    B服务

    只能放在

    A服务

    不存在的

    Node

    上这种需求

节点亲和

参数 含义
requiredDuringSchedulingIgnoredDuringExecution 必须满足
preferredDuringSchedulingIgnoredDuringExecution 倾向满足

虽然这个参数很长, 但实际上是由两部分构成的, 前半部分表示

软/硬

后半部分的

IgnoreDuringExecution

表示如果在

Pod

运行期间

Node

的标签发生变化, 导致亲和性策略不能满足, 则继续运行当前的

Pod

, 而不直接驱离

nodeaffinity

还支持多种规则匹配条件的配置

参数 含义
In

label

的值在列表内
NotIn

label

的值不在列表内
Gt

label

的值大于设置的值, 不支持

Pod

亲和性
Lt

label

的值小于设置的值, 不支持

Pod

亲和性
Exists 设置的

label

存在
DoesNotExist 设置的

label

不存在
  • 测试用

    node-affinity.yaml

    文件内容
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: disktype
               operator: In
               values:
                 - ssd
           
  • 这里的需求是 满足

    disktype=ssd

    的节点,

    key

    +

    operator

    +

    values

    共同完成了这一指名
  • 测试流程, 可以看到测试用的

    node-affinity

    被调度到了

    server3

[[email protected] Schedule]# kubectl apply -f nodeAffinity_required.yaml 
Pod/node-affinity created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATES
node-affinity   1/1     Running   0          5s    10.244.141.228   server3   <none>           <none>
           

倾向满足

的案例

apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  containers:
  - name: nginx
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: kubernetes.io/hostname
               operator: NotIn
               values:
               - server3
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd     
           

在这个资源清单中存在两条要求:

  • 必须满足 不能调度到

    server3

  • 倾向满足

    Node

    包含

    disktype=ssd

    tag

这样, 即使

server4

上并没有这个

tag

, 也可以调度到

server4

上了

Pod亲和

  • PodAffinity

    主要解决

    Pod

    可以和哪些

    Pod

    部署在同一个拓扑域中的问题(拓扑域用主机标签实现, 可以是单个主机, 也可以是多个主机组成的

    cluster

    ,

    zone

    等.) 与之效能相反的

    PodAntiAffinity

    主要解决

    Pod

    不能和哪些

    Pod

    部署在同一个拓扑域中的问题. 它们处理的是

    Kubernetes

    集群内部

    Pod

    Pod

    之间的关系.
  • Pod

    间亲和与反亲和在与更高级别的集合(例如

    ReplicaSets

    ,

    StatefulSets

    ,

    Deployments

    等)一起使用时, 它们可能更加有用. 可以轻松配置一组应位于相同定义拓扑(例如, 节点)中的工作负载.
  • Pod

    间亲和与反亲和需要大量的处理, 这可能会显著减慢大规模集群中的调度. \

测试样例

  • 创建一个自主的包含

    nginx

    服务的

    Pod

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx
           
  • 创建一个包含

    Pod

    亲和需求的资源清单
apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  containers:
  - name: mysql
    image: mysql
    env:
     - name: "MYSQL_ROOT_PASSWORD"
       value: "westos"
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname
           
[[email protected] Schedule]# kubectl apply -f nodeName.yaml
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATESnginx   1/1     Running   0          11s   10.244.141.230   server3   <none>           <none>

[[email protected] Schedule]# kubectl apply -f PodAffinity.yaml
Pod/demo created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP               NODE      NOMINATED NODE   READINESS GATESdemo    1/1     Running   0          6s    10.244.22.25     server4   <none>           <none> nginx   
 1/1     Running   0          54s   10.244.141.230   server3   <none>           <none>
           

可以看到, 两个

Pod

分别被调度到了2个不同的

Node

Taints

NodeAffinity

节点亲和性的目的是让

Pod

可以按照我们的需求调度到一个或一类

Node

上;

Taints

与之相反, 它能让

Node

拒绝运行

Pod

, 甚至驱离已经在该

Node

上运行的

Pod

Taints

(污点)是

Node

的一个属性, 设置了

Taints

后,

K8S

集群就不会把

Pod

调度到这个

Node

上了

如果想让

Pod

调度到有

Taints

的节点, 就需要给

Pod

设置

Tolerations

(容忍)属性

主节点上天生具有

Taints

, 因此才有了默认不会调度到主节点上的说法

  • 相关命令
##为node1增加一个NoSchedule(不允许调度)的污点
kubectl taint nodes node1 key=value:NoSchedule

##查询server1上的污点情况
kubectl describe nodes  server1 |grep Taints

##删除node1上的NoSchedule(不允许调度)污点属性
$ kubectl taint nodes node1 key:NoSchedule-
           
  • 一个标准的

    Deployment

    控制器部署

    nginx

    的清单
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
           
  • 主节点默认不允许调度
[[email protected] Schedule]# kubectl describe nodes  server2 |grep TaintsTaints:
node-role.kubernetes.io/master:NoSchedule
           
  • 为Server4增加驱离属性
[[email protected] Schedule]# kubectl taint node server4 key1=v1:NoExecute
node/server4 tainted
[[email protected] Schedule]# kubectl get Pod -o wide
           
  • 如果设置正确, 你将只会在

    server3

    上看到

    Pod

    , 因为

    server2

    server4

    都不能用于部署
  • 增加容忍设置的版本
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
      tolerations:
      - key: "key1"
        operator: "Equal"
        value: "v1"
        effect: "NoExecute"
           

Taints设置的取值

参数 含义
NoSchedule 不会被调度到标记节点
PreferNoSchedule NoSchedule 的软策略版本
NoExecute 不会调度到标记节点, 并且该节点内的

Pod

如无对应的

Tolerate

设置还会被驱逐

Tolerations相关设置

Tolerations

中定义的

key

,

value

,

effect

, 要与

node

上设置的

taint

保持一致, 但并不是都要填写

  • operator

    Exists

    时, 可以省略

    value

  • operator

    Equal

    时,

    key

    value

    之间的关系必须相等
  • 如果不指定

    operator

    属性, 则默认值为

    Equal

  • 当不指定

    key

    , 再配合

    Exists

    就能匹配所有的

    key

    value

    , 可以容忍所有污点
  • 当不指定

    effect

    , 则匹配所有的

    effect

tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"
对满足key=value 且污点策略为NoSchedule的节点进行容忍

tolerations:
  - operator: "Exists"
    effect: "NoSchedule"
容忍所有污点并不驱离
           

继续阅读