1、Deployment创建流程

13-Kuberbetes中Pod调度 - 图1

  • kubectl提交创建Pod,APIServer响应请求,通过一系列的认证授权,把请求数据存储到etcd,并返回状态。
  • Controller-Manager通过list-watch机制,检测发现存在未分配的deployment资源,发现该资源没有关联Pod和ReplicaSet,启动Deploument Controller创建ReplicaSet资源,在启用ReplicaSet Controller创建Pod。
  • 所有Controller正常后,将Deployment,replicaSet,pod资源信息更新到etcd。
  • Scheduler通过list-watch机制,检测发现存在未分配的Pod资源,通过调度算法选择合适的Node进行Pod的绑定。将绑定结果更新的etcd
  • kubelet每个20s向kube-apiserver通过NodeName获取自身Node上所要运行的Pod清单,通过与自己的内存缓存进行比较,调用docker api创建容器。
  • kubelet获取docker创建容器的状态,并汇报给apiserver,apiserver将Pod信息及状态更新的etcd。

2、影响Pod调度的因素

2.1、资源限制对Pod调度的影响

2.1.1、容器最大资源限制
  • resources.limits.cpu
    限制Pod最大允许使用CPU,CPU单位为m,也可以写为浮点数,例如0.5=500m,1=1000m
  • resources.limit.memory
    限制Pod最大允许使用的内存,内存单位为Mi、Gi

2.1.2、容器(最小)初始资源请求
  • resource.requests.cpu
    指定Pod创建时最小请求的CPU大小
  • resource.requests.memory
    限制Pod创建时最小请求的内存大小

2.1.3、资源限制示例

创建一个具有一个容器的 Pod。容器将会请求 0.5 个 CPU,而且最多限制使用 1 个 CPU,请求128Mi内存,最多限制使用512Mi

  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. name: cpu-demo
  5. namespace: cpu-example
  6. spec:
  7. containers:
  8. - name: cpu-demo-ctr
  9. image: nginx
  10. resources:
  11. limits: # 最大资源限制
  12. cpu: "1"
  13. memory: "512Mi"
  14. requests: # 初始请求资源
  15. cpu: "0.5"
  16. memory: "128Mi"

2.1.4、资源限制总结

资源限制包括CPU和内存对Pod调度的影响。

  • 如果指定限制条件,则会计算node节点是否满足Pod对资源的需要,如果不满足,则不会调度到此Node上。
  • 如果不指定限制条件,会发生以下情况之一。
    • 容器可以使用所有CPU资源。
    • 容器运行在有默认CPU限制的命名空间中,系统会自动为容器设置资源限制。
  • 如果设置了最大资源限制但没有设置初始资源请求,K8S会自动设置与最大限制相同的请求值。
  • 如果容器初始资源请求超过Node空闲资源,则Pod会处于Pending状态,直到满足条件。

2.2、nodeSelector

nodeSelector是影响Pod调度最简单的方式,通过对node添加标签label的方式,来选择Pod创建在哪个节点上。

2.2.1、nodeSelector示例
  • 添加标签label到node
# 给节点添加disktype为ssd的标签
kubectl label nodes k8s-slave1 disktype=ssd
# 查看node标签
kubectl get nodes --show-labels
  • 创建Pod是指定node标签
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:  # 选择nodeSelector
    disktype: ssd

此时创建的Pod只会在k8s-slave1上运行。

2.3、nodeAffinity

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

  • 匹配支持更多的逻辑组合,不只是字符串的完全相等,支持的操作符有
    • In、NotIn、Exists、DoesNotExist、Gt、Lt
  • 和nodeSelector完全匹配的硬性要求不同,调度分为软策略和硬策略
    • 硬(required):必须满足
    • 软(preferred):尝试满足,但不保证
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略,必须满足
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
      preferredDuringSchedulingIgnoredDuringExecution:  # 软策略,不保证满足
      - weight: 1  # 权重值,1-100,权重越大,调度到匹配节点的可能性越大。
        preference:  
          matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0

2.4、Taint(污点)与Tolerations(污点容忍)

Taint与节点亲和性相反,它使节点能够排斥一类特定的Pod。

2.4.1、Taint

避免Pod调度到指定的Node上

2.4.1.1、污点常用指令
  • 给节点添加污点。
    kubectl taint nodes [node] key=value:[effect]
    [effect]可取值为:
    • NoSchedule:一定不能被调度
    • PreferNoSchedule:尽量不要被调度,非必须配置容忍
    • NoExecute:不仅不会调度,还会驱逐Node上已有的Pod
# 给节点k8s-node1增加一个污点,键名为key1,值为value1,效果为NoSchedule。表示只有拥有和这个污点想匹配容忍度的Pod才能被分配到这个节点。
kubectl taint nodes k8s-node1 key1=value1:NoSchedule
  • 移除节点上的污点
kubectl taint nodes k8s-node1 key1=value1:NoSchedule-
  • 查看节点上的污点
[root@k8s-master resource]# kubectl describe node |grep Taint
Taints:             node-role.kubernetes.io/master:NoSchedule
Taints:             key1=value1:NoSchedule
Taints:             <none>

2.4.1.2、污点调度示例
  • 创建deployment,查看调度情况
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web
spec:
  replicas: 6
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}

执行kubectl apply -f taint.yaml后,可以发现所有Pod均调度到node2上。

2.4.2、Tolerations

允许Pod调度到指定Taints的Node上,并非一定会调度到指定的Node上。Taint和tolerations相互配合,可以用来避免Pod被分配到不合适的节点上。

2.4.2.1、污点容忍示例
  • 创建deployment,配置污点容忍,查看调度情况
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web
spec:
  replicas: 6
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      tolerations:
      - key: "key1"  # 容忍key
        operator: "Equal"  # 键值比对选项
        value: "value1"  # 值
        effect: "NoSchedule"
      containers:
      - image: nginx
        name: nginx
        resources: {}

operator默认值为Equal

  • 如果operator为Exists,表示只要存在和key相同的污点或相同污点调度策略则允许调度。为Exists时,不能存在value
  • 如果operator为Equal,则污点容忍要与value相等。

两种特殊情况:

  • 如果一个容忍度的key为空且operator为Exists,表示这个容忍度与任意的key、value、effect都匹配,即这个容忍度可以容忍任意污点。
  • 如果effect为空,则和所有key1的节点相匹配。

执行kubectl apply -f talerations.yaml后,可以发现node1和node2均会调度Pod。

2.5、nodeName

指定节点名称,用于将Pod调度到指定Node上,不经过调度器,不会受调度策略的影响。

使用nodename字段选择节点的一些限制“

  • 如果指定的节点不存在。
  • 如果指定的节点没有资源容纳Pod,Pod会调度失败。
  • 节点名称变化的情况。