首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Kubernetes 调度和驱逐

Kubernetes 调度和驱逐

作者头像
匿名用户的日记
发布2021-12-14 11:23:44
发布2021-12-14 11:23:44
9080
举报

概念

Kubernetes 调度和驱逐 doc

  • node上所有组件(kubelet/kube-proxy)都是与apiserver通信
  • master上两个组件(scheduler/controller-manager)都是与apiserver通信
  • apiserver将其他组件通信产生的事件、状态都保存到了与etcd数据库中
  • 其他组件与apiserver周期性watch事件。

图片解释:

kubectl通过读取集群配置文件 ~/.kube/config 将请求发给apiserver,之后apiserver将创建pod的属性信息写入到etcd中,etcd会响应一个状态给apiserver,保存etcd成功会在控制台显示pod/<pod名称> created,之后调度组件scheduler上线,负责将新的pod分配到合适的节点上,调度之后,将结果响应给apiserverapiserver再将结果保存到etcd中,kubelet当发现有个pod被绑定到自己的节点上时,就会调用dockerapi去创建容器,容器创建之后,docekr会返回一个状态给kubelet,创建成功之后,kubelet再通知apiserver容器状态,之后apiserver再将状态写入到etcd中,之后就可以使用kubelet get pod去查看pod的状态了

注意:有人会注意到,上图中少了两个组件,分别是node上的kube-proxy和master上的controller-manager,其中kube-proxy主要负责pod的服务发现和负载均衡,在图片中的位置就是介于kubelet与Docker之间,它的很多工作与kubelet是并行完成的,主要负责提供pod对外访问的一种形式。controller-manager组件主要是完成后台的一些任务,例如deployment与daemonset控制器等,而图片中是不涉及到创建控制器的步骤的,故与controller-manager就没什么关系,如果要创建控制器的话,角色位置介于Scheduler与kubelet之间,它负责创建多少个副本,启动多少个副本,滚动更新等更高级的功能。

总结:

kubectl ( .kube/config) -> apiserver -> write etcd -> scheduler -> 调度结果响应给apiserver -> kubelet 发现有分配到我的节点pod -> 调用docker api创建容器 -> 通知apiserver 容器状态

影响Pod调度的因素

参数解释:

  • resources:pod占用的硬件资源(资源调度依据)
  • schedulerName:默认调度器
  • nodeName:Scheduler控制器调度绑定的节点
  • nodeSelector:标签选择器
  • affinity:节点亲和性
  • tolerations:污点容忍

注意:调度器(schedulerName)除了使用自己的一些默认行为和默认策略之外,也会参考其他调度策略的值(主要参考)。

resources:资源限制

Pod和Container的资源请求和限制:

  • spec.containers[ ].resources.limits.cpu
  • spec.containers[ ].resources.limits.memory
  • spec.containers[ ].resources.requests.cpu
  • spec.containers[ ].resources.requests.memory
  • 参数解释:
  • requests:资源请求值,部署资源的最小配合,是调度依据,会根据requests的值去判定当前集群中有无节点去满足请求的量
  • limits:资源最大使用

requests必须小于limits的值!

扩展:查看当前节点的资源信息:

代码语言:javascript
复制
kubectl describe node <node-name>

注意: 若pod没有配置resources值,则pod可以使用宿主机所有资源,并且调度不参考配额

建议:requestslimits不要相差太多

nodeSelector & nodeAffinity (节点标签和节点亲和)

nodeSelector

nodeSelector:用于将Pod调度到匹配Label 的Node上

给节点打标签并查看对应节点的标签:

代码语言:javascript
复制
kubectl label nodes <node-name> key=value
kubectl get nodes <node-name> --show-labels

应用场景:适用于多节点,且不同节点配置不一,功能不一的情况。

yaml示例:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
spec:
  nodeSelector:
    disktype: ssd
  containers:
  - name: nginx
    image: nginx:1.15

注意:若没有匹配到任何标签,则pod会显示pending状态,节点都不可用

nodeAffinity

nodeAffinity:节点亲和性,类似于nodeSelector,可以根据节点上的标签来约束Pod可以调度到哪些节点。

相比nodeSelector

  • 匹配有更多的逻辑组合,不只是字符串的完全相等(nodeSelector是绝对相等的匹配)
  • 调度分为软策略和硬策略,而不是硬性要求 a.硬(required):必须满足 b.软(preferred):尝试满足,但不保证

操作符:InNotInExistsoesNotExistGtLt

yaml示例:

代码语言:javascript
复制
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: k8s.gcr.io/pause:2.0

参数解释:

  • requiredDuringSchedulingIgnoredDuringExecution:硬策略,节点必须满足的条件
  • operator:操作符
  • preferredDuringSchedulingIgnoredDuringExecution:软策略,尝试满足,不是必须满足的条件
  • weight:权重值,范围1-100,值越大,权重越大,pod调度到对应标签的节点概率越高

注意:若硬限制(requiredDuringSchedulingIgnoredDuringExecution)没有匹配到任何标签,则pod会显示pending状态,节点都不可用,当打完标签之后,pending会变为running状态

补充: 节点亲和性:希望调度到指定标签的节点上; 反亲和性:不希望调度到指定标签的节点上,如使用NotIn ,DoesNotExist等

podAffinity && podAntiAffinity (pod 间亲和与反亲和)

pod 间亲和与反亲和使你可以基于已经在节点上运行的 pod 的标签来约束 pod 可以调度到的节点,而不是基于节点上的标签。规则的格式为“如果 X 节点上已经运行了一个或多个 满足规则 Y 的pod,则这个 pod 应该(或者在非亲和的情况下不应该)运行在 X 节点”。Y 表示一个具有可选的关联命令空间列表的 LabelSelector;与节点不同,因为 pod 是命名空间限定的(因此 pod 上的标签也是命名空间限定的),因此作用于 pod 标签的标签选择器必须指定选择器应用在哪个命名空间。从概念上讲,X 是一个拓扑域,如节点,机架,云供应商地区,云供应商区域等。你可以使用 topologyKey 来表示它,

说明: Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。我们不建议在超过数百个节点的集群中使用它们

topologyKey 是节点标签的键以便系统用来表示这样的拓扑域。

  • kubernetes.io/hostname
  • failure-domain.beta.kubernetes.io/zone
  • failure-domain.beta.kubernetes.io/region
  • topology.kubernetes.io/zone
  • topology.kubernetes.io/region
  • beta.kubernetes.io/instance-type
  • node.kubernetes.io/instance-type
  • kubernetes.io/os
  • kubernetes.io/arch

说明: 这些标签的值是特定于云供应商的,因此不能保证可靠。例如,kubernetes.io/hostname 的值在某些环境中可能与节点名称相同,但在其他环境中可能是一个不同的值。

与节点亲和一样,当前有两种类型的 pod 亲和与反亲和,即 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution,分表表示“硬性”与“软性”要求。请参阅前面节点亲和部分中的描述。requiredDuringSchedulingIgnoredDuringExecution 亲和的一个示例是“将服务 A 和服务 B 的 pod 放置在同一区域,因为它们之间进行大量交流”,而 preferredDuringSchedulingIgnoredDuringExecution 反亲和的示例将是“将此服务的 pod 跨区域分布”(硬性要求是说不通的,因为你可能拥有的 pod 数多于区域数)。

Pod 间亲和通过 PodSpec 中 affinity 字段下的 podAffinity 字段进行指定。而 pod 间反亲和通过 PodSpec 中 affinity 字段下的 podAntiAffinity 字段进行指定

Pod 使用 pod 亲和 的示例:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: failure-domain.beta.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

在这个 pod 的 affinity 配置定义了一条 pod 亲和规则和一条 pod 反亲和规则。在此示例中,podAffinity 配置为 requiredDuringSchedulingIgnoredDuringExecution,然而 podAntiAffinity 配置为 preferredDuringSchedulingIgnoredDuringExecution。pod 亲和规则表示,仅当节点和至少一个已运行且有键为“security”且值为“S1”的标签的 pod 处于同一区域时,才可以将该 pod 调度到节点上。(更确切的说,如果节点 N 具有带有键 failure-domain.beta.kubernetes.io/zone 和某个值 V 的标签,则 pod 有资格在节点 N 上运行,以便集群中至少有一个节点具有键 failure-domain.beta.kubernetes.io/zone 和值为 V 的节点正在运行具有键“security”和值“S1”的标签的 pod。)pod 反亲和规则表示,如果节点已经运行了一个具有键“security”和值“S2”的标签的 pod,则该 pod 不希望将其调度到该节点上。(如果 topologyKeyfailure-domain.beta.kubernetes.io/zone,则意味着当节点和具有键“security”和值“S2”的标签的 pod 处于相同的区域,pod 不能被调度到该节点上。)

Pod 亲和与反亲和的合法操作符有 InNotInExistsDoesNotExist

原则上,topologyKey 可以是任何合法的标签键。然而,出于性能和安全原因,topologyKey 受到一些限制:

  1. 对于亲和与 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,topologyKey 不允许为空。
  2. 对于 requiredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,准入控制器 LimitPodHardAntiAffinityTopology 被引入来限制 topologyKey 不为 kubernetes.io/hostname。如果你想使它可用于自定义拓扑结构,你必须修改准入控制器或者禁用它。
  3. 对于 preferredDuringSchedulingIgnoredDuringExecution 要求的 pod 反亲和,空的 topologyKey 被解释为“所有拓扑结构”(这里的“所有拓扑结构”限制为 kubernetes.io/hostnamefailure-domain.beta.kubernetes.io/zonefailure-domain.beta.kubernetes.io/region 的组合)。
  4. 除上述情况外,topologyKey 可以是任何合法的标签键。

除了 labelSelectortopologyKey,你也可以指定表示命名空间的 namespaces 队列,labelSelector 也应该匹配它(这个与 labelSelectortopologyKey 的定义位于相同的级别)。如果忽略或者为空,则默认为 pod 亲和/反亲和的定义所在的命名空间。

所有与 requiredDuringSchedulingIgnoredDuringExecution 亲和与反亲和关联的 matchExpressions 必须满足,才能将 pod 调度到节点上。

阿里云nginx-ingress示例

分布nginx-ingress到每个节点 只是部分内容请勿直接使用

代码语言:javascript
复制
spec:
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: ingress-nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      annotations:
        prometheus.io/port: '10254'
        prometheus.io/scrape: 'true'
        redeploy-timestamp: '1597647322549'
      labels:
        app: ingress-nginx
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                  - key: type
                    operator: NotIn
                    values:
                      - virtual-kubelet
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values:
                        - ingress-nginx
                topologyKey: kubernetes.io/hostname
              weight: 100


      nodeSelector:
        beta.kubernetes.io/os: linux

Taint(污点)

Taints:避免Pod调度到特定Node上

nodeSelector & nodeAffinity区别:

  • nodeSelector & nodeAffinity:将pod分配到某些节点。pod属性
  • Taints:节点不允许分配pod。节点属性

应用场景:

  • 专用节点
  • 配备了特殊硬件的节点
  • 基于Taint的驱逐

查看节点污点:

代码语言:javascript
复制
kubectl describe node <node-name> | grep Taint

设置污点:

代码语言:javascript
复制
kubectl taint node <node-name> key=value:<effect>

给节点 <node-name> 增加一个污点,它的键名是 key,键值是 value,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 <node-name> 这个节点

其中<effect> 可取值:

  • NoSchedule :一定不能被调度(已经调度的不会被驱逐)。
  • PreferNoSchedule:尽量不要调度(软性)。
  • NoExecute:不仅不会调度,还会驱逐Node上已有的Pod(若pod为设置污点容忍)。

去掉污点:

代码语言:javascript
复制
kubectl taint node <node-name> key:<effect>-

Tolerations(污点容忍)

Tolerations:允许Pod调度到有特定Taints的Node上

yaml示例:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: pod-taints
spec:
  containers:
  - name: pod-taints
    image: busybox:latest
  tolerations:
  - key: "key"
    operator: "Equal"
    value: "value"
    effect: "NoSchedule"

operator 的默认值是 Equal

一个容忍度和一个污点相“匹配”是指它们有一样的键名和效果,并且:

  • 如果 operatorExists (此时容忍度不能指定 value),或者
  • 如果 operatorEqual ,则它们的 value 应该相等

node根据状态也会自动打一些污点:

  • node.kubernetes.io/not-ready:节点未准备好。这相当于节点状态 Ready 的值为 “False”。
  • node.kubernetes.io/unreachable:节点控制器访问不到节点. 这相当于节点状态 Ready 的值为 “Unknown”。
  • node.kubernetes.io/out-of-disk:节点磁盘耗尽。
  • node.kubernetes.io/memory-pressure:节点存在内存压力。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力。
  • node.kubernetes.io/network-unavailable:节点网络不可用。
  • node.kubernetes.io/unschedulable: 节点不可调度。
  • node.cloudprovider.kubernetes.io/uninitialized:如果 kubelet 启动时指定了一个 “外部” 云平台驱动, 它将给当前节点添加一个污点将其标志为不可用。在 cloud-controller-manager 的一个控制器初始化这个节点后,kubelet 将删除这个污点。

容忍污点:不是强制性分配到具有污点的节点上,配置了容忍污点,在调度时忽略节点污点

nodeName

nodeName:用于将Pod调度到指定的Node上,不经过调度器(default-scheduler

应用场景:

  • 调度组件故障,希望临时救急

yaml示例:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
  labels:
    app: nginx
spec:
  nodeName: k8s-node2
  containers:
  - name: nginx
    image: nginx:1.15

DaemonSet(守护进程集)

DaemonSet功能:

  • 在每一个Node上运行一个Pod
  • 新加入的Node也同样会自动运行一个Pod

应用场景:

  • 网络插件
  • Agent(zabbix-agent监控)
  • 日志采集(filebeat)
  • C/S架构软件
  • 必要的分发服务例如 nginx-ingress

yaml示例:

代码语言:javascript
复制
apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: web
  name: filebeat
spec:
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}

通过kubectl get pod可以发现filebeat在每个node上都部署了一个:

代码语言:javascript
复制
[root@k8s-master k8s]# kubectl get pod -o wide
NAME                         READY   STATUS             RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
filebeat-9kc9d               1/1     Running            0          8s      10.244.36.118    k8s-node1   <none>           <none>
filebeat-wsbxb               1/1     Running            0          8s      10.244.169.183   k8s-node2   <none>           <none>

查看daemonset:

代码语言:javascript
复制
[root@k8s-master k8s]# kubectl get ds
NAME       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
filebeat   2         2         2       2            2           <none>          3m2s

调度失败原因分析

查看调度结果:

代码语言:javascript
复制
kubectl get pod <NAME> -o wide

查看调度失败原因:

代码语言:javascript
复制
kubectl describe pod <NAME>

错误解析:

  • 没有匹配到标签的提示信息: 0/3 nodes are available: 3 node(s) didn’t match node selector.
  • 没有足够的cpu资源分配: 0/3 nodes are available: 3 Insufficient cpu.
  • 3个节点有污点,没有配置污点容忍: 0/3 nodes are available: 3 node(s) had taints that the pod didn’t tolerate.
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • 影响Pod调度的因素
  • resources:资源限制
  • nodeSelector & nodeAffinity (节点标签和节点亲和)
    • nodeSelector
    • nodeAffinity
    • podAffinity && podAntiAffinity (pod 间亲和与反亲和)
    • Taint(污点)
    • Tolerations(污点容忍)
    • nodeName
    • DaemonSet(守护进程集)
  • 调度失败原因分析
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档