kubernetes 简介:调度器和调度算法((Affinity/Anti-Affinity, Taints and Tolerations, 自定义调度器 )

进大厂,身价翻倍的法宝来了!

主讲内容:docker/kubernetes 云原生技术,大数据架构,分布式微服务,自动化测试、运维。

视频地址:ke.qq.com/course/419718


全栈工程师开发手册 (作者:栾鹏)
架构系列文章

简介

scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上。听起来非常简单,但有很多要考虑的问题:

  • 公平:如何保证每个节点都能被分配资源
  • 资源高效利用:集群所有资源最大化被使用
  • 效率:调度的性能要好,能够尽快地对大批量的 pod 完成调度工作
  • 灵活:允许用户根据自己的需求控制调度的逻辑

高级调度的新特性主要集中在四个方面:

sheduler 是作为单独的程序运行的,启动之后会一直坚挺 API Server,获取 PodSpec.NodeName 为空的 pod,对每个 pod 都会创建一个 binding,表明该 pod 应该放到哪个节点上。

  • Node的亲和性和反亲和性(Affinity/Anti-Affinity)
  • Node的污点和容忍(Taints and Tolerations)
  • Pod的亲和性和反亲和性(Affinity/Anti-Affinity)
  • 自定义调度器

参数说明

Scheduler 的参数是相对因为比较少的,因为它做的事情比较清晰,而且需要配置的地方比较少。下面是常见的参数列表和解释(不同版本 kubernetes 提供的参数可能会有出入,请以实际为准):

参数 意思 默认值
–address 监听地址 “0.0.0.0”
–port 调度器监听的端口 10251
–algorithm-provider 提供调度算法的对象 “DefaultProvider”
–master kubernetes API Server 的 HTTP API 地址
–profiling 是否开启 profiling,开启后可以在 host:port/debug/pprof 访问 profile 信息 true
–scheduler-name 调度器名称,用来唯一确定该调度器 “default-scheduler”
–kube-api-burst 和 API Server 通信的时候最大 burst 值 100
–kube-api-qps 和 API Server 通信的时候 QPS 值 50
–log_dir 日志保存的目录
–policy-config-file json 配置文件,用来指定调度器的 filters 和 priorities,可以参考 examples/scheduler-policy-config.json 文件

安装和使用

scheduler 的安装比较简单,它重要的参数就是 master 的 ip 地址,也是唯一必须指定的地址:

/opt/kubernetes/bin/kube-scheduler \
    --logtostderr=false \
    --v=4 \
    --log_dir=/var/log/kubernetes \
    --master=172.17.8.100:8080

运行之后,我们可以创建 pod 来测试。前一篇文章我们讲到需要手动指定 pod 要放到哪台 node 上,这次就不需要我们来做了,因为调度系统帮我们自动完成了这个步骤。来看看配置文件:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-server
spec:
  containers:
  - name: nginx-server
    image: 172.16.1.41:5000/nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - mountPath: /var/log/nginx
      name: nginx-logs
  - name: log-output
    image: 172.16.1.41:5000/busybox
    command:
    - bin/sh
    args: [-c, 'tail -f /logdir/access.log']
    volumeMounts:
    - mountPath: /logdir
      name: nginx-logs
  volumes:
  - name: nginx-logs
    emptyDir: {}

这里我们没有指定 pod 的 nodeName 属性,创建看看:

# kubectl create -f nginx-log.yml

等一段时间,可以使用 kubectl describe pod 来查看 pod 的信息,在输出的最后部分的事件列表中,我们可以看到第一条就是调度信息。下面这条记录说明了调度的时间,使用的调度器(default-scheduler),以及调度的最终结果(172.17.8.101):

Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath                   Type            Reason          Message
  ---------     --------        -----   ----                    -------------                   --------        ------          -------
  11m           11m             1       {default-scheduler }                                    Normal          Scheduled       Successfully assigned nginx-server to 172.17.8.101
  11m           11m             1       {kubelet 172.17.8.101}  spec.containers{nginx-server}   Normal          Pulling         pulling image "172.16.1.41:5000/library/nginx"
......

NOTE:这篇文章运行的实体都是 pod,但是实际上 ReplicationController(1.5 之后的版本更名为 ReplicaSet) 在实际更常用,我们会在后面的文章介绍。

调度过程

调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为 predicate;然后对通过的节点按照优先级排序,这个是 priority;最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。

predicate 有一系列的算法可以使用:

  • PodFitsResources:节点上剩余的资源是否大于 pod 请求的资源
  • PodFitsHost:如果 pod 指定了 NodeName,检查节点名称是否和 NodeName 匹配
  • PodFitsHostPorts:节点上已经使用的 port 是否和 pod 申请的 port 冲突
  • PodSelectorMatches:过滤掉和 pod 指定的 label 不匹配的节点
  • NoDiskConflict:已经 mount 的 volume 和 pod 指定的 volume 不冲突,除非它们都是只读

如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:
按照优先级大小对节点排序。

优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。这些优先级选项包括:

  • LeastRequestedPriority:通过计算 CPU 和 Memory 的使用率来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点
  • BalancedResourceAllocation:节点上 CPU 和 Memory 使用率越接近,权重越高。这个应该和上面的一起使用,不应该单独使用
  • ImageLocalityPriority:倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高

通过算法对所有的优先级项目和权重进行计算,得出最终的结果。

Node亲和性/反亲和性, Pod的亲和性和反亲和性

参考:https://blog.csdn.net/luanpeng825485697/article/details/84900192

污点和容忍(Taints and Tolerations)

污点(Taint)的组成

使用kubectl taint命令可以给某个Node节点设置污点,Node被设置上污点之后就和Pod之间存在了一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将Node已经存在的Pod驱逐出去。

每个污点的组成如下:

key=value:effect

每个污点有一个key和value作为污点的标签,其中value可以为空,effect描述污点的作用。当前taint effect支持如下三个选项:

  • NoSchedule:表示k8s将不会将Pod调度到具有该污点的Node上
  • PreferNoSchedule:表示k8s将尽量避免将Pod调度到具有该污点的Node上
  • NoExecute:表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去

污点的设置和去除

使用kubectl设置和去除污点的命令示例如下:

# 设置污点
kubectl taint nodes node1 key1=value1:NoSchedule

# 去除污点
kubectl taint nodes node1 key1:NoSchedule-

接下来看一个具体的例子,使用kubeadm部署和初始化的Kubernetes集群,master节点被设置了一个node-role.kubernetes.io/master:NoSchedule的污点,可以使用kubectl describe node 命令查看。这个污点表示默认情况下master节点将不会调度运行Pod,即不运行工作负载。对于使用二进制手动部署的集群设置和移除这个污点的命令如下:

kubectl taint nodes  node-role.kubernetes.io/master=:NoSchedule
kubectl taint nodes  node-role.kubernetes.io/master:NoSchedule-

注意:kubeadm初始化的Kubernetes集群,master节点也被打上了一个node-role.kubernetes.io/master=的label,标识这个节点的角色为master。给Node设置Label和设置污点是两个不同的操作。设置Label和移除Label的操作命令如下

# 设置Label
kubectl label node node1 node-role.kubernetes.io/master=
# 移除Label
kubectl label node node1 node-role.kubernetes.io/master-

kubectl get node
NAME      STATUS    ROLES     AGE       VERSION
node1    Ready     master    10d       v1.9.8
node2    Ready     master    10d       v1.9.8
node3    Ready     master    10d       v1.9.8
node4    Ready         10d       v1.9.8
node5    Ready         10d       v1.9.8

容忍(Tolerations)

设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。 但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。

通过在Pod的spec中设置tolerations字段,给Pod设置上容忍点Toleration:

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
  tolerationSeconds: 3600
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"
- key: "key2"
  operator: "Exists"
  effect: "NoSchedule"
  • 其中key, vaule, effect要与Node上设置的taint保持一致
  • operator的值为Exists将会忽略value值
  • tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间

下面看一下在Pod上设置容忍的两个特例:

示例1: 当不指定key值时,表示容忍所有的污点key:

tolerations:
- operator: "Exists"

示例2:当不指定effect值时,表示容忍所有的污点作用:

tolerations:
- key: "key"
  operator: "Exists"

自定义调度器

除了 kubernetes 自带的调度器,你也可以编写自己的调度器。通过 spec:schedulername 参数指定调度器的名字,可以为 pod 选择某个调度器进行调度。

比如下面的 pod 选择 my-scheduler 进行调度,而不是默认的 default-scheduler

apiVersion: v1
kind: Pod
metadata:
  name: annotation-second-scheduler
  labels:
    name: multischeduler-example
spec:
  schedulername: my-scheduler
  containers:
  - name: pod-with-second-annotation-container
    image: gcr.io/google_containers/pause:2.0

调度器的编写请参考 kubernetes 默认调度器的实现,最核心的内容就是读取 apiserver 中 pod 的值,根据特定的算法找到合适的 node,然后把调度结果会写到 apiserver。

自定义调度语言可以用任何语言编写,调度策略根据需要可以简单也可以复杂。这是一个非常简单的例子,它使用Bash编写,它可以为Pod随机分配一个Node。请注意,您需要让它与kubectl proxy一起运行:

#!/bin/bash
SERVER='localhost:8001' # Proxy address for apiServer
while true;
do
    # Get all pods, and pod's properties
    for PODNAME in $(kubectl --server $SERVER get pods -o json 
            | jq '.items[] 
            | select(.spec.schedulerName == "my-scheduler") 
            | select(.spec.nodeName == null) 
            | .metadata.name' | tr -d '"');
    do
        # Get all nodes
        NODES=($(kubectl --server $SERVER get nodes -o json 
                | jq '.items[].metadata.name' 
                | tr -d '"'))
        NUMNODES=${#NODES[@]}
        
        # Choose a node randomly
        CHOSEN=${NODES[$[ $RANDOM % $NUMNODES ]]}
        
        # Bind a pod($PODNAME) to a node($CHOSEN)
        curl --header "Content-Type:application/json"  
             --request POST 
             --data 
            '{
                 "apiVersion":"v1",
                 "kind": "Binding",
                 "metadata": {
                     "name": "'$PODNAME'"
                 }, 
                 "target": {
                     "apiVersion": "v1", 
                     "kind": "Node", 
                     "name": "'$CHOSEN'"
                 }
             }'
             http://$SERVER/api/v1/namespaces/default/pods/$PODNAME/binding/        echo "Assigned $PODNAME to $CHOSEN"
    done
    sleep 1
done

参考资料

https://cizixs.com/2017/03/10/kubernetes-intro-scheduler/

https://www.kubernetes.org.cn/1890.html

你可能感兴趣的:(架构,微服务架构)