0
点赞
收藏
分享

微信扫一扫

k8s调度策略

k8s调度策略

我们在创建pod资源的时候,pod会根据schduler进行调度,那么默认会调度到随机的一个工作节点,如果我们想要pod调度到指定节点或者调度到一些具有相同特点的节点,应该怎么办呢?下面介绍k8s中的调度策略,主要有以下调度策略:

  • 节点选择器调度

  • 节点亲和调度
  • pod亲和调度
  • pod反亲和调度
  • 污点-容忍度调度

节点选择器

nodeName

通过指定节点名称,把pod调度到指定节点,下面的pod将会被调度到k8s-node01节点。

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: default
  labels:
    app: nginx
spec:
  nodeName: k8s-node01
  containers:
  - name: nginx
    image: nginx:1.21.5
    imagePullPolicy: IfNotPresent

pod创建成功后,通过kubectl get pod -o wide发现被调度到了k8s-node01节点。

NAME           READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod-nodename   1/1     Running   0          5s    10.81.85.226   k8s-node01   <none>           <none>

nodeSelector

首先给k8s-node02节点添加一个标签type=nginx

#给节点添加标签
kubectl label node k8s-node02 type=nginx
#查看节点-显示标签
kubectl get node --show-labels

创建pod并将该pod调度到标签为type=nginx的节点上

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: default
  labels:
    app: nginx
spec:
  nodeSelector: 
    type: nginx
  containers:
  - name: nginx
    image: nginx:1.21.5
    imagePullPolicy: IfNotPresent

pod创建成功后,通过kubectl get pod -o wide查看pod状态,如下所示pod被成功调度到k8s-node02节点。

NAME           READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod-nodename   1/1     Running   0          9s    10.81.58.214   k8s-node02   <none>           <none>

节点亲和性

节点亲和性属性定义可以通过kubectl explain pods.spec.affinity.nodeAffinity查看,如下所示:

nodeAffinity             <Object>                                # POD 对 node 节点的亲和性
  preferredDuringSchedulingIgnoredDuringExecution  <[]Object>    # 软亲和性要求,尽量满足亲和性
    preference           <Object>                                # 亲和的节点对象
      matchExpressions   <[]Object>                              # 查找表达式
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值
      matchFields        <[]Object>                              # 查找字段
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值
    weight               <integer>                               # 权重 1 - 100
  requiredDuringSchedulingIgnoredDuringExecution   <Object>      # 硬亲和性要求,不满足则 Pending
    nodeSelectorTerms    <[]Object>                              # 选择器对象列表
      matchExpressions   <[]Object>                              # 选择器对象列表
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值
      matchFields        <[]Object>                              # 查找字段
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值

preferredDuringSchedulingIgnoredDuringExecution表示有节点尽量满足这个位置定义的亲和性,这不是一个必须的条件,也叫软亲和性

requiredDuringSchedulingIgnoredDuringExecution表示必须有节点满足这个位置定义的亲和性,这是个硬性条件,也叫硬亲和性

软亲和性

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity1
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21.5
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:     # 软亲和性要求,不满足也可以
      - preference:
          matchExpressions:
          - key: type:
            operator: In
            values:
            - tomcat
        weight: 50

上面的pod在调度时,尽管找不到标签为type=tomcat的节点,任然可以调度成功,这是软亲和性的特点。

硬亲和性

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity2
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21.5
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:        # 硬亲和性要求,不满足就Pending
        nodeSelectorTerms:
        - matchExpressions:
          - key: type
            operator: In
            values:
            - tomcat

pod创建成功后,我们查看pod状态如下:

NAME                READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
pod-nodeaffinity2   0/1     Pending   0          6s    <none>   <none>   <none>           <none>

上面的pod在调度时,因为找不到标签为type=tomcat的节点,所以调度不成功,一直显示Pending状态,这是硬亲和性的特点。

pod亲和性

pod亲和性属性定义可以通过kubectl explain pods.spec.affinity.podAffinity查看,如下所示:

podAffinity                <Object>                              # POD 对其他 POD 的亲和性
  preferredDuringSchedulingIgnoredDuringExecution  <[]Object>    # 软性亲和性,尽量满足亲和性
    podAffinityTerm        <Object>                              # 亲和的 POD 对象
      labelSelector        <Object>                              # 标签选择器对象列表
        matchExpressions   <[]Object>                            # 标签选择器对象,选 POD 标签
          key              <string>                              # 标签
          operator         <string>                              # 操作:比较
          values           <[]string>                            # 值
        matchLabels        <map[string]string>                   # 集合标签选择器
      namespaces           <[]string>                            # 名称空间的列表
      topologyKey        <string>                              # 亲和判断条件
    weight                 <integer>                             # 权重 1 - 100
  requiredDuringSchedulingIgnoredDuringExecution   <[]Object>    # 硬性亲和性,不满足则 Pending
    labelSelector          <Object>                              # 标签选择器对象列表
      matchExpressions   <[]Object>                              # 标签选择器对象,选 POD 标签
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值
      matchLabels        <map[string]string>                     # 集合标签选择器
    namespaces             <[]string>                            # 名称空间的列表
    topologyKey            <string>                              # 亲和判断条件

pod亲和性跟节点亲和性一样,也有软亲和性和硬亲和性,它的特点跟节点亲和性里的软亲和性和硬亲和性一样。下面用硬亲和性举个例子,软亲和性大家自己动手写写。

apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: nginx:1.21.5
    imagePullPolicy: IfNotPresent

---

apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: default
  labels:
    app: db
spec:
  containers:
  - name: nginx
    image: nginx:1.21.5
    imagePullPolicy: IfNotPresent
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   # 硬亲和性要求,不满足的 Pending
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp
        topologyKey: kubernetes.io/hostname             # 亲和性的依据为同一个主机名则亲和

上面有两个pod,第一个pod设置了标签app=myapp,第二个pod通过硬亲和性去匹配标签为app=myapp的pod,所以两个pod会被调度到同一个节点。查看pod状态如下(可以删除后重新创建,多运行几次,观察两个pod总是调度相同的节点上):

NAME   READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          9s    10.81.85.230   k8s-node01   <none>           <none>
pod2   1/1     Running   0          9s    10.81.85.231   k8s-node01   <none>           <none>

pod反亲和性

节点亲和性属性定义可以通过kubectl explain pods.spec.affinity.podAntiAffinity查看,如下所示:

podAntiAffinity              <Object>                            # POD 对其他 POD 的反亲和性
  preferredDuringSchedulingIgnoredDuringExecution  <[]Object>    # 软性反亲和性,尽量满足亲和性
    podAffinityTerm        <Object>                              # 反亲和的 POD 对象
      labelSelector        <Object>                              # 标签选择器对象列表
        matchExpressions   <[]Object>                            # 标签选择器对象,选 POD 标签
          key              <string>                              # 标签
          operator         <string>                              # 操作:比较
          values           <[]string>                            # 值
        matchLabels        <map[string]string>                   # 集合标签选择器
      namespaces           <[]string>                            # 名称空间的列表
      topologyKey        <string>                              # 亲和判断条件
    weight                 <integer>                             # 权重 1 - 100
  requiredDuringSchedulingIgnoredDuringExecution   <[]Object>    # 硬性反亲和性,不满足则 Pending
    labelSelector          <Object>                              # 标签选择器对象列表
      matchExpressions   <[]Object>                              # 标签选择器对象,选 POD 标签
        key              <string>                                # 标签
        operator         <string>                                # 操作:比较
        values           <[]string>                              # 值
      matchLabels        <map[string]string>                     # 集合标签选择器
    namespaces             <[]string>                            # 名称空间的列表
    topologyKey            <string>                              # 亲和判断条件

反亲和性跟亲和性刚好相反,看下下面的例子,第一个pod定义了标签app=myapp,第二个pod通过反亲和性规则app=myapp,因此第二个pod不会调度到第一个pod相同的节点上。

apiVersion: v1
kind: Pod
metadata:
  name: pod3
  namespace: default
  labels:
    app: myapp
spec:
  containers:
  - name: myapp
    image: nginx:1.21.5

---

apiVersion: v1
kind: Pod
metadata:
  name: pod4
  namespace: default
  labels:
    app: db
spec:
  containers:
  - name: busybox
    image: nginx:1.21.5
    imagePullPolicy: IfNotPresent
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   # 硬亲和性要求,不满足的 Pending
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp
        topologyKey: kubernetes.io/hostname             # 反亲和性的依据为同一个主机名

查看两个pod的状态如下所示,分别被调度到了两个不同的节点

NAME   READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
pod3   1/1     Running   0          5s    10.81.85.232   k8s-node01   <none>           <none>
pod4   1/1     Running   0          5s    10.81.58.215   k8s-node02   <none>           <none>

pod亲和性就是pod和pod更倾向腻在一起,把相近的pod结合到相近的位置,如同一区域,同一机架,这样的话pod和pod之间更好通信,比方说有两个机房,这两个机房部署的集群有1000台主机,那么我们希望把nginx和tomcat都部署同一个地方的node节点上,可以提高通信效率;

pod反亲和性就是pod和pod更倾向不腻在一起,如果部署两套程序,那么这两套程序更倾向于反亲和性,这样相互之间不会有影响。

污点-容忍度

node污点

污点只用在node上的键值属性nodes.spec.taints,它的作用是拒绝不能容忍这些污点的pod运行的,因此需要在pod上定义容忍度pods.spec.tolerations,它也是键值数据,是一个列表,表示pod可以容忍的污点列表。一个pod能不能运行在一个节点上,就是pods.spec.tolerations列表中是否包括了nodes.spec.taints中的数据。

node污点的属性格式详见kubectl explain node.spec.taints,如下所示:

taints          <[]Object>     # 污点对象列表
  effect        <string>       # 当 POD 不能容忍这个污点的时候,要采取的行为,也就是排斥不容忍污点的 POD
    NoSchedule                 # 影响调度过程,但是已经调度完成 POD 无影响
    PreferNoSchedule           # 影响调度过程,尝试驱逐调度已经完成的但不容忍新污点的 POD
    NoExecute                  # 新增的污点,影响新的调度过程,且强力驱逐调度已经完成的但不容忍新污点的 POD
  key           <string>       # 键
  timeAdded     <string>       # 
  value         <string>       # 值
#给节点1打上污点,键为 node-type 值为 production,污点动作NoSchedule
kubectl taint node k8s-node01 node-type=production:NoSchedule

#删除污点
kubectl taint node k8s-node01 node-type-

节点k8s-node01被打上污点后,创建一个pod不设置容忍度,看它的调度情况是怎么样的。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx:1.21.5
          ports:
            - name: http
              containerPort: 80

pod创建成功后,如下所示,发现pod都被调度到k8s-node02节点上,符合预期,因为k8s-node01节点设置了污点,如果pod不添加容忍度是不会被调度到该节点的。

NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
myapp-deploy-5c75f74dc5-2z7hg   1/1     Running   0          7s    10.81.58.216   k8s-node02   <none>           <none>
myapp-deploy-5c75f74dc5-4sww5   1/1     Running   0          6s    10.81.58.217   k8s-node02   <none>           <none>
myapp-deploy-5c75f74dc5-fsdwh   1/1     Running   0          6s    10.81.58.219   k8s-node02   <none>           <none>
myapp-deploy-5c75f74dc5-w9w82   1/1     Running   0          6s    10.81.58.218   k8s-node02   <none>           <none>

此时给k8s-node02节点也打上污点,如下所示:

kubectl taint node k8s-node02 node-type=dev:NoExecute

通过kubectl get pods -o wide命令查看pod状态如下所示,发现k8s-node02节点新增的污点驱逐了不能容忍污点的pod ,所以所有pod都被挂起。

NAME                            READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
myapp-deploy-5c75f74dc5-4dfzl   0/1     Pending   0          20s   <none>   <none>   <none>           <none>
myapp-deploy-5c75f74dc5-654bx   0/1     Pending   0          20s   <none>   <none>   <none>           <none>
myapp-deploy-5c75f74dc5-b5bl4   0/1     Pending   0          20s   <none>   <none>   <none>           <none>
myapp-deploy-5c75f74dc5-wnz2r   0/1     Pending   0          20s   <none>   <none>   <none>           <none>

pod容忍度

pod容忍度的属性格式详见kubectl explain node.spec.tolerations,如下所示:

tolerations            <[]Object>    # 容忍度对象
  effect               <string>      # 能否容忍 node 上的污点驱逐策略,为空表示容忍任何驱逐策略
    NoSchedule                       # 能容忍 node 污点的 NoSchedule
    PreferNoSchedule                 # 能容忍 node 污点的 PreferNoSchedule
    NoExecute                        # 能容忍 node 污点的 NoExecute
  key                  <string>      # 污点的键
  operator             <string>      # Exists 污点存在不管什么值,Equal 污点的值必须等值
  tolerationSeconds    <integer>     # 容忍时间,即如果被驱逐,可以等多久再走,默认 0 秒,NoExecute 使用
  value                <string>      # 污点的值

上面分别给k8s-node01节点和k8s-node02节点都设置了污点,下面创建pod并添加容忍度,值为dev污点动作为NoExecute

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx:1.21.5
          ports:
            - name: http
              containerPort: 80
      tolerations:
      - key: node-type
        operator: Equal
        value: dev
        effect: NoExecute

运行上面的pod,可以发现pod成功调度到了k8s-node02节点,因为pod设置了node-type=dev:NoExecute的容忍度。

NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
myapp-deploy-667785b946-4kxml   1/1     Running   0          6s    10.81.58.222   k8s-node02   <none>           <none>
myapp-deploy-667785b946-9dqgn   1/1     Running   0          6s    10.81.58.220   k8s-node02   <none>           <none>
myapp-deploy-667785b946-cp7db   1/1     Running   0          6s    10.81.58.221   k8s-node02   <none>           <none>
myapp-deploy-667785b946-xf5b5   1/1     Running   0          6s    10.81.58.223   k8s-node02   <none>           <none>

字段选择器

上面介绍亲和性时,示例中的匹配规则都是用的表达式匹配,匹配规则有两种:表达式匹配-matchExpressions字段匹配-matchFields

表达式匹配通过节点、pod的标签进行匹配,字段匹配根据字段选择器进行匹配,在k8s中不同的资源类型支持不同的字段选择器。 所有资源类型都支持metadata.namemetadata.namespace字段。下面是一些使用字段选择器查询的例子:

  • metadata.name=my-service
  • metadata.namespace!=default
  • status.phase=Pending

使用不被支持的字段选择器会产生错误,例如:

kubectl get ingress --field-selector foo.bar=baz

下面这个命令将筛选出status.phase字段值为Running的所有pod

kubectl get pods --field-selector status.phase=Running

链式选择器

kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

匹配亲和性

下面创建pod,通过字段选择器进行匹配,匹配条件为metadata.name=k8s-node02,该pod将会被调度到k8s-node02节点(前提是不考虑污点和容忍度)。

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity2
  namespace: default
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.21.5
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:        # 硬亲和性要求,不满足就Pending
        nodeSelectorTerms:
        - matchFields:
          - key: metadata.name
            operator: In
            values:
            - k8s-node02
举报

相关推荐

0 条评论