【kubernetes系列】Kubernetes之调度器和调度过程

Kubernetes之调度器和调度过程

概述

当用户请求向API server创建新的Pod时,API server检查授权、权限等没有任何问题的话,他会把这个请求交由Scheduler,由Scheduler检查所有符合该Pod要求的列表,开始执行Pod调度逻辑,选定Node完成后会把选择结果返回给API server,并将选定信息写入etcd中。接下来API server将指挥被选定Node的kubelet去创建Pod(或者说kubelet始终去watch API server当中与当前节点相关联的事件变动),因此接下来这个node就要去尝试着获取到API server当中定义的这个pod的配置清单,根据配置清单当中的定义去创建pod。Scheduler在整个系统中承担了承上启下的作用,承上是负责接收创建的新Pod,为安排一个落脚的地(Node),启下是安置工作完成后,目标Node上的kubelet服务进程接管后继工作,负责Pod生命周期的后半生。具体来说Scheduler的作用是将待调度的Pod按照特定的调度算法和调度策略绑定到集群中的某个合适的Node上,整个调度过程中涉及三个对象,分别是:待调度的Pod列表,可用的Node列表,以及调度算法和策略。

调度流程

Kubernetes Scheduler 提供的调度流程分三步:

  • 预选策略(predicate) 遍历nodelist,选择出符合要求的候选节点,Kubernetes内置了多种预选规则供用户选择。
  • 优选策略(priority) 在选择出符合要求的候选节点中,采用优选规则计算出每个节点的积分,最后选择得分最高的。
  • 选定(select) 如果最高得分有好几个节点,select就会从中随机选择一个节点。

如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oZbCzjOA-1689302208127)(image/scheduler-1.png)]

常用的预选策略(代码里的策略不一定都会被使用,Filtering-预选阶段)

常用的预选策略用途
CheckNodeConditionPred检查节点是否正常
GeneralPred HostName如果pod定义hostname属性,会检查节点是否匹配。(pod.spec.hostname)
PodFitsHostPorts检查pod要暴露的hostpors是否被占用。(pod.spec.containers.ports.hostPort)
MatchNodeSelector pod.spec.nodeSelector看节点标签能否适配pod定义的nodeSelector
PodFitsResources判断节点的资源能够满足Pod的定义(如果一个pod定义最少需要1C2G node上的低于此资源的将不被调度。用kubectl describe node NODE名称 可以查看资源使用情况)
NoDiskConflict判断pod定义的存储是否在node节点上使用。(默认没有启用)
PodToleratesNodeTaints检查pod上Tolerates的能否容忍污点(pod.spec.tolerations)
CheckNodeLabelPresence检查节点上的标志是否存在 (默认没有启动)
CheckServiceAffinity根据pod所属的service。将相同service上的pod尽量放到同一个节点(默认没有启动)
CheckVolumeBinding检查是否可以绑定(默认没有启动)
NoVolumeZoneConflict检volume区域是否冲突(默认没有启动)
CheckNodeMemoryPressure检查内存压力是否过大
CheckNodeDiskPressure检查磁盘IO压力是否过大
CheckNodePIDPressure检查pid资源是否过大

优选策略(scoring-打分阶段)

优选过滤器名说明
LeastRequestedPriority调度至请求较少、资源更空闲的节点上
BalancedResourceAllocation调度至资源平衡的节点
NodePreferAvoidPodsPriority通过scheduler.alpha.kubernetes.io/preferAvoidPods注释,避免pod间调度至同一个node节点
SelectorSpreadPriority标签优先级计算
InterPodAffinityPrioritypod亲和度计算
MostRequestedPriority调度至请求较多、资源更紧凑的节点上(尽量将一个节点上的资源用完)
RequestedToCapacityRatioPriority使用默认资源打分函数进行优选计算
NodeAffinityPrioritynode亲和度计算
TaintTolerationPriority根据节点上无法忍受的污点数量,为所有节点准备优先级列表
ImageLocalityPriority倾向于本地已有pod缓存的节点。(根据已有镜像体积大小之和)
ServiceSpreadingPriority对于给定服务,此策略旨在确保该服务的Pod在不同的节点上运行
CalculateAntiAffinityPriorityMap此策略有助于实现pod的反亲和力
EqualPriorityMap所有节点给定一个相同的权重

高级调度方式

当我们想把Pod调度到希望的节点上时,我们可以可以使用如下高级调度方式进行Pod调度:

  • 节点选择器: nodeSelector(Pod仅运行在能匹配到节点标签的主机上)、nodeName(Pod仅运行特定node)
  • 节点亲和性调度: nodeAffinity
  • Pod亲和性调度:PodAffinity
  • Pod反亲和性调度:podAntiAffinity
    注:可通过kubectl explain deployment.spec.template.spec.affinity查看

调度器说明:

  • nodeSelector:直接选定某个节点,选择性强,如果不存在匹配的node节点,pod将不会被调度
  • nodeAffinity:节点亲和性,主要控制pod要部署在哪些主机,以及pod不能部署在哪些主机上的问题,处理的是pod和主机之间的关系。
  • podAffinity/podAntiAffinity:主要控制pod可以和哪些pod部署在同一个拓扑域中的问题(拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的cluster、zone等)。podAntiAffinity和podAffinity它们都是处理Kubernetes集群内部pod和pod之间的关系。比如一个 pod 在一个节点上了,那么我这个pod也得部署在这个节点,或者你这个 pod 在节点上了,那么我这个pod就不想和你部署在同一个节点上。

三种亲和性策略的比较如下

策略名称匹配目标支持的操作符支持拓扑域设计目标
nodeAffinity主机标签In,NotIn,Exists,DoesNotExist,Gt,Lt不支持决定Pod可以部署在哪些主机上
podAffinityPod标签In,NotIn,Exists,DoesNotExist支持决定Pod可以和哪些Pod部署在同一拓扑域
PodAntiAffinityPod标签In,NotIn,Exists,DoesNotExist支持决定Pod不可以和哪些Pod部署在同一拓扑域
  • In:label 的值在某个列表中
  • NotIn:label 的值不在某个列表中
  • Gt:label 的值大于某个值
  • Lt:label 的值小于某个值
  • Exists:某个 label 存在(Values必须为空)
  • DoesNotExist:某个 label 不存在(Values必须为空)

示例

语法说明

使用命令 kubectl explain deployment.spec.template.spec.affinity可以查看语法格式,大致说明:
1)nodeAffinity
node亲和性,pod和node之间的亲和性,表示是否愿意调度到某个node上,其细分为以下两种:

  • 硬亲和性(required):使用requiredDuringSchedulingIgnoredDuringExecution字段定义,必须满足条件才会调度,否则Pod对象的状态会一直是Pending状态。
  • 软亲和性(preferred):使用preferredDuringSchedulingIgnoredDuringExecution字段定义,如果条件不满足,也会按一定的策略计算打分从中“尽量”的选择一个进行调度。

2)podAffinity
pod亲和性,pod和pod之间的亲和性,表示该pod愿意与其他pod调度到一个区域(可以是node、机架、也可以是机房)
3)podAntiAffinity
pod反亲和性,和podAffinity相反表示该pod不愿意与其他pod调度到一个区域。

podAffinity和podAntiAffinity也也可以细分为以下两种:

  • 硬亲和性(required):使用requiredDuringSchedulingIgnoredDuringExecution字段定义,必须满足条件才会调度,否则Pod对象的状态会一直是Pending状态。
  • 软亲和性(preferred):使用preferredDuringSchedulingIgnoredDuringExecution字段定义,如果条件不满足,也会按一定的策略计算打分从中“尽量”的选择一个进行调度。

使用场景

nodeAffinity使用场景:

  • 将某个服务的所有Pod部署到指定的符合标签规则的主机上。
  • 将某个服务的所有Pod部署到除部分主机外的其他主机上。

podAffinity使用场景:

  • 将某特定服务的pod部署在同一拓扑域中,不用指定具体的拓扑域。
  • 如果某服务和另一服务依赖性比较强,为了减少它们之间的网络延迟(或其它原因),就可以把=该服务的pod和另一服务的pod部署在同一拓扑域中。

podAntiAffinity使用场景:

  • 将某服务的pod分散在不同的主机或者拓扑域中,提高服务本身的稳定性。
  • 将某服务的pod单独部署到一个节点中来保证资源隔离,保证不会有其它pod来分享该节点资源。
  • 把可能会相互影响的服务的POD分散在不同的主机上。

NodeSelector

k8s中的节点默认自带一些标签,通过如下查看:

[root@k8s-m1 k8s-scheduler]# kubectl get nodes --show-labels 
NAME     STATUS   ROLES    AGE    VERSION    LABELS
k8s-m1   Ready    master   133d   v1.19.16   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-m1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-m2   Ready    master   133d   v1.19.16   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-m2,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-m3   Ready    master   133d   v1.19.16   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-m3,kubernetes.io/os=linux,node-role.kubernetes.io/master=
[root@k8s-m1 k8s-scheduler]# 

我们定义一个pod,让其选择带有kubernetes.io/hostname=k8s-m2这个标签的节点

[root@k8s-m1 k8s-scheduler]# cat node-selector-pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  containers:
  - name: myapp
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    kubernetes.io/hostname: k8s-m2
    
[root@k8s-m1 k8s-scheduler]# kubectl apply -f node-selector-pod.yml 
pod/nginx create

[root@k8s-m1 k8s-scheduler]# kubectl get pod -o wide
NAME                                   READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
nginx                                  1/1     Running   0          16s   10.244.81.170   k8s-m2   <none>           <none>
#定向调度到节点k8s-m2上

从上面的效果可以看出,设置了nodeSelector以后只会将Pod调度到符合标签的node1上,但是需要注意的是如果没有一个node满足nodeSelector的标签那么Pod会一直处于Pending状态直到有Node满足条件。

nodeAffinity

  • requiredDuringSchedulingIgnoredDuringExecution 硬亲和性 必须满足亲和性。
    • matchExpressions 匹配表达式,这个标签可以指定一段,例如pod中定义的key为kubernetes.io/hostname,operator为In(包含那些),values为 k8s-m2和k8s-m3。表示就是在节点中kubernetes.io/hostname的值为k8s-m2和k8s-m3的标签中调度
    • matchFields 匹配字段 和上面定义方式一样,不过他定义的不是标签值而是定义字段。
  • preferredDuringSchedulingIgnoredDuringExecution 软亲和性 能满足最好,不满足也没关系。
    • preference 配置节点选择器,与相应的权重相关联。
    • weight 权重1-100范围内,因为它是软性条件,所以并非一定要全匹配。在preference中匹配到的条目越多越符合条件。最后通过计算权重决定那个节点更符合条件。

硬亲和性:
硬亲和性,必须满足条件才能正常调度。

[root@k8s-m1 k8s-scheduler]# cat node-hard-affinity.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hard-affinity-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: my-nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:         #硬亲和
            nodeSelectorTerms:
            - matchExpressions:
               - key: kubernetes.io/hostname
                 operator: In
                 values: ["k8s-m2","k8s-m3"]
                                      
[root@k8s-m1 k8s-scheduler]# kubectl apply -f node-hard-affinity.yaml 
deployment.apps/hard-affinity-nginx created

[root@k8s-m1 k8s-scheduler]# kubectl get po -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
hard-affinity-nginx-d5cbfc49-g6gzj   1/1     Running   0          78s   10.244.81.163   k8s-m2   <none>           <none>
hard-affinity-nginx-d5cbfc49-p74ch   1/1     Running   0          56s   10.244.11.20    k8s-m3   <none>           <none>
# 通过上面结果发现两个pod分别分布在k8s-m2和k8s-m3上

软亲和性:
与requiredDuringSchedulingIgnoredDuringExecution比较,这里需要注意的是preferredDuringSchedulingIgnoredDuringExecution是个列表对象,而preference就是一个对象。

[root@k8s-m1 k8s-scheduler]# cat node-soft-affinity.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: soft-affinity-nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: my-nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 50
              preference:
                matchExpressions:
                   - key: kubernetes.io/hostname
                     operator: In
                     values: ["k8s-m4"]
##设置了一个不存在的节点

[root@k8s-m1 k8s-scheduler]# kubectl  apply  -f node-soft-affinity.yaml 
deployment.apps/soft-affinity-nginx created

[root@k8s-m1 k8s-scheduler]# kubectl get po -o wide
NAME                                   READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
soft-affinity-nginx-6cdb7b4899-z5bhw   1/1     Running   0          20s     10.244.11.63    k8s-m3   <none>           <none>
soft-affinity-nginx-6cdb7b4899-z72gd   1/1     Running   0          15s     10.244.81.167   k8s-m2   <none>           <none>
#通过结果发现,软亲和性的pod在节点不存在的情况下页能正常调度

podAffinity

Pod亲和性场景,我们的k8s集群的节点分布在不同的区域或者不同的机房,当服务A和服务B要求部署在同一个区域或者同一机房的时候,我们就需要使用亲和性调度。
podAffinity和NodeAffinity是一样的,都是有硬亲和性和软亲和性。

参数:

  • labelSelector 选择跟那组Pod亲和
  • namespaces 选择哪个命名空间
  • topologyKey 用来缩小节点选择范围,其值可以是任何合法的节点标签(key),在大规模集群中,为此字段不指定或者指定错误值,可能引发巨大的性能、安全问题。因此,对其使用有如下限制:
    • 对于Pod亲和与Pod硬性反亲和,topologyKey字段值不能为空。
    • 对于硬性反亲和,topoloygKey只能是kubernetes.io/hostname,除非禁止LimitPodHardAntiAffinityTopology允入控制器或者修改其实现。
    • 对于Pod软反亲和,允许topoloygKey为空,表示对节点拓扑没有限制。
    • 以上情况外,topologyKey可以是任何合法标签(key)。

硬亲和性:
由于我的集群都是虚拟机创建的节点,并没有划分区域或者机房,所以我这里直接使用主机名来作为拓扑域(topologyKey),把 pod 创建在同一个主机上面。

[root@k8s-m1 k8s-scheduler]# kubectl get node -o wide
NAME     STATUS   ROLES    AGE    VERSION    INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION              CONTAINER-RUNTIME
k8s-m1   Ready    master   133d   v1.19.16   192.168.2.140   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64       docker://19.3.15
k8s-m2   Ready    master   133d   v1.19.16   192.168.2.141   <none>        CentOS Linux 7 (Core)   3.10.0-957.el7.x86_64       docker://19.3.9
k8s-m3   Ready    master   133d   v1.19.16   192.168.2.142   <none>        CentOS Linux 7 (Core)   6.1.9-1.el7.elrepo.x86_64   docker://19.3.9

[root@k8s-m1 k8s-scheduler]# cat pod-affinity-pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity-pod1
  labels:
    name: podaffinity-nginx1
spec:
  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity-pod2
  labels:
spec:
  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: name
            operator: In
            values:
            - podaffinity-nginx1
        topologyKey: kubernetes.io/hostname

[root@k8s-m1 k8s-scheduler]# kubectl apply  -f pod-affinity-pod.yml 
pod/pod-affinity-pod1 created
pod/pod-affinity-pod2 created

[root@k8s-m1 k8s-scheduler]# kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
pod-affinity-pod1   1/1     Running   0          81s
pod-affinity-pod2   1/1     Running   0          81s

上面这个例子中的Pod pod-affinity-pod2需要调度到某个指定的主机上,至少有一个节点上运行了这样的 pod:这个 pod 有一个name=pod-affinity-pod1的 label

如果我们不部署上面的 node-affinity-pod1,然后重新创建 pod-affinity-pod2这个pod,看看能不能正常调度呢,先注释 node-affinity-pod1的相关yaml文件。

[root@k8s-m1 k8s-scheduler]# kubectl apply  -f pod-affinity-pod.yml 
pod/pod-affinity-pod2 created
[root@k8s-m1 k8s-scheduler]# kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
pod-affinity-pod2   0/1     Pending   0          3s
[root@k8s-m1 k8s-scheduler]# kubectl get pod
NAME                READY   STATUS    RESTARTS   AGE
pod-affinity-pod2   0/1     Pending   0          5s
[root@k8s-m1 k8s-scheduler]# kubectl describe po pod-affinity-pod2 
Name:         pod-affinity-pod2
Namespace:    default
Priority:     0
Node:         <none>
Labels:       <none>
Annotations:  <none>
Status:       Pending
IP:           
IPs:          <none>
Containers:
  myapp:
    Image:        nginx:latest
    Port:         <none>
    Host Port:    <none>
    Environment:  <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-glxls (ro)
Conditions:
  Type           Status
  PodScheduled   False 
Volumes:
  default-token-glxls:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-glxls
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  5s (x2 over 5s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't match pod affinity rules, 3 node(s) didn't match pod affinity/anti-affinity.

可以看到pod-affinity-pod2处于Pending状态了,这是因为现在没有一个节点上面拥有name=pod-affinity-pod1这个 label 的 pod,而上面我们的调度使用的是硬策略,所以就没办法进行调度了,也可以去尝试下重新将pod-affinity-pod1 这个 pod 调度到 某个具体节点上,看看上面的 pod-affinity-pod2会不会也被调度到 相同节点上去?

[root@k8s-m1 k8s-scheduler]# cat pod-affinity-pod.yml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity-pod1
  labels:
    name: podaffinity-nginx1
spec:
  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
  nodeSelector:
    kubernetes.io/hostname: k8s-m3
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-affinity-pod2
  labels:
spec:
  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: name
            operator: In
            values:
            - podaffinity-nginx1
        topologyKey: kubernetes.io/hostname

[root@k8s-m1 k8s-scheduler]# kubectl apply  -f pod-affinity-pod.yml 
pod/pod-affinity-pod1 created
pod/pod-affinity-pod2 configured

[root@k8s-m1 k8s-scheduler]# kubectl get po -o wide
NAME                READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
pod-affinity-pod1   1/1     Running   0          51s     10.244.11.7    k8s-m3   <none>           <none>
pod-affinity-pod2   1/1     Running   0          5m28s   10.244.11.22   k8s-m3   <none>           <none>

我们这个地方使用的是kubernetes.io/hostname这个拓扑域,意思就是我们当前调度的 pod 要和目标的 pod 处于同一个主机上面,因为要处于同一个拓扑域下面kubernetes.io/hostname=k8s-m3中,为了说明这个问题,我们把拓扑域改成beta.kubernetes.io/os,同样的我们当前调度的 pod 要和目标的 pod 处于同一个拓扑域中,目标的 pod 是不是拥有beta.kubernetes.io/os=linux的标签,而我们这里3个节点都有这样的标签,这也就意味着我们3个节点都在同一个拓扑域中,所以我们这里的 pod 可能会被调度到任何一个节点(因为master的污点被清除了,所以和普通节点一样都可以调度),判断他们是否在同一拓扑域中是根据topologyKey中指定的node标签的values是否相同,如果相同则表示在同一拓扑域中。软亲和性类似,关键字为preferredDuringSchedulingIgnoredDuringExecution请大家自行测试使用。

podAntiAffinity

和Pod亲和性的用法类似,只是podAntiAffinity是反着来的。比如一个节点上运行了某个应用服务pod,那么我们的redis服务pod则尽量不要在同一台节点上,这就是反亲和性。podAntiAffinity和上面两个策略也是有硬亲和性和软亲和性两种不同用法;

硬亲和性:

[root@k8s-m1 k8s-scheduler]# cat pod-antiaffinity-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-antiaffinity-pod1
  labels:
    name: podantiaffinity-nginx
    tier: service
spec:
  containers:
  - name: myapp
    image: nginx:latest
    imagePullPolicy: IfNotPresent
  nodeSelector:
    kubernetes.io/hostname: k8s-m2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: antiaffinity-nginx
  labels:
    app: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
     containers:
     - name: myapp
       image: nginx:latest
       imagePullPolicy: IfNotPresent
     affinity:
       podAntiAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           - labelSelector:
               matchExpressions:
                 - key: name
                   operator: In
                   values: ["podantiaffinity-nginx"]
             topologyKey: kubernetes.io/hostname

[root@k8s-m1 k8s-scheduler]# kubectl apply  -f pod-antiaffinity-pod.yaml 
pod/pod-antiaffinity-pod1 created
deployment.apps/antiaffinity-nginx created

这里的意思就是如果一个节点上面有一个podantiaffinity-nginx这样的 pod 的话,那么我们的pod 就不能调度到这个节点上面来,上面我们把podantiaffinity-nginx这个 pod 固定到了 k8s-m2这个节点上面来,所以正常来说我们这里的 pod 不会出现在 k8s-m2 节点上:

[root@k8s-m1 k8s-scheduler]# kubectl get pod -o wide
NAME                                  READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
antiaffinity-nginx-769b467cf4-4qkh6   1/1     Running   0          75s   10.244.42.189   k8s-m1   <none>           <none>
antiaffinity-nginx-769b467cf4-6qthb   1/1     Running   0          75s   10.244.11.25    k8s-m3   <none>           <none>
antiaffinity-nginx-769b467cf4-7ppbj   1/1     Running   0          75s   10.244.42.130   k8s-m1   <none>           <none>
pod-antiaffinity-pod1                 1/1     Running   0          75s   10.244.81.179   k8s-m2   <none>           <none>

更实际的用例

在三个节点集群中,web应用程序需要使用redis做缓存,比如redis。我们希望web服务器尽可能与redis共存。
下面的yaml文件是部署一个简单的redis,其中包含三个副本和label标签app=store。还配置了PodAntiAffinity,以确保调度器不会在单个节点上同时调度多个副本。

[root@k8s-m1 k8s-scheduler]# cat redis-podaffinity.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-cache
spec:
  selector:
    matchLabels:
      app: redis
  replicas: 3
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - redis
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: redis-server
        image: redis:5.0.14-alpine

下面是web服务器部署的yaml文件配置了podAntiAffinity和podAffinity。这将通知调度器,它的所有副本都将与具有选择器标签app=redis的pod共存。这还将确保每个web服务器副本不会同时位于单个节点上。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-server
spec:
  selector:
    matchLabels:
      app: nginx-server
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx-server
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - nginx-server
            topologyKey: "kubernetes.io/hostname"
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - redis
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: web-app
        image: nginx:1.22.1-alpine

如果我们创建上面的两个部署,我们集群中的3个节点上每个节点都有一个nginx-server和redis服务。如下:

[root@k8s-m1 k8s-scheduler]# kubectl get po -o wide
NAME                           READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
redis-cache-64d4c5fbd6-mhxzl   1/1     Running   0          6m22s   10.244.81.144   k8s-m2   <none>           <none>
redis-cache-64d4c5fbd6-qh82v   1/1     Running   0          6m23s   10.244.42.167   k8s-m1   <none>           <none>
redis-cache-64d4c5fbd6-sfw6s   1/1     Running   0          6m22s   10.244.11.29    k8s-m3   <none>           <none>
web-server-7f965dcbcc-crsd9    1/1     Running   0          2m9s    10.244.81.151   k8s-m2   <none>           <none>
web-server-7f965dcbcc-rsmhr    1/1     Running   0          2m9s    10.244.42.190   k8s-m1   <none>           <none>
web-server-7f965dcbcc-tblsz    1/1     Running   0          2m9s    10.244.11.14    k8s-m3   <none>           <none>

上面的例子使用PodAntiAffinity规则和topologyKey: "kubernetes.io/hostname"配合使用来部署redis集群,使其同一主机上不存在两个实例;而在实际工作中,我们的集群节点一般都是都以hostname来划分拓扑域。

最后注意,亲和性设置中多个key之间的关系是与关系(and),而matchExpressions之间的关系是是或关系(or),但实际使用中我们也不会设置太复杂。

更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/38672.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI智能助手的未来:与人类互动的下一代人工智能技术

自我介绍⛵ &#x1f4e3;我是秋说&#xff0c;研究人工智能、大数据等前沿技术&#xff0c;传递Java、Python等语言知识。 &#x1f649;主页链接&#xff1a;秋说的博客 &#x1f4c6; 学习专栏推荐&#xff1a;人工智能&#xff1a;创新无限、MySQL进阶之路、C刷题集、网络安…

WEB APIs day4 (1)

一、日期对象 1.实例化 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…

数据结构——六大排序 (插入,选择,希尔,冒泡,堆,快速排序)

1. 插入排序 1.1基本思路 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 我们熟知的斗地主就是一个插入排序 1.2 代码实现 我们这里将一个无序数组变成有序数组 插入排序时…

antd-React Table 中文转化

1.首先需要进行中文包导入 2.引入标签对Table进行包裹即可 import zh_CN from antd/lib/locale-provider/zh_CN;import {ConfigProvider} from antd;<ConfigProvider locale{zh_CN}><Tablecolumns{columns}rowKey{record > record.id}dataSource{data}pagination{p…

SQL进阶(2)——SQL语句类型 增删改查CRUD 事务初步 表关联关系 视图 +索引

目录 引出SQL语句类型1.DML数据操纵语言&#xff08;重点&#xff09;2.DQL数据查询语言&#xff08;重点&#xff09;3.DDL(Data Definition Language了解)4.DCL(Data Control Language了解)5.TCL 事务控制语言 运算符和其他函数1.运算符2.其它函数增删改查CRUD 视图索引事务1…

如何克服Leetcode做题的困境

文章目录 如何克服Leetcode做题的困境问题背景克服困境的建议实践与理论结合切忌死记硬背分析解题思路不要过早看答案迭代式学习寻求帮助坚持与耐心查漏补缺 结论 如何克服Leetcode做题的困境 问题背景 明明自觉学会了不少知识&#xff0c;可真正开始做Leetcode题目时&#x…

基于单片机的恒温恒湿温室大棚温湿度控制系统的设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;液晶显示当前温湿度按键设置温湿度报警上限和下限&#xff1b;温度低于下限继电器闭合加热片进行加热&#xff1b;温度超过上限继电器闭合开启风扇进行降温湿度低于下限继电器闭合加湿器进行加湿湿度高于上限继电器闭合开启风扇进行…

JavaWeb(3)——HTML、CSS、JS 快速入门

一、JavaScript 运算符 • 赋值运算符&#xff08; &#xff09; 赋值运算符执行过程&#xff1f; 将等号右边的值赋予给左边, 要求左边必须是一个容器 出现是为了简化代码, 比如让 let age 18 &#xff0c;age 加 2 怎么写呢 let age 18age 2console.log(age)age * 2con…

苹果APP安装包ipa如何安装在手机上

苹果APP安装包ipa如何安装在手机上 苹果APP的安装比安卓复杂且困难&#xff0c;很多人不知道如何将ipa文件安装到手机上。以下是几种苹果APP安装在iOS设备的方式&#xff0c;供大家参考。 一、上架App Store 这是最正规的方式。虽然审核过程复杂、时间较长&#xff0c;且审核…

关于电脑显示器屏幕看不出灰色,灰色和白色几乎一样无法区分,色彩调整方法

问题&#xff1a; 电脑显示器屏幕看不出灰色&#xff0c;灰色和白色几乎一样无法区分。白色和灰色有色差。 解决方法&#xff1a; 打开“控制面板” ->“色彩管理” ->“高级” ->“校正显示器” 在下一步调节中调成中间这一个实例的样子就可以了 进行微调&#x…

基于linux下的高并发服务器开发(第二章)- 2.9 waitpid 函数

#include <sys/types.h> #include <sys/wait.h>pid_t waitpid(pid_t pid, int *wstatus, int options); 功能&#xff1a;回收指定进程号的子进程&#xff0c;可以设置是否阻塞。 参数&#xff1a; - pid: pid > 0…

小白到运维工程师的自学之路 第五十四集 (ansible自动化运维工具)

一、概述 Ansible是一种开源的自动化工具&#xff0c;用于自动化任务的执行、配置管理和应用部署。它采用基于Python编写的简单、轻量级的语法&#xff0c;可以通过SSH协议远程管理和配置多台计算机。 Ansible的主要特点包括&#xff1a; 1、简单易用&#xff1a;设计简单&a…

(33)接收信号强度指示(RSSI)

文章目录 前言 33.1 在你的自动驾驶仪上设置RSSI 33.2 在MissionPlanner的HUD中显示RC接收器的RSSI值 33.3 连接实例 33.4 特殊用例 前言 本文介绍了如何获取自动驾驶仪的接收信号强度指示&#xff08;RSSI&#xff09;。 33.1 在你的自动驾驶仪上设置RSSI RSSI 可通过一…

ChatGPT变现五个思路

一、前言 ChatGPT是一款AI聊天机器人&#xff0c;发布于2022年11月。凭借着在广泛的知识领域为消费者问题做出清晰、详尽解答的出色能力&#xff0c;其一经推出就引发全球轰动&#xff0c;自然也得到零售行业的高度关注。例如&#xff0c;消费者只要询问ChatGPT如何布置一个梦…

flink1.16读取hive数据存到es 本地和服务器上遇到的问题和解决思路

话不多说 直接上官网 Overview | Apache Flink hive版本 3.1.3000 ​ hadoop 版本 3.1.1.7.1.7 ​ flink 1.16.2 ​ 代码 很简单我还是贴下 import com.fasterxml.jackson.databind.ObjectMapper import com.typesafe.config.{Config, ConfigFactory} import org.apache…

Redis可视化工具 - Another Redis Desktop Manager 安装与使用详细步骤

一、下载安装 Another Redis Desktop Manager AnotherRedisDesktopManager 发行版 - Gitee.com&#xff08;gitee&#xff09; 2. 安装 以管理员身份运行下载的安装包 选择是为所有用户还是当前用户安装&#xff0c;按需选择 选择安装位置&#xff0c;点击安装进行安装 安装…

Unity UnityWebRequest使用http与web服务器通讯

一、搭建客户端与服务器http通讯 1.在Nodejs中文官网Node.js 中文网 (nodejs.com.cn)&#xff0c;下载并安装Nodejs 2.在项目文件夹下新建WebServer文件夹&#xff0c;打开CMD窗口&#xff0c;在WebServer文件夹路径下安装express 3.在WebServer文件夹中新建main.js文件&#…

Unity游戏源码分享-迷你高尔夫球游戏MiniGolfConstructionKitv1.1

Unity游戏源码分享-迷你高尔夫球游戏MiniGolfConstructionKitv1.1 有多个游戏关卡 工程地址&#xff1a;https://download.csdn.net/download/Highning0007/88052881

安全中级11:sql注入+联合、报错、时间盲注+sqlmap使用

目录 一、sql注入原理 二、联合SQL注入的方法 1.总体的思路 &#xff08;1&#xff09;先进行闭合&#xff0c;进行报错 &#xff08;2&#xff09;进行逃逸 &#xff08;3&#xff09;外带数据 &#xff08;4&#xff09;获取库名 表名 列名 数据 &#xff08;5&#…

自动驾驶商用驶入“快车道”,汽车软件厂商如何“抢市”?

L3级及以上自动驾驶的商业化进程正在驶入“快车道”。 一方面&#xff0c;高阶自动驾驶的相关法规及标准不断出台&#xff0c;为自动驾驶行业的发展注入了“强心剂”。 比如工业和信息化部副部长辛国斌就曾表示&#xff0c;将启动智能网联汽车准入和上路通行试点&#xff0c;…