淘先锋技术网

首页 1 2 3 4 5 6 7

Kubernetes资源调度

1. 深入理解Pod对象:调度

  • 创建一个Pod的工作流程
  • Pod中影响调度的主要属性
  • 资源限制对Pod调度的英雄
  • nodeSelector & nodeAffinity
  • Tain(污点)& Tolerations(污点容忍)
  • nodeName

Kubernetes Scheduler 是 Kubernetes 控制平面的核心组件之一。它在控制平面上运行,将 Pod 分配给节点,同时平衡节点之间的资源利用率。将 Pod 分配给新节点后,在该节点上运行的 kubelet 会在 Kubernetes API 中检索 Pod 定义,根据节点上的 Pod 规范创建资源和容器。换句话说,Scheduler 在控制平面内运行,并将工作负载分配给 Kubernetes 集群。
在这里插入图片描述

2. 创建一个Pod的工作流程

Kubernetes基于list-watch机制的控制器架构,实现组件间交互的解耦。

其他组件监控自己负责的资源,当这些资源发生变化时,kube-apiserver会通知这些组件,这个过程类似于发布与订阅

在这里插入图片描述

3. nodeSelector(节点选择器)

nodeSelector : 用于将Pod调度到匹配Label的Node上,如果没有匹配的标签会调度失败。
作用:

  • 约束Pod到特定的节点运行

  • 完全匹配节点标签

nodeSelector 是节点选择约束的最简单推荐形式。nodeSelector 是 PodSpec 的一个字段。 它包含键值对的映射。为了使 pod 可以在某个节点上运行,该节点的标签中 必须包含这里的每个键值对(它也可以具有其他标签)。 最常见的用法的是一对键值对。

执行 kubectl get nodes 命令获取集群的节点名称。 选择一个你要增加标签的节点,然后执行 kubectl label nodes = 命令将标签添加到你所选择的节点上。 例如,如果你的节点名称为 ‘kubernetes-foo-node-1.c.a-robinson.internal’ 并且想要的标签是 ‘disktype=ssd’,则可以执行 kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd 命令。

你可以通过重新运行 kubectl get nodes --show-labels, 查看节点当前具有了所指定的标签来验证它是否有效。 你也可以使用 kubectl describe node “nodename” 命令查看指定节点的标签完整列表
添加 nodeSelector 字段到 Pod 配置中
添加一个 nodeSelector 部分

//查看 node 的 label
[root@master ~]# kubectl get nodes --show-labels
NAME                STATUS   ROLES                  AGE     VERSION   LABELS
master              Ready    control-plane,master   5d10h   v1.23.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
node1.example.com   Ready    <none>                 5d10h   v1.23.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1.example.com,kubernetes.io/os=linux
node2.example.com   Ready    <none>                 5d10h   v1.23.1   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2.example.com,kubernetes.io/os=linux

//节点添加标签
[root@master ~]# kubectl label nodes node2.example.com disktype=ssd

//写入disktype=ssd
[root@master manifest]# vim test.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: b1
    image: busybox
    command: ["/bin/sh","-c","sleep 9000"]
    env:
    - name: xx
      valueFrom:
        fieldRef:
          fieldPath: status.podIPs
  nodeSelector:
    disktype: ssd

[root@master manifest]# kubectl create -f test.yaml 
pod/test created
[root@master manifest]# kubectl get pods
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          8s
//标签选择到指定主机上面,不会变
[root@master manifest]# kubectl get pods -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test   1/1     Running   0          58s   10.197.3.79  node2.example.com   <none>           <none>

4. 节点亲和性

nodeAffinity:
节点亲和性,与 nodeSelector作用一样,但相比更灵活,满足更多条件,诸如:

  • 匹配右更多的逻辑组合,不只是字符串的完全相等

  • 调度分为软策略和硬策略,而不是硬性要求

    • 硬(required):必须满足
    • 软(preferred):尝试满足,但不保证
      操作符:ln、Notln、Exists、DoesNotExist、Gt、Lt
操作符作用
Inlabel 的值在某个列表中
NotInlabel 的值不在某个列表中
Gtlabel 的值大于某个值
Ltlabel 的值小于某个值
Exists某个 label 存在
DoesNotExist某个 label 不存在

nodeAffinity 相对应的是 Anti-Affinity,就是反亲和性,这种方法比上面的 nodeSelector更加灵活,它可以进行一些简单的逻辑组合了,不只是简单的相等匹配。 调度可以分成软策略和硬策略两种方式。

软策略就是如果你没有满足调度要求的节点的话,Pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策。

硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不干的策略。

nodeAffinity就有两上面两种策略

  • preferredDuringSchedulingIgnoredDuringExecution:软策略
  • requiredDuringSchedulingIgnoredDuringExecution:硬策略
[root@master ~]# cat test2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - node1
            - node2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: source
            operator: In
            values:
            - qikqiak

[root@master ~]# kubectl apply -f test2.yaml 
pod/with-node-affinity created
[root@master ~]# kubectl get pods
NAME                 READY   STATUS    RESTARTS   AGE
test-busybox         1/1     Running   0          15m
with-node-affinity   1/1     Running   0          59s

5. Taint(污点)& Tolerations(污点容忍)

节点亲和性 是 Pod 的一种属性,它使 Pod 被吸引到一类特定的节点 (这可能出于一种偏好,也可能是硬性要求)。 污点(Taint)则相反——它使节点能够排斥一类特定的 Pod。

容忍度(Toleration)是应用于 Pod 上的,允许(但并不要求)Pod 调度到带有与之匹配的污点的节点上。

污点和容忍度(Toleration)相互配合,可以用来避免 Pod 被分配到不合适的节点上。 每个节点上都可以应用一个或多个污点,这表示对于那些不能容忍这些污点的 Pod,是不会被该节点接受的。

概念

您可以使用命令 kubectl taint 给节点增加一个污点。比如,

kubectl taint nodes node1 key1=value1:NoSchedule

给节点 node1 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 node1 这个节点。

若要移除上述命令所添加的污点,你可以执行:

kubectl taint nodes node1 key1=value1:NoSchedule-

您可以在 PodSpec 中定义 Pod 的容忍度。 下面两个容忍度均与上面例子中使用 kubectl taint 命令创建的污点相匹配, 因此如果一个 Pod 拥有其中的任何一个容忍度都能够被分配到 node1

tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
  tolerations:
- key: "key1"
  operator: "Exists"
  effect: "NoSchedule"

例子

[root@master ~]# kubectl describe node master
CreationTimestamp:  Sat, 18 Dec 2021 11:50:26 +0800
Taints:             node-role.kubernetes.io/master:NoSchedule	// 默认为不可调度
Unschedulable:      false
Lease:
  HolderIdentity:  master

// 删除就是在添加污点的后面加一个减号"-"
[root@master ~]# kubectl taint node master node-role.kubernetes.io/master-
node/master untainted

[root@master ~]# kubectl describe node master
CreationTimestamp:  Sat, 18 Dec 2021 11:50:26 +0800
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  master

//添加污点
 删除就是在添加污点的后面加一个减号"-"
[root@master ~]# kubectl taint node master node-role.kubernetes.io/master-
node/master untainted

[root@master ~]# kubectl describe node master
CreationTimestamp:  Sat, 18 Dec 2021 11:50:26 +0800
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  master

//查看各节点的污点
[root@master ~]# kubectl get nodes
NAME                STATUS   ROLES                  AGE     VERSION
master              Ready    control-plane,master   5d11h   v1.23.1
node1.example.com   Ready    <none>                 5d11h   v1.23.1
node2.example.com   Ready    <none>                 5d11h   v1.23.1

[root@master ~]# kubectl describe node  master | grep Taints:
Taints:             node-role.kubernetes.io/master:NoSchedule

[root@master ~]# kubectl describe node  node1 | grep Taints: 
Taints:             <none>


// 添加污点
[root@master ~]# kubectl taint node node1.example.com env_wu=yes:NoSchedule
node/node1.example.com tainted
[root@master ~]# kubectl describe node node1 | grep Taints:Taints:             env_wu=yes:NoSchedule

# 格式:
# key=value:值
# k/v都可以自定义

添加NoSchedule污点后,节该节点不会调度pod运行;如果该节点已经运行pod,也不会删除

// 测试一下
创建一个test容器,复制成两个
[root@master ~]# kubectl create deployment test --image=nginx
deployment.apps/test created

[root@master ~]#kubectl create deployment test--replicas=2
deployment.apps/test created

// 全部由node2运行
[root@master ~]# kubectl get pod -o wide
NAME                   READY   STATUS              RESTARTS      AGE   IP            NODE                NOMINATED NODE   READINESS GATES
test-8499f4f74-nnkn4   1/1     Running             0             38s   10.244.2.72   node2.example.com   <none>           <none>
test-8499f4f74-r2w9l   1/1     Running   		   0           

// 删除污点,重新扩展Pod
[root@master ~]# kubectl taint node node1.example.com env_wu=yes:NoSchedule-
node/node1.example.com untainted
[root@master ~]# kubectl describe node node1 | grep Taints:Taints:             <none>

[root@master ~]# node/node1.example.com untainted

CreationTimestamp:  Sat, 18 Dec 2021 12:00:45 +0800
Taints:             <none>
Unschedulable:      false
Lease:
  HolderIdentity:  node1.example.com

Tolerations(污点容忍)

// 添加污点/NoExecute (驱逐)
[root@master ~]# kubectl taint node node01 env_wu=yes:NoExecute
node/node1.example.com tainted

[root@master ~]# vi test.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-ton
spec:
  selector:
    matchLabels:
      app: test-ton
  replicas: 3
  template:
    metadata:
      labels:
        app: test-ton
    spec:
      containers:
      - name: nginx
        image: nginx

// 没有node1节点Pod
[root@master ~]# kubectl get pod -o wide  //node01无pod
NAME                        READY   STATUS              RESTARTS        AGE   IP            NODE     			  NOMINATED NODE   READINESS GATES
test-ton-6798d496c7-2rfnf   1/1     Running  			  0               25s    <none>        node2.example.com   <none>           <none>
test-ton-6798d496c7-2x6j9   1/1     Running  			  0               25s    <none>        node2.example.com   <none>           <none>
test-ton-6798d496c7-r66wk   1/1     Running   		  	  0               25s    <none>        node2.example.com   <none>           <none>

// 添加容忍
// 编写yaml文件
[root@master ~]# vi test2.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-ton
spec:
  selector:
    matchLabels:
      app: test-ton
  replicas: 3
  template:
    metadata:
      labels:
        app: test-ton
    spec:
      containers:
      - name: nginx
        image: nginx
      tolerations:        		// 容忍
      - key: "env_wu"       	// 设置污点的key
        operator: "Equal"
        value: "yes"        	// 设置污点的values
        effect: "NoExecute" 	// 设置污点类型
        
// 应用yaml文件
[root@master ~]# kubectl apply -f ss.yaml
Warning: resource deployments/test-ton is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.	// 警告可以不用管
deployment.apps/test-taint configured

[root@master ~]# kubectl get pod -o wide
NAME                        READY   STATUS              RESTARTS      AGE     IP            NODE     			NOMINATED NODE   READINESS GATES
test-ton-6798d496c7-2x6j9   1/1     Running             0             5m32s   10.244.2.64   node2.example.com   <none>           <none>
test-ton-749fbcf99f-jlf42   1/1     Running             0             40s     10.244.1.62   node1.example.com   <none>           <none>
test-ton-749fbcf99f-rtrbr   1/1     Running             0             21s     10.244.2.67   node2.example.com   <none>           <none>
test-ton-749fbcf99f-v86zc   0/1     ContainerCreating   0             3s      <none>        node1.example.com   <none>           <none>

6. nodename

nodeName是最简单的节点选择约束形式,但由于其局限性,通常不使用它。 是 PodSpec 的一个域。如果它是非空的,调度程序将忽略 pod,并且在命名节点上运行的 kubelet 会尝试运行该 pod。因此,如果在 PodSpec 中提供,则它优先于上述节点选择方法。nodeName nodeName

使用来选择节点的一些限制是:nodeName

如果命名节点不存在,则不会运行 Pod,并且在某些情况下可能会被自动删除。
如果命名节点没有容纳 pod 的资源,则 Pod 将失败,其原因将指示原因,例如 OutOfmemory 或 OutOfcpu。
云环境中的节点名称并不总是可预测的或稳定的。
下面是使用该字段的 pod 配置文件的示例:nodeName

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
  nodeName: kube-01