Docker&Kubernetes ❀ Kubernetes集群Pod调度方式资源配置清单

Posted 无糖可乐没有灵魂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker&Kubernetes ❀ Kubernetes集群Pod调度方式资源配置清单相关的知识,希望对你有一定的参考价值。

文章目录

1、调度方式产生背景


默认情况下,一个Pod在那个节点上运行是由Scheduler组件采用相应的算法计算出来的,这个过程是不应该受到人工控制的,但是在实际使用环境中,这并不能满足现在的需求,因为较多情况下,需要根据控制某些Pod执行到某些节点上就需要了解KUbernetes对Pod的调度规则,Kubernetes目前提供了四种调度方式:

  • 自动调度:运行在那个节点上完全由Scheduler经过一些列的计算得出;
  • 定向调度:NodeName、NodeSelector;
  • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity;
  • 污点与容忍:Taints、Toleration

2、定向调度


定向调度,指的是利用在Pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上,注意这里的调度是强制性的,这就意味这即便调度目标node不存在,也会调度成功,只不过pod运行失败而已;

2.1 NodeName

NodeName用于强制约束将Pod调度到指定Name的node上,这种调度方式直接跳过了Scheduler组件的逻辑调度,直接写入PodList列表中,该匹配规则是强制约束;

#创建YAML文件
[root@master ~]# vim pod-nodename.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
  nodeName: node2.kubernetes          #调度到node2
#调用YAML文件
[root@master ~]# kubectl apply -f pod-nodename.yaml 
pod/pod-nodename created

#查看Pod调度Node
[root@master ~]# kubectl get pods -n dev -owide
NAME               READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
pod-nodeselector   1/1     Running   0          64s   10.244.80.81   node2.kubernetes   <none>           <none>

2.2 NodeSelector

NodeSelector用于将Pod调度到了指定标签的node节点上,它是通过Kubernetes的label-selector机制来实现的,也就是说需要在Pod创建之前由Scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将Pod调度到目标node上,该匹配规则也是强制约束;

#分别给node配置label
[root@master ~]# kubectl label nodes node1.kubernetes nodeenv=pro
node/node1.kubernetes labeled
[root@master ~]# kubectl label nodes node2.kubernetes nodeenv=test
node/node2.kubernetes labeled

#查看所配置的label
[root@master ~]# kubectl get nodes --show-labels
NAME                STATUS   ROLES                  AGE   VERSION   LABELS
master.kubernetes   Ready    control-plane,master   13d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master.kubernetes,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
node1.kubernetes    Ready    <none>                 13d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1.kubernetes,kubernetes.io/os=linux,nodeenv=pro
node2.kubernetes    Ready    <none>                 13d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2.kubernetes,kubernetes.io/os=linux,nodeenv=test
#创建YAML文件
[root@master ~]# vim pod-nodeselector.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
    ports:
    - name: nginx-port
      containerPort: 80
  nodeSelector:
    nodeenv: pro        #指定调度到具有nodeenv=pro标签的节点上
#调用YAML文件
[root@master ~]# kubectl apply -f pod-nodeselector.yaml 
pod/pod-nodeselector created

#查看调度节点是否为node1(node1的label为pro)
[root@master ~]# kubectl get pods -n dev -owide
NAME               READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
pod-nodeselector   1/1     Running   0          64s   10.244.80.81   node1.kubernetes   <none>           <none>

#修改调度label为其他值
[root@master ~]# kubectl delete -f pod-nodeselector.yaml 
pod "pod-nodeselector" deleted

[root@master ~]# cat pod-nodeselector.yaml | grep nodeenv
    nodeenv: pro1
[root@master ~]# kubectl apply -f pod-nodeselector.yaml 
pod/pod-nodeselector created

#查看Pod状态是否为Running
[root@master ~]# kubectl get pod -n dev
NAME               READY   STATUS    RESTARTS   AGE
pod-nodeselector   0/1     Pending   0          9s

#查看报错原因
[root@master ~]# kubectl describe pod pod-nodeselector -n dev
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  41s   default-scheduler  0/3 nodes are available: 1 node(s) had taint node-role.kubernetes.io/master: , that the pod didn't tolerate, 2 node(s) didn't match Pod's node affinity/selector.
#默认情况下scheduler会将master也算作一个node节点,因此会显示default-scheduler 0/3 nodes

3、亲和性调度


上面介绍了两种定向调度的方式,使用起来非常方便,但是也有一定的问题,那就是如果没有满足条件的Node,那么Pod将不会被运行,即使在集群中还有可用Node列表也不行,这就是限制了它的使用场景;基于上面的问题,Kubernetes还提供了一种亲和性调度(Affinity),它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足的节点上,使调度更加灵活;

亲和性主要分为三类:

  • nodeAffinity(node亲和性):以node为目标,解决pod可以调度到哪些node的问题;
  • podAffinity(pod亲和性):以pod为目标,解决pod可以和哪些已存在的pod部署在同一拓扑中的问题;
  • podAntiAffinity(pod反亲和性):以pod为目标,解决pod不能和哪些已存在pod部署在同一个拓扑域中的问题;

调用规则主要分为两类:

  • 亲和性:如果两个应用频繁交互,那么就有必要使用亲和性让两个应用尽可能的靠近,这样就可以减少因网络通信而带来的性能损耗;
  • 反亲和性:当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性;

3.1 NodeAffinity

下面为NodeAffinity Node的相关配置内容:

spec:
  affinity:                      #亲和性配置
    nodeAffinity:                #Node亲和性
      requiredDuringSchedulingIgnoredDuringExecution:       #Node节点必须满足指定规则才可以调度,硬限制
        nodeSelectorTerms:       #节点选择列表
          matchFields:           #按照节点字段列出的节点选择器要求列表
            key:                 #键
            values:              #值(包含与不包含的关系符号配置后即不需要配置value,只作用于key)
            operator: In,NotIn,Exists,DoesNotExist.Gt,Lt    #关系符,选择内容分别为:在...里面,不在...里面,包含,不包含.大于/小于
          matchExpressions:     #按照节点标签列出的节点选择器要求列表(推荐使用)
            key:
            values:
            operator: In,NotIn,Exists,DoesNotExist.Gt,Lt
      preferredDuringSchedulingIgnoredDuringExecution:      #Pod节点优先调度到指定规则的Node上,软限制(推荐使用)
        preference:             #一个节点选择器项,与相应的权重值互相关联
          matchFields:
          matchExpressions:
            key:
            values:
            operator: In,NotIn,Exists,DoesNotExist.Gt,Lt
          matchFields:
        weight:                  #权重值,范围在1-100之间,定义不同Node的权重值
    podAffinity:                 #Pod亲和性
    podAntiAffinity:             #Pod反亲和性

关系符号使用说明:

          matchExpressions:
          - key: nodedev
            operator: Exists         #匹配标签的key为nodeenv的所有节点
          - key: nodedev
            operator: In
            values: ["xxx","yyy"]    #匹配标签的key为nodeenv,值为xxx或yyy的节点
          - key: nodedev
            operator: Gt
            values: "xxx"            #匹配标签的key为nodeenv,值大于xxx的节点

3.1.1 Required 硬限制

#创建YAML文件
[root@master ~]# cat pod-node-affinity-required.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:  #硬限制
        nodeSelectorTerms:
        - matchExpressions:     #匹配key为nodeenv,值为xxx或yyy的Node节点
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
#调用YAML文件
[root@master ~]# kubectl create -f pod-node-affinity-required.yaml 
pod/pod-node-affinity-required created

#查看Pod创建状态
[root@master ~]# kubectl get pod -n dev -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-node-affinity-required   0/1     Pending   0          64s   <none>   <none>   <none>           <none>

#Pod状态为Pending,查看告警日志信息
[root@master ~]# kubectl describe pod pod-node-affinity-required -n dev
Events:
  Type     Reason            Age                  From               Message
  ----     ------            ----                 ----               -------
  Warning  FailedScheduling  28s (x3 over 2m37s)  default-scheduler  0/3 nodes are available: 1 node(s) had taint node-role.kubernetes.io/master: , that the pod didn't tolerate, 2 node(s) didn't match Pod's node affinity/selector.				#由于未匹配key为nodeenv,值为xxx或yyy的Node节点,因此调度失败(硬限制)

#删除Pod
[root@master ~]# kubectl delete -f pod-node-affinity-required.yaml 
pod "pod-node-affinity-required" deleted
#给node1 与node2分别打上pro、test标签
[root@master ~]# kubectl label node node1.k8s nodeenv=pro 
node/node1.k8s labeled
[root@master ~]# kubectl label node node2.k8s nodeenv=test
node/node2.k8s labeled

#查看Node标签
[root@master ~]# kubectl get node --show-labels
NAME         STATUS   ROLES                  AGE   VERSION   LABELS
master.k8s   Ready    control-plane,master   22d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master.k8s,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
node1.k8s    Ready    <none>                 22d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1.k8s,kubernetes.io/os=linux,nodeenv=pro
node2.k8s    Ready    <none>                 22d   v1.23.0   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2.k8s,kubernetes.io/os=linux,nodeenv=test

#将values: ["xxx","yyy"]修改为 values: ["pro","yyy"]
[root@master ~]# cat $_ | grep -w values
            values: ["pro","yyy"]

#再次调用YAML文件
[root@master ~]# kubectl create -f pod-node-affinity-required.yaml 
pod/pod-node-affinity-required created

#查看Pod调用是否在pro的Node1上
[root@master ~]# kubectl get pod -n dev -o wide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
pod-node-affinity-required   1/1     Running   0          2m   10.244.112.20   node1.k8s   <none>           <none>

3.1.2 Preferred 软限制

#创建YAML文件
[root@master ~]# cat pod-node-affinity-preferred.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-node-affinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:   #软限制
      - preference:
          matchExpressions:     #匹配key为nodeenv,值为xxx或yyy的Node节点(当前环境无此Node)
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
        weight: 1
#调用YAML文件
[root@master ~]# kubectl apply -f pod-node-affinity-preferred.yaml 
pod/pod-node-affinity-preferred created

#查看Pod状态
[root@master ~]# kubectl get pod -n dev -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES
pod-node-affinity-preferred   1/1     Running   0          52s   10.244.112.21   node1.k8s   <none>           <none>

3.1.3 注意事项

  • 如果同时定义了nodeSelector(定向调度)和nodeAffinity(亲和性调度),那么必须两个条件都得到满足,Pod才能运行在指定的node上;
  • 如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可;
  • 如果一个nodeSelectorTerms中有多个matchExpressions,则一个节点必须满足所有的才能匹配成功;
  • 如果一个Pod所在的Node在Pod运行期间其标签发生了变化,不再符合该Pod的节点亲和性需求,则系统将忽略此变化;

3.2 PodAffinity

podAffinity主要实现以运行Pod为参照,实现让创建的Pod跟参照Pod在一个区域的功能;
下面为podAffinity的相关配置内容:

spec:
  affinity:                       #亲和性配置
    nodeAffinity:                 #Node亲和性
    podAffinity:                  #Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution:        #Node节点必须满足指定规则才可以调度,硬限制
        namespace:                #指定参照Pod的命名空间
        topologyKey:              #指定调度作用域
        labelSelector:            #标签选择器
          matchExpressions:       #按照节点标签列出的节点选择器要求列表(推荐使用)
            key:                 #键
            values:              #值(包含与不包含的关系符号配置后即不需要配置value,只作用于key)
            operator: In,NotIn,Exists,DoesNotExist.Gt,Lt     #关系符号
          matchLabels:           #指定多个matchExpressions的映射内容
      preferredDuringSchedulingIgnoredDuringExecution:       #Pod节点优先调度到指定规则的Node上,软限制(推荐使用)
        podAffinityTerm:         #一个Pod选择器,与相应的权重值互相关联
          namespace:
          topologyKey:
          labelSelector:
            matchExpressions:
              key:
              values:
              operator:
            matchLabels:
        weight:                  #权重值,范围在1-100之间
    podAntiAffinity:             #Pod反亲和性

topologyKey用于指定调度时作用域,如下

  • 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围;
  • 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分;

3.2.1 测试环境准备

此参照Pod只是为了完成podAffinity与podAntiAffinity实验而创建,无其他实际意义;

#创建一个参照Pod,标签为podenv=pod
[root@master ~]# cat pod-pod-affinity-target.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-pod-affinity-target
  namespace: dev
  labels:
    podenv: pro             #设置标签
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: node1.k8s       #将Pod分发在node1上
#调用YAML文件
[root@master ~]# kubectl apply -f pod-pod-affinity-target.yaml 
pod/pod-pod-affinity-target created

#查看Pod部署Node与标签信息
[root@master ~]# kubectl get pod -n dev --show-labels -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE        NOMINATED NODE   READINESS GATES   LABELS
pod-pod-affinity-target   1/1     Running   0          65s   10.244.112.23   node1.k8s   <none>           <none>            podenv=pro

3.2.2 Required 硬限制

#创建YAML文件
[root@master ~]# cat pod-pod-affinity-required.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-pod-affinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:     #硬限制
      - labelSelector:                     #标签选择器
          matchExpressions:                #按照节点标签列出的节点选择器选择对应Node
          - key: podenv                    #匹配key为nodeenv,值为xxx或yyy的Pod所在的节点
            operator: In
            values: ["xxx","yyy"]
        topologyKey: kubernetes.io/hostname               #以Node为区分范围
#调用YAML文件
[root@master ~]# kubectl apply -f pod-pod-affinity-required.yaml 
pod/pod-pod-affinity-required created

#查看Pod状态
[root@master ~]# kubectl get pod -n dev -o wide
NAME                        READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-pod-affinity-required   0/1     Pending   0          65s   <none>   <none>   <none>           <none>

#查看告警信息
[root@master ~]# kubectl describe pod pod-pod-affinity-required -n dev
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  88s   default-scheduler  0/3 nodes are available: 1 node(s) had taint node-role.kubernetes.io/master: , that the pod didn't tolerate, 2 node(s) didn't match pod affinity rules.

#删除Pod
[root@master ~]# kubectl delete -f pod-pod-affinity-required.yaml 
pod "pod-pod-affinity-required" deleted
#更改YAML文件中values: ["xxx","yyy"]为values: ["pod","yyy"]
[root@master ~]# cat $_ | grep -w values
            values: ["pod","yyy"]
[root@master ~]# 

#再次调用YAML文件
[root@master ~]# kubectl apply -f pod-pod-affinity-required.yaml 
pod/pod-pod-affinity-required created

#查看创建结果
[root@master ~]# kubectl get pod -n dev --show-labels -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES   LABELS
pod-pod-affinity-required   1/1     Running   0          14s     10.244.112.24   node1.k8s   <none>           <none>            <none>
pod-pod-affinity-target     1/1     Running   0          2m30s   10.244.112.23   node1.k8s   <none>           <none>            podenv=pro

#删除硬限制Pod
[root@master ~]# kubectl delete -f pod-pod-affinity-required.yaml 
pod "pod-pod-affinity-required" deleted

3.2.3 Preferred 软限制

#创建YAML文件
[root@master ~]# cat pod-pod-affinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-pod-affinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:     #软限制
      - podAffinityTerm:             
          topologyKey: kubernetes.io/hostname              #以Node为区分范围
          labelSelector:
            matchExpressions:                #按照节点标签列出的节点选择器选择对应Node
            - key: podenv                    #匹配key为nodeenv,值为xxx或yyy的Pod所在的节点
              operator: In
              values: ["pod","yyy"]
        weight: 1
#调用YAML文件
[root@master ~]# kubectl apply -f pod-pod-affinity-preferred.yaml 
pod/pod-pod-affinity-preferred created

#查看Pod状态
[root@master ~]# kubectl get pod -n dev -owide
NAME                         READY   STATUS    RESTARTS   AGE    IP              NODE        NOMINATED NODE   READINESS GATES
pod-pod-affinity-preferred   1/1     Running   0          95s    10.244.112.25   node1.k8s   <none>           <none>

3.3 PodAntiAffinity

PodAntiAffinity与PodAffinity是一样的,配置参数不做赘述;
(反亲和性创建的新Pod需要与匹配到的Pod分布在不同的Node上)

3.3.1 Required 硬限制

#创建YAML文件
[root@master ~]# cat pod-podantiaffinity-required.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    podAntiAffinity:                  #反亲和性
      requiredDuringSchedulingIgnoredDuringExecution:     #硬限制
      - labelSelector:
          matchExpressions:           #匹配key为podenv,值为pro的pod
          - key: podenv
            operator: In
            values: ["pro"]            
        topologyKey: kubernetes.io/hostname    
#调用YAML文件
[root@master ~]# kubectl apply -f pod-podantiaffinity-required.yaml 
pod/pod-podantiaffinity-required created

#查看Pod调度在Node2节点上
[root@master ~]# kubectl get pod -n dev -o wide
NAME                           READY   STATUS    RESTARTS   AGE    IP               NODE        NOMINATED NODE   READINESS GATES
pod-pod-affinity-target        1/1     Running   0          6m6s   10.244.112.26    node1.k8s   <none>           <none>
pod-podantiaffinity-required   1/1     Running   0          85s    10.244.166.146   node2.k8s   <none>           <none>

3.3.2 Preferred 软限制

#创建YAML文件
[root@master ~]# cat pod-podantiaffinity-preferred.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    podAntiAffinity:                  #反亲和性
      preferredDuringSchedulingIgnoredDuringExecution:     #软限制
      - podAffinityTerm:
          topologyKey: kubernetes.io/hostname              #以Node为区分范围
          labelSelector:
            matchExpressions:                #按照节点标签列出的节点选择器选择对应Node
            - key: podenv                    #匹配key为nodeenv,值为xxx或yyy的Pod所在的节点
              operator: In
              values: ["pro","yyy"]
        weight: 1
#调用YAML文件
[root@master ~]# kubectl apply -f pod-podantiaffinity-preferred.yaml 
pod/pod-podantiaffinity-preferred created

#查看Pod调度在Node2节点上
[root@master ~]# kubectl get pod -n dev -owide
NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
pod-pod-affinity-target         1/1     Running   0          12m     10.244.112.26    node1.k8s   <none>           <none>
pod-podantiaffinity-preferred   1/1     Running   0          45s     10.244.166.147   node2.k8s   <none>           <none>

4、污点与容忍


在前面的告警内容中出现了污点 taint,此章节即讲解污点与容忍在Kubernetes中的作用;

Message:0/3 nodes are available: 1 node(s) had taint node-role.kubernetes.io/master: , that the pod didn't tolerate, 2 node(s) didn't match pod affinity rules.

Kubernetes默认情况下会给master所在节点配置一个NoSchedule的污点

以上是关于Docker&Kubernetes ❀ Kubernetes集群Pod调度方式资源配置清单的主要内容,如果未能解决你的问题,请参考以下文章

Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法

Docker&Kubernetes ❀ Kubernetes集群安装部署过程与常见的错误解决方法

Docker&Kubernetes ❀ Kubernetes集群实践与部署笔记知识点梳理

Docker&Kubernetes ❀ Docker 容器技术笔记链接梳理

Docker&Kubernetes ❀ Kubernetes集群Pod控制器 - Job

Docker&Kubernetes ❀ Kubernetes集群Service资源配置清单