kubernetes 亲和性调度详解

概述:

默认情况下创建pod调度是根据kubernetes scheduler默认的调度规则去进行调度的,但有些时候,有些应用有一些特殊的需求比如指定部署到对应的节点、多个pod之间需要部署在不同一个节点,需要互斥、pod和pod间相互交流比较频繁需要跑在同一个节点,需要亲和。这时就需要灵活配置scheduler来实现了。

场景一:调度到一组具有相同特性的主机上(label+nodeSelector)

比如在整个kubernetes集群内,有一组配置比较好的服务器,然后有一些特殊的应用需要对硬件配置有需求,需要被调度到这些服务器上,这时可以通过kubernetes的label+nodeSelector去实现,实际上在kubernetes里面label是一个非常灵活的概念,kubernetes内不同资源对象之间的关联就是通过label的方式去进行的。

我们给那些配置高的节点打上个label

给高配置的host打上一个label Configuration=hight(这里以rke-node2为例)

kubectl label node rke-node2 Configuration=hight

在show labels可以看见我们刚刚打上去的label

创建pod使用nodeSelector调度到指定label的节点上

mysql-deployment.yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: mysql-2
spec:
 selector:
   matchLabels:
     app: mysql
 template:
   metadata:
     labels:
       app: mysql
   spec:
     containers:
     - image: mysql:5.6
       name: mysql
       env:
       - name: MYSQL_ROOT_PASSWORD
         value: password
       ports:
       - containerPort: 3306
         name: mysql
     nodeSelector:
       Configuration: hight

配置nodeSelector调度到Configuration:hight的host上
创建deployment

kubectl apply -f mysql-deployment.yaml

查看pod被调度到label为 Configuration: hight的host上了

场景二:部署的应用不想调度到某些节点上(nodeaffinity)

比如在一个kubernetes集群内,需要将应用部署到指定标签的机器上,但如果没有的话这类机器的话,就按正常调度规则进行调度。这时通过nodeSelector就无法实现这个需求了,在kubernetes内可以通过nodeaffinity的方式的去实现。

nodeaffinitynodeSelecotr非常类似,都是node层面的调度策略的配置,但区别是nodeSelect功能比较单一,只能根据label选择对应的主机,而nodeaffinity更加灵活,nodeaffinity有两种调度类型requiredDuringSchedulingIgnoredDuringExecution(硬要求)和preferredDuringSchedulingIgnoredDuringExecution(软要求),两种类型区别在于,硬要求要求调度时必须满足设置的调度规则,否则抛异常调度失败,而软要求,只是调度时优先考虑设置的调度规则,当达不到设置的规则时,则按kube-scheduler默认的调度策略进行调度。nodeaffinity还支持多种规则匹配条件的配置如
In:label 的值在列表内
NotIn:label 的值不在列表内
Gt:label 的值大于设置的值
Lt:label 的值小于设置的值
Exists:设置的label 存在
DoesNotExist:设置的 label 不存在

apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: mysql-2
spec:
 selector:
   matchLabels:
     app: mysql
 template:
   metadata:
     labels:
       app: mysql
   spec:
     containers:
     - image: mysql:5.6
       name: mysql
       env:
       - name: MYSQL_ROOT_PASSWORD
         value: password
       ports:
       - containerPort: 3306
         name: mysql
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: kubernetes.io/hostname
               operator: NotIn
               values:
               - rke-node3
               - rke-node4
         preferredDuringSchedulingIgnoredDuringExecution:
         - weight: 1
           preference:
             matchExpressions:
             - key: disk_type
               operator: In
               values:
               - ssd

如上所例,要求pod不能被调度到rke-node3和rke-node4上,但如果有满足dis_type=ssd的label的节点则优先选择。
如果在 nodeAffinity 类型中指定了多个 nodeSelectorTerms,那么 pod 将会被调度到只要满足其中一个 nodeSelectorTerms 的 node 上。
如果在 nodeSelectorTerms 中指定了多个 matchExpressions,那么 pod 将会被调度到 满足所有 matchExpressions 的 node 上。

场景三:部署的应用关联性很强,需要尽量在一个节点上

比如在kubernetes集群,有些pod和pod之间的交互很频繁,这时就需要将它们尽可能的调度到一台主机上,通过pod与pod之间的关系来选择调度,这时候我们就可以使用podaffinity。根nodeaffinity一样,podaffinity也有两种调度类型requiredDuringSchedulingIgnoredDuringExecution(硬要求)和preferredDuringSchedulingIgnoredDuringExecution(软要求),多种规则匹配条件配置。
例 部署一个nginx和mysql因为nginx和mysql之间的交互很频繁,所以尽量将他们部署在一个host上。
先启动一个nginx。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx

启动mysql

apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  containers:
  - name: mysql
    image: nginx
    env:
     - name: "MYSQL_ROOT_PASSWORD"
       value: "123456"
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname

topologyKey可以设置成如下几种类型
kubernetes.io/hostname  #Node
failure-domain.beta.kubernetes.io/zone #Zone
failure-domain.beta.kubernetes.io/region #Region
可以设置node上的label的值来表示node的name,zone,region等信息,pod的规则中指定topologykey的值表示指定topology范围内的node上运行的pod满足指定规则

这里我们配置podaffinity,mysql会调度到有app:nginx这个label的pod的host上,所以你部署出来的mysql会调度到有nginx的pod上,因为默认部署出来的nginx就自带app:nginx这个label。

场景四:部署应用需要互斥,不能同时运行在一台主机上,会冲突

我们继续以我们刚刚的nginx+mysql这个应用组合为例,现在我们修改mysql的podaffinitypodAntiAffinity

apiVersion: v1
kind: Pod
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  containers:
  - name: mysql
    image: nginx
    env:
     - name: "MYSQL_ROOT_PASSWORD"
       value: "123456"
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - nginx
        topologyKey: kubernetes.io/hostname

podaffinity改为podAntiAffinity这样调度mysql这个pod时会避开有label为app:nginx的pod的主机

高级特性Taints and tolerations

Taints其实根nodeaffinity正好相反,nodeaffinity是将设置策略的pod调度到期望的节点上,而taints正好相反,如果一个节点被标记为taints,除非pod配置了tolerations,否则是不会被允许调度过来在生产环境中我们一般会将master节点配置Taints,因为master只跑kubernetes 系统组件,如果跑了用户应用pod容易把资源耗尽,造成master节点崩溃,当然后期如果要添加额外的系统组件,这时就可以通过给对应的pod配置toleration。

设置rke-node2不能被调度

kubectl taint nodes rke-node2 key=value:NoSchedule

value可以配置多个值如
NoSchedule:不能调度,当之前调度的不管。
PreferNoSchedule:尽量不调度上去,其实就是Noschedule软策略版。
NoExecute:不能调度,但之前已经调度上去的也会自动迁移走。

NoSchedule更像执行kubectl cordon xxx
NoExecute更想执行kubectl cordon xxx+kubectl drain

取消taints

kubectl taint nodes rke-node2 key-

如何让pod调度到配置了taints主机上?
通过配置tolerations,可以让pod调度到配置了taints的机器上

apiVersion: apps/v1beta1
kind: Deployment
metadata:
 name: mysql-2
spec:
 selector:
   matchLabels:
     app: mysql
 template:
   metadata:
     labels:
       app: mysql
   spec:
     containers:
     - image: mysql:5.6
       name: mysql
       env:
       - name: MYSQL_ROOT_PASSWORD
         value: password
       ports:
       - containerPort: 3306
         name: mysql
     tolerations:
     - key: "key"
       operator: "Equal"
       value: "value"
       effect: "NoSchedule"
原文地址:https://www.cnblogs.com/cheyunhua/p/11309784.html