千家信息网

kubernetes中pod资源的调度

发表于:2025-02-12 作者:千家信息网编辑
千家信息网最后更新 2025年02月12日,kubernetes简介kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容
千家信息网最后更新 2025年02月12日kubernetes中pod资源的调度

kubernetes简介

kubernetes,简称K8s,是用8代替8个字符"ubernete"而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。

Pod简介

Pod是Kubernetes创建或部署的最小/最简单的基本单位,一个Pod代表集群上正在运行的一个进程。

一个Pod封装一个应用容器(也可以有多个容器),存储资源、一个独立的网络IP以及管理控制容器运行方式的策略选项。Pod代表部署的一个单位:Kubernetes中单个应用的实例,它可能由单个容器或多个容器共享组成的资源。

通常情况下,使用的都是k8s默认的调度调度方式,但是在有些情况下,我们需要将pod运行在具有特点的标签的node上才能都运行,这个时候,pod的调度策略就不能使用k8s默认的调度策略了,这个时候,就需要指定调度策略,告诉k8s需要将pod调度到那些node(节点)上。

nodeSelector
常规情况下,会直接使用nodeSelector这种调度策略。labels(标签) 是k8s里面用来编标记资源的一种常用的方式,我们可以给node标记特殊的标签,然后nodeSelector会将pod调度到带有指定labels的node上的。

下面看个示例:

首先,查看node的label信息,通过下面的命令查看的 node 的 label:

$ kubectl get nodes --show-labelsNAME      STATUS    ROLES     AGE       VERSION   LABELSmaster    Ready     master    147d      v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=node02    Ready         67d       v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,course=k8s,kubernetes.io/hostname=node02node03    Ready         127d      v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03

然后,可以给node02节点新增一个label:

$ kubectl label nodes node02 com=yijiadashujunode "node02" labeled

然后通过上面的--show-labels参数可以查看上述标签是否生效。当 node 被打上了相关标签后,在调度的时候就可以使用这些标签了,只需要在 Pod 的spec字段中添加nodeSelector字段,里面是我们需要被调度的节点的 label 即可。比如,要将 Pod 我们要强制调度到 node02 这个节点上去,可以使用 nodeSelector 来表示了:(pod-selector-demo.yaml)

apiVersion: v1kind: Podmetadata:  labels:    app: busybox-pod  name: test-busyboxspec:  containers:  - command:    - sleep    - "3600"    image: busybox    imagePullPolicy: Always    name: test-busybox  nodeSelector:    com: yijiadashuju

然后,执行pod-selector-demo.yaml文件后,可以通过下面的命令查看pod运行的节点信息

kubectl get pod -o wide -n default

也可以使用description命令查看pod被调度到哪个节点上:

$ kubectl create -f pod-selector-demo.yamlpod "test-busybox" created$ kubectl describe pod test-busyboxName:         test-busyboxNamespace:    defaultNode:         node02/10.151.30.63......QoS Class:       BestEffortNode-Selectors:  com=youdianzhishiTolerations:     node.kubernetes.io/not-ready:NoExecute for 300s                 node.kubernetes.io/unreachable:NoExecute for 300sEvents:  Type    Reason                 Age   From               Message  ----    ------                 ----  ----               -------  Normal  SuccessfulMountVolume  55s   kubelet, node02    MountVolume.SetUp succeeded for volume "default-token-n9w2d"  Normal  Scheduled              54s   default-scheduler  Successfully assigned test-busybox to node02  Normal  Pulling                54s   kubelet, node02    pulling image "busybox"  Normal  Pulled                 40s   kubelet, node02    Successfully pulled image "busybox"  Normal  Created                40s   kubelet, node02    Created container  Normal  Started                40s   kubelet, node02    Started container

从上面的执行结果可以看出,pod 通过默认的 default-scheduler 调度器到了node02节点上。不过,这种调度方式属于强制性的。如果node02上的资源不足,那么pod的状态将会一直是pending状态。这就是nodeselector的用法了。

通过上面的介绍,可以看出nodeselector使用起来非常方便,但是还有很多的不足,那就是不够灵活,控制粒度偏大,在实际使用中还是有许多的不便。接下来一起看先亲和性和反亲和性调度。

亲和性和反亲和性调度

k8s的默认调度流程实际上是经过了两个阶段:predicates 和 priorities 。使用默认的调度流程的话,k8s会将pod调度到资源充裕的节点上,使用nodeselector的调度方法,又会将pod调度具有指定标签的pod上。然后在实际生产环ongoing境中,我们需要将pod调度到具有默些label的一组node才能满足实际需求,这个时候就需要nodeAffinity(节点亲和性)、podAffinity(pod 亲和性) 以及 podAntiAffinity(pod 反亲和性)。

亲和性可以分为具体可以细分为硬和软两种亲和性,

软亲和性:如果调度的时候,没有满足要求,也可以继续调度,即能满足最好,不能也无所谓
硬亲和性:是指调度的时候必须满足特定的要求,如果不满足,那么pod将不会被调度到当前node

规则可以设置:
软策略: preferredDuringSchedulingIgnoredDuringExecution

硬策略: requiredDuringSchedulingIgnoredDuringExecution

nodeAffinity 节点亲和性
节点亲和性主要是用来控制 pod 能部署在哪些节点上,以及不能部署在哪些节点上的。它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。

接下来看一个示例,使用 Deployment 来管理3个 pod 副本,使用nodeAffinity控制 pod 的调度,如下例子:(node-affinity-demo.yaml)

apiVersion: apps/v1beta1kind: Deploymentmetadata:  name: affinity  labels:    app: affinityspec:  replicas: 3  revisionHistoryLimit: 15  template:    metadata:      labels:        app: affinity        role: test    spec:      containers:      - name: nginx        image: nginx:1.7.9        ports:        - containerPort: 80          name: nginxweb      affinity:        nodeAffinity:          requiredDuringSchedulingIgnoredDuringExecution:  # 硬策略            nodeSelectorTerms:            - matchExpressions:              - key: kubernetes.io/hostname                operator: NotIn                values:                - node03          preferredDuringSchedulingIgnoredDuringExecution:  # 软策略          - weight: 1            preference:              matchExpressions:              - key: com                operator: In                values:                - yijiadashuju

这个pod调度的时候,首先要求不能运行在node03节点上,但是如果有节点满足labels为com:yijiadashuju 的话,就会优先调度到这个节点上。

接下来看下节点信息:

$ kubectl get nodes --show-labelsNAME      STATUS    ROLES     AGE       VERSION   LABELSmaster    Ready     master    154d      v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=node02    Ready         74d       v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=yijiadashuju,course=k8s,kubernetes.io/hostname=node02node03    Ready         134d      v1.10.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03

可以看到 node02 节点有com=yijiadashuju的 label,按要求会优先调度到这个节点,接下来创建 pod,然后使用descirbe命令查看调度情况。

$ kubectl create -f node-affinity-demo.yamldeployment.apps "affinity" created$ kubectl get pods -l app=affinity -o wideNAME                        READY     STATUS    RESTARTS   AGE       IP             NODEaffinity-7b4c946854-5gfln   1/1       Running   0          47s       10.244.4.214   node02affinity-7b4c946854-l8b47   1/1       Running   0          47s       10.244.4.215   node02affinity-7b4c946854-r86p5   1/1       Running   0          47s       10.244.4.213   node02

从结果可以看到 pod 均被部署到了 node02节点。

现在Kubernetes提供的操作符有下面的几种

In:label 的值在某个标签中NotIn:label 的值不在某个标签中Gt:label 的值大于某个值Lt:label 的值小于某个值Exists:某个 label 存在DoesNotExist:某个 label 不存在

如果nodeSelectorTerms下面有多个选项的话,满足任何一个条件就可以了;如果matchExpressions有多个选项的话,则必须同时满足这些条件才能正常调度 POD。

podAffinity pod亲和性

pod的亲和性主要用来解决pod可以和哪些pod部署在同一个集群里面,即拓扑域(由node组成的集群)里面;而pod的反亲和性是为了解决pod不能和哪些pod部署在一起的问题,二者都是为了解决pod之间部署问题。需要注意的是,Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度,不建议在具有几百个节点的集群中使用,而且Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配 topologyKey。如果某些或所有节点缺少指定的 topologyKey 标签,可能会导致意外行为。

下面是pod间亲和的示例:

pods/pod-with-pod-affinity.yaml:

apiVersion: v1kind: Podmetadata:  name: with-pod-affinityspec:  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

podAntiAffinity pod反亲和性

下面是一个pod反亲和yaml文件示例:

apiVersion: apps/v1kind: Deploymentmetadata:  name: redis-cachespec:  selector:    matchLabels:      app: store  replicas: 3  template:    metadata:      labels:        app: store    spec:      affinity:        podAntiAffinity:          requiredDuringSchedulingIgnoredDuringExecution:          - labelSelector:              matchExpressions:              - key: app                operator: In                values:                - store            topologyKey: "kubernetes.io/hostname"      containers:      - name: redis-server        image: redis:3.2-alpine
0