Kubernetes之Pod调度

【编者的话】Kubernetes调度器根据特定的算法与策略将pod调度到工作节点上。在默认情况下,Kubernetes调度器可以满足绝大多数需求,例如调度pod到资源充足的节点上运行,或调度pod分散到不同节点使集群节点资源均衡等。但一些特殊的场景,默认调度算法策略并不能满足实际需求,例如使用者期望按需将某些pod调度到特定硬件节点(数据库服务部署到SSD硬盘机器、CPU/内存密集型服务部署到高配CPU/内存服务器),或就近部署交互频繁的pod(例如同一机器、同一机房、或同一网段等)。

Kubernetes中的调度策略主要分为全局调度与运行时调度2种。其中全局调度策略在调度器启动时配置,而运行时调度策略主要包括选择节点(nodeSelector),节点亲和性(nodeAffinity),pod亲和与反亲和性(podAffinity与podAntiAffinity)。Node Affinity、podAffinity/AntiAffinity以及后文即将介绍的污点(Taints)与容忍(tolerations)等特性,在Kuberntes1.6中均处于Beta阶段。

本文着重介绍运行时调度策略。

设置节点label

Label是Kubernetes核心概念之一,其以key/value的形式附加到各种对象上,如Pod、Service、Deployment、Node等,达到识别这些对象,管理关联关系等目的,如Node和Pod的关联。
获取当前集群中的全部节点:

kubectl get nodes

为指定节点设置label:

kubectl label nodes <node-name> <label-key>=<label-value>

确认节点label是否设置成功:

kubectl get nodes -label_key=label_value

选择节点(nodeSelector)

nodeSelector是目前最为简单的一种pod运行时调度限制,目前在Kubernetes1.7.x及以下版本可用。Pod.spec.nodeSelector通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,而后调度pod到目标节点,该匹配规则属于强制约束。后文要讲的nodeAffinity具备nodeSelector的全部功能,所以未来Kubernetes会将nodeSelector废除。

nodeSelector举例:

设置label

$ kubectl label nodes bjo-rpt-re-002.dev.fwmrm.net disktype=ssd
node "bjo-rpt-re-002.dev.fwmrm.net" labeled

查看满足非master节点且disktype类型为ssd的节点:

kubectl get nodes -'role!=master, disktype=ssd'
NAME                           STATUS    AGE       VERSION
bjo-rpt-re-002.dev.fwmrm.net   Ready     39d       v1.7.1

pod.yaml文件内容:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd

创建pod:

kubectl create -f pod.yaml

查看pod nginx被调度到预期节点运行:

$ kubectl get po nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP            NODE
nginx     1/1       Running   0          10s       10.244.3.13   bjo-rpt-re-002.dev.fwmrm.net

注:如果非默认namespace,需要指定具体namespace,例如:

kubectl -n kube-system get pods -o wide

内置节点label

Kubernetes自v1.4开始,节点有一些built-in label,罗列如下:

  • kubernetes.io/hostname
  • failure-domain.beta.kubernetes.io/zone
  • failure-domain.beta.kubernetes.io/region
  • beta.kubernetes.io/instance-type
  • beta.kubernetes.io/os
  • beta.kubernetes.io/arch
built-in label举例

yaml文件内容:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
kubernetes.io/hostname: bjo-ep-svc-017.dev.fwmrm.net

创建pod,并检查结果符合预期,pod被调度在预先设置的节点 bjo-ep-svc-017.dev.fwmrm.net:

$ kubectl get po nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP            NODE
nginx     1/1       Running   0          3m        10.244.1.58   bjo-ep-svc-017.dev.fwmrm.net

亲和性(Affinity)与非亲和性(anti-affinity)

前面提及的nodeSelector,其仅以一种非常简单的方式、即label强制限制pod调度到指定节点。而亲和性(Affinity)与非亲和性(anti-affinity)则更加灵活的指定pod调度到预期节点上,相比nodeSelector,Affinity与anti-affinity优势体现在:

  • 表述语法更加多样化,不再仅受限于强制约束与匹配。
  • 调度规则不再是强制约束(hard),取而代之的是软限(soft)或偏好(preference)。
  • 指定pod可以和哪些pod部署在同一个/不同拓扑结构下。

亲和性主要分为3种类型:node affinity与inter-pod affinity/anti-affinity,下文会进行详细说明。

节点亲和性(Node affinity)

Node affinity在Kubernetes 1.2做为alpha引入,其涵盖了nodeSelector功能,主要分为requiredDuringSchedulingIgnoredDuringExecution与preferredDuringSchedulingIgnoredDuringExecution 2种类型。前者可认为一种强制限制,如果 Node 的标签发生了变化导致其没有符合 Pod 的调度要求节点,那么pod调度就会失败。而后者可认为理解为软限或偏好,同样如果 Node 的标签发生了变化导致其不再符合 pod 的调度要求,pod 依然会调度运行。

Node affinity举例

设置节点label:

$ kubectl label nodes bjo-ep-dep-040.dev.fwmrm.net cpu=high
node "bjo-ep-dep-040.dev.fwmrm.net" labeled

$  kubectl label nodes bjo-ep-svc-017.dev.fwmrm.net cpu=mid
node "bjo-ep-svc-017.dev.fwmrm.net" labeled

$  kubectl label nodes bjo-rpt-re-002.dev.fwmrm.net cpu=low
node "bjo-rpt-re-002.dev.fwmrm.net" labeled

部署pod的预期是到非master节点(role!=master)、且CPU高配的机器上(cpu=high)。
查看满足条件节点:

$ kubectl get nodes -'cpu=high, role!=master'
NAME                           STATUS    AGE       VERSION
bjo-ep-dep-040.dev.fwmrm.net   Ready     41d       v1.7.1

pod.yaml文件内容如下:

apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
affinity:
nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchExpressions:
      - key: role
        operator: NotIn
        values:
        - master
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 1
    preference:
      matchExpressions:
      - key: cpu
        operator: In
        values:
        - high
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

检查结果符合预期,pod nginx成功部署到非master节点且CPU高配的机器上。

$ kubectl get po  nginx -o wide
NAME      READY     STATUS    RESTARTS   AGE       IP             NODE
nginx     1/1       Running   0          32s       10.244.2.185   bjo-ep-dep-040.dev.fwmrm.net

pod亲和性(Inter-pod affinity)与反亲和性(anti-affinity)

inter-pod affinity与anti-affinity由Kubernetes 1.4引入,当前处于beta阶段,其中podAffinity用于调度pod可以和哪些pod部署在同一拓扑结构之下。而podAntiAffinity相反,其用于规定pod不可以和哪些pod部署在同一拓扑结构下。通过pod affinity与anti-affinity来解决pod和pod之间的关系。
与Node affinity类似,pod affinity与anti-affinity同样分为requiredDuringSchedulingIgnoredDuringExecution and preferredDuringSchedulingIgnoredDuringExecution等2种类型,前者被认为是强制约束,而后者后者可认为理解软限(soft)或偏好(preference)。

pod affinity与anti-affinity举例

本示例中假设部署场景为:期望is服务与oltp服务就近部署,而不希望与solr服务部署同一拓扑结构上。
yaml文件部分内容:

spec:
replicas: 1
template:
metadata:
  labels:
    app: is

spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: NotIn
            values:
            - solr
        topologyKey: kubernetes.io/hostname
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - oltp
          topologyKey: beta.kubernetes.io/os

查看部署结果,is服务与oltp部署到了同一台机器,而solr被部署在其他机器上。

$ kubectl get po -o wide
NAME                           READY     STATUS    RESTARTS   AGE       IP             NODE
is-3059482752-5s14t            0/1       Running   1          1m        10.244.1.60    bjo-ep-svc-017.dev.fwmrm.net
oltp-282283610-kdvnp           1/1       Running   0          1m        10.244.1.53    bjo-ep-svc-017.dev.fwmrm.net
solr-908150957-rswlm           1/1       Running   0          1m        10.244.3.5     bjo-rpt-re-002.dev.fwmrm.net

亲和性/反亲和性调度策略比较

调度策略         匹配标签 操作符                拓扑域支持  调度目标
nodeAffinity    主机    In, NotIn, Exists,            pod到指定主机
                       DoesNotExist, Gt, Lt  
podAffinity     Pod    In, NotIn, Exists,            pod与指定pod同一拓扑域
                       DoesNotExist            
PodAntiAffinity Pod    In, NotIn, Exists,            pod与指定pod非同一拓扑域
                       DoesNotExist            

污点(Taints)与容忍(tolerations)

对于Node affinity,无论是强制约束(hard)或偏好(preference)方式,都是调度pod到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taints ,除非 Pod也被标识为可以耐受污点节点,否则该Taints节点不会被调度pod。Taints)与tolerations当前处于beta阶段,
Taints节点应用场景比如用户希望把Kubernetes Master节点保留给 Kubernetes 系统组件使用,或者把一组具有特殊资源预留给某些 pod。pod不会再被调度到taint标记过的节点。

taint标记节点举例如下:
$ kubectl taint nodes bjo-ep-dep-039.dev.fwmrm.net key=value:NoSchedule
node "bjo-ep-dep-039.dev.fwmrm.net" tainted

如果仍然希望某个pod调度到taint节点上,则必须在 Spec 中做出Toleration 定义,才能调度到该节点,举例如下:

tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"

effect 共有三个可选项,可按实际需求进行设置:

  • NoSchedule:pod不会被调度到标记为taints节点。
  • PreferNoSchedule:NoSchedule的“preference”或“soft”版本。
  •  NoExecute:该选项意味着一旦Taint 生效,如该节点内正在运行的 Pod 没有对应 Tolerate 设置,会直接被逐出。

总结

使用者可根据实际需求,充分利用pod的相关高级调度策略,使Kubernetes更好的服务于我们的需求。

参考文档

  • Assigning Pods to Nodes: https://kubernetes.io/docs/con … node/
  • Advanced Scheduling in Kubernetes: http://blog.kubernetes.io/2017 … .html

欢迎转载,请注明作者出处:张夏,FreeWheel Lead Engineer,Kubernetes中文社区

你可能感兴趣的:(docker,kubernetes)