Skip to content

Kubernets-资源管理

k8s集群中为了能够使系统正常稳定运行,通常会限制Pod的资源使用情况,在k8s集群中如果有一个程序出现异常,并占用大量的系统资源。如果未对该Pod进行资源限制的话,可能会影响其他的Pod。

k8s常见的资源管理方式

  • 计算资源管理(Compute Resources): 为Pod中的容器指定使用的计算资源(CPU和内存)。

  • 资源的配置范围管理(LimitRange):可以对集群内Request和Limits的配置做一个全局的统一的限制,相当于批量设置了某一个范围内(某个命名空间)的Pod的资源使用限制。

  • 资源的配额管理(Resource Quotas):可以为每一个命名空间(namespace)提供一个总体的资源使用限制,通过它可以限制命名空间中某个类型的对象的总数目上限,也可以设置命名空间中Pod可以使用到的计算资源的总上限。资源的配额管理有效解决了多用户或多个团队公用一个k8s集群时资源有效分配的问题。

ResourceQuota 资源配额

ResourceQuota 是 Kubernetes 中用于限制命名空间资源使用量的核心机制,它如同集群资源的"守门人",确保多租户环境下资源的公平分配与合理使用。本文将深入剖析 ResourceQuota 的工作原理、配置方法、高级特性以及最佳实践,帮助您全面掌握这一关键工具。

资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。 它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命令空间中的 Pod 可以使用的计算资源的总上限。

  • 不同的团队可以在不同的命名空间下工作,目前这是非约束性的,在未来的版本中可能会通过 ACL(Access Control List 访问控制列表) 来实现强制性约束。
  • 集群管理员可以为每个命名空间创建一个或多个资源配额对象。
  • 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会 跟踪集群的资源使用情况,以确保使用的资源用量不超过资源配额中定义的硬性资源限额。
  • 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。
  • 如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用,则用户必须为 这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 提示: 可使用LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。

ResourceQuota 核心概念与工作原理

什么是 ResourceQuota?

ResourceQuota 是 Kubernetes 提供的命名空间级资源配额管理机制,它通过定义硬性限制来:

  • 限制命名空间中可使用的计算资源(CPU/内存)和存储资源总量
  • 控制命名空间中特定类型对象(如 Pod、Service 等)的数量上限

典型应用场景包括:

  • 多租户隔离:防止某个团队占用过多集群资源而影响其他团队
  • 成本控制:在公有云环境中限制资源使用量以控制成本
  • 稳定性保障:避免资源耗尽导致的集群不稳定

核心工作原理

ResourceQuota 通过以下机制实现资源管控:

  1. 命名空间隔离:不同团队工作在不同的命名空间中,通过 RBAC 实现访问控制
  2. 配额创建:管理员为每个命名空间创建 ResourceQuota 对象定义限制规则
  3. 准入控制:当用户创建资源时,API 服务器会检查是否违反配额限制
  4. 强制拒绝:如果请求超出配额,API 服务器返回 HTTP 403 Forbidden 错误

特殊要求

  • 对于 CPU 和内存资源,Pod 必须明确指定 requests 或 limits,否则创建会被拒绝
  • 可使用 LimitRange 准入控制器为未设置资源需求的 Pod 提供默认值

ResourceQuota 的三种主要类型

计算资源配额

计算资源配额限制命名空间内可请求的计算资源总量,支持以下资源类型:

资源名称描述
limits.cpu所有非终止状态 Pod 的 CPU 限制总和
limits.memory所有非终止状态 Pod 的内存限制总和
requests.cpu所有非终止状态 Pod 的 CPU 请求总和
requests.memory所有非终止状态 Pod 的内存请求总和
hugepages-<size>指定大小的巨页请求总数

配置示例

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    requests.cpu: "1"       # CPU请求总量不超过1核
    requests.memory: 1Gi     # 内存请求总量不超过1GB
    limits.cpu: "2"         # CPU限制总量不超过2核
    limits.memory: 2Gi      # 内存限制总量不超过2GB
    hugepages-2Mi: "4Gi"    # 2MB巨页请求不超过4GB

存储资源配额

存储资源配额限制命名空间内的存储资源使用,包括持久化存储和临时存储:

资源名称描述
requests.storage所有 PVC 的存储请求总和
persistentvolumeclaims允许的 PVC 总数
<storage-class>.storageclass.storage.k8s.io/requests.storage特定存储类的存储请求总和
requests.ephemeral-storage所有 Pod 的临时存储请求总和

多存储类配额示例

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage-resources
spec:
  hard:
    requests.storage: 100Gi                  # 所有存储类总量限制
    gold.storageclass.storage.k8s.io/requests.storage: 50Gi   # 黄金存储类限制
    bronze.storageclass.storage.k8s.io/requests.storage: 10Gi # 青铜存储类限制
    persistentvolumeclaims: "20"             # PVC总数限制

对象数量配额

对象数量配额限制命名空间中特定类型 Kubernetes 对象的数量,语法格式为:

  • 核心组资源:count/<resource>(如 count/pods
  • 非核心组资源:count/<resource>.<group>(如 count/deployments.apps

常见可限制对象

  • count/pods - 非终止状态的 Pod 数量
  • count/services - Service 数量
  • count/secrets - Secret 数量
  • count/configmaps - ConfigMap 数量
  • count/deployments.apps - Deployment 数量

配置示例

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
spec:
  hard:
    count/pods: "50"               # 最多50个Pod
    count/services: "10"           # 最多10个Service
    count/secrets: "20"            # 最多20个Secret
    count/deployments.apps: "5"    # 最多5个Deployment

ResourceQuota 特性

配额作用域(Scopes)

ResourceQuota 可以设置作用域,只有匹配作用域的资源才会被计入配额。支持的作用域包括:

作用域描述跟踪的资源
Terminating匹配设置了 activeDeadlineSeconds 的 Podpods
NotTerminating匹配未设置 activeDeadlineSeconds 的 Podpods, cpu, memory 等
BestEffort匹配 QoS 为 BestEffort 的 Podpods
NotBestEffort匹配 QoS 不为 BestEffort 的 Podpods, cpu, memory 等
PriorityClass匹配特定优先级的 Podpods, cpu, memory 等

作用域使用规则

  • 不能在同一配额中同时设置 TerminatingNotTerminating
  • 不能在同一配额中同时设置 BestEffortNotBestEffort

作用域选择器示例

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: scope-selector
spec:
  hard:
    pods: "10"
    cpu: "1"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values: ["high"]    # 仅对优先级为high的Pod生效

基于优先级的资源配额

从 Kubernetes 1.17 开始稳定支持基于 Pod 优先级的配额控制,允许为不同优先级的 Pod 分配不同的资源量:

yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: pods-high
spec:
  hard:
    cpu: "1000"
    memory: 200Gi
    pods: "10"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values: ["high"]    # 仅限制高优先级Pod

这种机制特别适合确保关键业务应用能获得所需资源,同时限制低优先级应用的资源使用。

配额与 LimitRange 的协同工作

ResourceQuota 通常与 LimitRange 配合使用,形成完整的资源管控体系:

  • ResourceQuota:控制命名空间资源总量
  • LimitRange:为单个容器/Pod 设置:
    • 默认资源请求和限制
    • 最小/最大资源限制
    • 存储请求大小限制

典型工作流程

  1. 管理员创建命名空间
  2. 设置 ResourceQuota 定义命名空间资源上限
  3. 设置 LimitRange 定义单个资源的默认值和限制范围
  4. 用户创建资源时:
    • 未设置资源需求时使用 LimitRange 默认值
    • 所有资源需求总和不能超过 ResourceQuota 限制

ResourceQuota 案例

基础配置步骤

步骤1:创建测试命名空间

bash
kubectl create ns quota-demo

步骤2:创建计算资源配额

yaml
# compute-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: quota-demo
spec:
  hard:
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
    pods: "5"
bash
kubectl apply -f compute-quota.yaml

步骤3:验证配额状态

bash
kubectl get quota -n quota-demo
kubectl describe quota compute-quota -n quota-demo

输出示例:

Name:            compute-quota
Namespace:       quota-demo
Resource         Used  Hard
--------         ----  ----
limits.cpu       0     2
limits.memory    0     2Gi
pods             0     5
requests.cpu     0     1
requests.memory  0     1Gi

配额限制验证案例

案例1:创建合规 Pod

yaml
# pod-valid.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-valid
  namespace: quota-demo
spec:
  containers:
  - name: nginx
    image: nginx:1.19
    resources:
      requests:
        cpu: "500m"
        memory: "512Mi"
      limits:
        cpu: "1"
        memory: "1Gi"
bash
kubectl apply -f pod-valid.yaml  # 成功创建

案例2:创建超出配额的 Pod

yaml
# pod-invalid.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-invalid
  namespace: quota-demo
spec:
  containers:
  - name: nginx
    image: nginx:1.19
    resources:
      requests:
        cpu: "1.5"    # 超过requests.cpu配额(1)
        memory: "512Mi"
      limits:
        cpu: "2"
        memory: "1Gi"
bash
kubectl apply -f pod-invalid.yaml

预期错误:

Error from server (Forbidden): error when creating "pod-invalid.yaml": pods "pod-invalid" is forbidden: exceeded quota: compute-quota, requested: requests.cpu=1.5, used: requests.cpu=0.5, limited: requests.cpu=1

对象数量配额验证

创建对象数量配额

yaml
# object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
  namespace: quota-demo
spec:
  hard:
    count/pods: "3"
    count/services: "2"
    count/secrets: "5"
bash
kubectl apply -f object-counts.yaml

测试创建多个 Pod

bash
kubectl create deployment nginx --image=nginx:1.19 -n quota-demo --replicas=5

由于 Pod 数量限制为3,只有3个 Pod 能成功运行:

bash
kubectl get pods -n quota-demo

输出:

NAME                     READY   STATUS    RESTARTS   AGE
nginx-6799fc88d8-4bn6x   1/1     Running   0          15s
nginx-6799fc88d8-8wq5k   1/1     Running   0          15s
nginx-6799fc88d8-kx9g7   1/1     Running   0          15s

esourceQuota 常用命令

bash
# 查看指定命名空间的所有 ResourceQuota
kubectl get resourcequotas -n <namespace>

# 查看所有命名空间的 ResourceQuota
kubectl get resourcequotas --all-namespaces

# 使用缩写形式
kubectl get quota -n <namespace>

# 查看特定 ResourceQuota 的详细配置
kubectl describe resourcequota <quota-name> -n <namespace>

# 示例:查看 dev 命名空间中 compute-quota 的详情
kubectl describe resourcequota compute-quota -n dev

# 删除指定的 ResourceQuota
kubectl delete resourcequota <quota-name> -n <namespace>

# 通过 YAML 文件删除
kubectl delete -f quota.yaml -n <namespace>

LimitRange

LimitRange 是 Kubernetes 中用于精细控制命名空间内资源分配的核心机制,它如同资源分配的"精密调节器",能够为容器和 Pod 设置默认资源值、定义资源使用范围,并确保资源配置的合理性。本文将系统性地介绍 LimitRange 的核心概念、工作原理、配置方法、使用场景以及最佳实践,帮助您全面掌握这一关键资源管理工具。

LimitRange 核心概念与价值

LimitRange 是什么?

LimitRange 是 Kubernetes 中的一种策略对象,用于约束命名空间内各种资源对象(如 Pod 和 PersistentVolumeClaim)的资源分配量。它主要提供以下关键功能:

  • 设置默认值:为未指定资源需求的 Pod 或容器自动注入合理的资源请求(request)和限制(limit)值
  • 定义资源范围:约束 Pod 或容器能够使用的资源最小值和最大值,防止配置不合理
  • 控制比例关系:限制资源请求值与限制值之间的比例,避免资源分配失衡
  • 存储限制:对 PersistentVolumeClaim 设置最小和最大存储空间限制

为什么需要 LimitRange?

在 Kubernetes 集群中,容器默认可以无限制地使用计算资源(CPU、内存等),这会导致一系列问题:

  1. 资源浪费:开发者可能忘记设置资源限制,导致容器占用过多资源
  2. 资源争用:单个 Pod 或容器可能独占节点资源,影响其他应用性能
  3. 调度不稳定:未设置资源请求的 Pod 可能导致节点资源超卖,引发随机驱逐
  4. 配置不一致:不同团队设置的资源值差异过大,难以统一管理

LimitRange 通过命名空间级别的资源约束,有效解决了这些问题,确保集群资源得到合理分配和使用。

LimitRange 与 ResourceQuota 的关系

LimitRange 和 ResourceQuota 都是 Kubernetes 的资源管理机制,但侧重点不同:

特性LimitRangeResourceQuota
作用对象命名空间内的单个 Pod/容器/PVC整个命名空间的资源总量
控制粒度精细控制(单个对象)宏观控制(命名空间总量)
主要功能设置默认值、定义范围、控制比例限制命名空间资源使用上限
使用场景确保单个资源配置合理防止命名空间耗尽集群资源
互补性通常与 ResourceQuota 配合使用依赖 LimitRange 提供默认值

最佳实践是将两者结合使用:LimitRange 确保单个 Pod/容器的资源配置合理,ResourceQuota 确保命名空间不会耗尽集群资源。

LimitRange 工作原理

LimitRange 通过 Kubernetes 的准入控制机制实现资源约束,具体流程如下:

  1. 管理员创建 LimitRange:在命名空间中定义资源限制规则
  2. 用户创建资源对象:尝试创建 Pod/PVC 等资源
  3. 准入控制器介入
    • 如果对象未设置资源需求,注入默认值(default/defaultRequest)
    • 验证显式设置的资源值是否符合 min/max 范围
    • 检查 limit/request 比率是否超过 maxLimitRequestRatio
  4. 创建结果
    • 验证通过:创建资源对象
    • 验证失败:返回 HTTP 403 错误,拒绝创建

LimitRange 核心配置详解

LimitRange 对象结构

一个完整的 LimitRange 配置包含以下主要部分:

yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: [LimitRange名称]
  namespace: [命名空间名称]
spec:
  limits:
  - type: [限制类型] # Pod/Container/PersistentVolumeClaim
    # 容器/Pod级别配置
    min:  						# 资源最小值
      cpu: "100m"
      memory: "128Mi"
    max:  						# 资源最大值
      cpu: "1"
      memory: "1Gi"
    default:  					# 默认限制值
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:  			# 默认请求值
      cpu: "250m"
      memory: "256Mi"
    maxLimitRequestRatio:  		# 限制与请求的最大比率
      cpu: "2"
      memory: "1.5"

支持的限制类型

LimitRange 支持对三种类型的对象进行资源限制:

  1. Container:针对 Pod 中的每个容器设置资源限制

    • 控制单个容器的 CPU/内存 requests 和 limits
    • 可设置默认值、最小/最大值、比例限制
  2. Pod:针对整个 Pod 的资源总和设置限制

    • 控制 Pod 中所有容器的 requests/limits 总和
    • 仅支持设置 max 值(最大值限制)
  3. PersistentVolumeClaim:针对存储声明设置限制

    • 控制 PVC 的存储请求大小
    • 可设置最小/最大存储容量

关键参数解析

min 和 max

  • min:指定资源请求(request)或限制(limit)的最小值

    • 对于 CPU:通常以毫核为单位(如 "100m" 表示 0.1 核)
    • 对于内存:通常以 MiB/GiB 为单位(如 "128Mi" 表示 128MB)
  • max:指定资源请求或限制的最大值

    • 确保单个容器/Pod 不会占用过多资源
    • 超过 max 的资源创建请求将被拒绝

示例:

yaml
min:
  cpu: "100m"
  memory: "128Mi"
max:
  cpu: "1"
  memory: "1Gi"

default 和 defaultRequest

  • default:当未指定资源限制(limits)时使用的默认限制值
  • defaultRequest:当未指定资源请求(requests)时使用的默认请求值

这两个参数确保即使开发者忘记设置资源需求,容器也能获得合理的默认配置。

示例:

yaml
default:
  cpu: "500m"
  memory: "512Mi"
defaultRequest:
  cpu: "250m"
  memory: "256Mi"

maxLimitRequestRatio

  • 定义资源限制与请求之间的最大允许比率
  • 防止资源配置严重失衡(如 limit 远大于 request)
  • 计算公式:limit/request ≤ maxLimitRequestRatio

示例:

yaml
maxLimitRequestRatio:
  cpu: "2"    # CPU limit 最多是 request 的2倍
  memory: "1.5" # 内存 limit 最多是 request 的1.5倍

LimitRange 案例

未设置资源需求的 Pod

创建不指定任何资源需求的 Pod:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-limitrange-pod
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: Never

结果

  • LimitRange 会注入默认的 requests 和 limits
  • 查看 Pod 配置可见自动添加的资源设置:
    yaml
          resources:
            limits:
              cpu: 100m
              memory: 128Mi
            requests:
              cpu: 100m
              memory: 128Mi

设置部分资源需求的 Pod

创建只设置 requests 的 Pod:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: dmeo-limitrage
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: Never
    resources:
      requests:
        cpu: "180m"
        memory: "180Mi"

结果

  • requests 使用用户指定的值
  • limits 使用 LimitRange 的默认值:
    yaml
          resources:
            limits:				# pod 资源未定义limits会使用LimitRange的default的值
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 180m
              memory: 180Mi

设置 limits 但未设置 requests 的 Pod

创建只设置 limits 的 Pod:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: limit-only-spec
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: Never
    resources:
      limits:
        cpu: "300m"
        memory: "300Mi"

结果

  • Kubernetes 会将 requests 设置为与 limits 相同的值:
    yaml
    resources:
      limits:
        cpu: "300m"
        memory: "300Mi"
      requests:
        cpu: "300m"
        memory: "300Mi"

违反 min/max 限制的 Pod

尝试创建 requests 小于 min 的 Pod:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: invalid-resource-spec
spec:
  containers:
  - name: nginx
    image: nginx:1.19
    resources:
      limits:
        cpu: "300m"
        memory: "300Mi"
      requests:
        cpu: "80m"   # 小于 min.cpu (100m)
        memory: "80Mi" # 小于 min.memory (100Mi)

结果

  • API 服务器返回 403 错误:
    Error from server (Forbidden): error when creating "pod.yaml": pods "invalid-resource-spec" is forbidden: 
    [minimum cpu usage per Container is 100m, but request is 80m, 
    minimum memory usage per Container is 100Mi, but request is 80Mi]

多租户环境资源隔离

在多团队共享的 Kubernetes 集群中,LimitRange 可确保:

  • 每个团队的命名空间有统一的资源标准
  • 防止某个团队的应用配置异常影响其他团队
  • 通过默认值降低配置门槛,减少人为错误

配置示例

yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: team-a-limits
  namespace: team-a
spec:
  limits:
  - type: Container
    min:
      cpu: "100m"
      memory: "256Mi"
    max:
      cpu: "2"
      memory: "4Gi"
    default:
      cpu: "500m"
      memory: "1Gi"
    defaultRequest:
      cpu: "250m"
      memory: "512Mi"

关键应用资源保障

对于关键业务应用,可通过 LimitRange 确保:

  • 设置较高的 min 值,防止资源不足
  • 限制非关键应用的 max 值,避免资源争用
  • 通过 maxLimitRequestRatio 防止过度超卖

生产环境示例

yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: critical-app-limits
  namespace: production
spec:
  limits:
  - type: Container
    min:  # 关键应用最小需求
      cpu: "500m"
      memory: "1Gi"
    max:
      cpu: "4"
      memory: "8Gi"
    defaultRequest:
      cpu: "1"
      memory: "2Gi"
    maxLimitRequestRatio:
      cpu: "1.5"  # 严格限制超卖比例
      memory: "1.2"

存储资源限制

LimitRange 可对 PersistentVolumeClaim 进行约束:

  • 防止申请过大存储造成浪费
  • 确保存储请求满足最低要求

存储限制示例

yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: storage-limits
spec:
  limits:
  - type: PersistentVolumeClaim
    min:
      storage: "1Gi"  # 最小1GB
    max:
      storage: "50Gi" # 最大50GB

与 ResourceQuota 的协同配置

典型的多层次资源管控方案:

  1. LimitRange:确保单个 Pod/容器的资源配置合理

    yaml
    # limitrange.yaml
    apiVersion: v1
    kind: LimitRange
    metadata:
      name: default-limits
    spec:
      limits:
      - type: Container
        default:
          cpu: "500m"
          memory: "512Mi"
        defaultRequest:
          cpu: "250m"
          memory: "256Mi"
  2. ResourceQuota:限制命名空间资源总量

    yaml
    # quota.yaml
    apiVersion: v1
    kind: ResourceQuota
    metadata:
      name: team-quota
    spec:
      hard:
        requests.cpu: "10"
        requests.memory: "20Gi"
        limits.cpu: "20"
        limits.memory: "40Gi"
  3. 工作流程

    • 开发者创建 Pod,未设置资源需求 → 使用 LimitRange 默认值
    • 所有 Pod 的资源总和不能超过 ResourceQuota 限制
    • 确保既有个体合理性,又有总量控制

LimitRange 管理命令

  • 查看 LimitRange 列表

    bash
    kubectl get limitrange -n [命名空间]
  • 查看 LimitRange 详情

    bash
    kubectl describe limitrange [名称] -n [命名空间]
  • 创建 LimitRange

    bash
    kubectl apply -f limitrange.yaml
  • 删除 LimitRange

    bash
    kubectl delete limitrange [名称] -n [命名空间]

节点亲和性-NodeSelector

NodeSelector 核心概念

定义 NodeSelector 是 Kubernetes 中一种基于节点标签(Labels)的简单调度机制,允许用户通过键值对匹配将 Pod 强制调度到特定节点上。它通过 spec.nodeSelector 字段实现,仅支持完全匹配(精确的键值对)。

核心用途

  • 资源隔离:将不同服务(如生产/测试环境)调度到不同节点组。
  • 硬件约束:指定 Pod 运行在具备特定硬件(如 GPU、SSD)的节点上。
  • 地理位置调度:在多区域集群中,选择低延迟的节点。

NodeSelector 工作原理

  1. 节点标签标记 管理员需先为节点打上标签,例如:

    bash
    kubectl label nodes <node-name> disktype=ssd
  2. Pod 配置匹配 Pod 的 YAML 中通过 nodeSelector 指定标签,调度器会筛选出匹配的节点:

    yaml
    spec:
      nodeSelector:
        disktype: ssd  # 仅调度到带有 disktype=ssd 标签的节点
  3. 强制调度 若无匹配节点,Pod 将处于 Pending 状态,直到符合条件的节点可用。

NodeSelector 案例

测试pod

资源清单

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-ssd
spec:
  containers:
    - name: nginx
      image: nginx
      imagePullPolicy: Never
  nodeSelector:
    disktype: ssd  # 必须与节点标签完全匹配

给节点添加标签

bash
# node创建标签
kubectl label nodes k8s-node01 disktype=ssd

# 查看node标签
kubectl get node --show-labels

多标签匹配

yaml
nodeSelector:
  disktype: ssd
  gpu: "true"  # 同时满足多个标签的节点

结合 Namespace 使用

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  namespace: production  # 指定命名空间
spec:
  nodeSelector:
    env: prod

NodeSelector 与相关调度策略对比

NodeSelector vs. NodeAffinity

特性NodeSelectorNodeAffinity
匹配条件仅完全匹配支持 InNotInExists 等运算符
规则类型硬性要求支持硬性(required)和软性(preferred
多条件组合仅 AND 逻辑支持 AND/OR 逻辑
适用场景简单调度需求复杂调度策略(如多可用区、权重优先级)

NodeSelector vs. NodeName

  • NodeName:直接指定节点名称(跳过调度器),灵活性极低。
  • NodeSelector:通过标签动态选择节点,更适合自动化管理。

节点亲和性-NodeAffinity

节点亲和性核心概念

节点亲和性(Node Affinity)是 Kubernetes 中比 NodeSelector 更高级的调度机制,它允许您通过复杂的逻辑表达式指定 Pod 应该(或不应该)调度到哪些节点上。

与 NodeSelector 的关键区别

特性NodeSelectorNode Affinity
匹配逻辑完全相等匹配支持多种操作符(In, NotIn, Exists等)
约束强度硬性约束支持软性(preferred)和硬性(required)约束
表达式复杂度简单键值对支持复杂逻辑表达式
多条件组合AND 逻辑支持复杂组合逻辑

节点亲和性类型

  1. requiredDuringSchedulingIgnoredDuringExecution (硬性要求)

    • 调度时必须满足的条件
    • 不满足则 Pod 保持 Pending 状态
    • "IgnoredDuringExecution"表示 Pod 运行后节点标签变化不影响已调度 Pod
  2. preferredDuringSchedulingIgnoredDuringExecution (软性偏好)

    • 调度时优先考虑的条件
    • 不满足仍可调度,但会影响调度评分
    • 可设置权重(weight)表示偏好强度

节点亲和性实战案例解析

案例1:多区域部署(硬性要求)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:  					# 亲和性配置,包含节点亲和性和Pod亲和性/反亲和性
    nodeAffinity:  				# 节点亲和性配置,定义Pod与节点的调度关系
      requiredDuringSchedulingIgnoredDuringExecution:  # 硬性调度要求(必须满足的条件)
        # 注意:即使有多个nodeSelectorTerms,也只需满足其中一个即可(OR逻辑)
        nodeSelectorTerms:  	# 节点选择条件列表(每个term内部是AND逻辑)
        - matchExpressions:  	# 节点标签匹配表达式列表
          - key: disktype  		# 要匹配的节点标签键
            operator: In  		# 匹配操作符(In表示标签值在指定列表中)
            values:  			# 允许的标签值列表(OR逻辑)
            - ssd  				# 必须调度到disktype为ssd...
            - antarctica-west1  # ...或antarctica-west1的节点上
            # 注意:若找不到匹配节点,Pod将保持Pending状态
  containers:
  - name: with-node-affinity
    image: nginx 
    imagePullPolicy: Never
    # 注意:实际生产环境应设置resources.requests/limits确保调度稳定性

配置解析

  • 必须调度到带有 topology.kubernetes.io/zone 标签且值为 antarctica-east1antarctica-west1 的节点
  • 若无匹配节点,Pod 将保持 Pending 状态
  • 使用场景:跨可用区部署保证高可用性

案例2:偏好特定节点标签(软性偏好)

yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-node-affinity
spec:
  containers:
  - name: test-node-affinity
    image: nginx
    # 注意:生产环境建议设置resources.requests/limits
  affinity:  						# 亲和性配置
    nodeAffinity:  					# 节点亲和性配置
      preferredDuringSchedulingIgnoredDuringExecution:  # 软性调度偏好(非强制要求)
      # 注意:多个preference之间按weight权重竞争,不影响最终调度结果
      - weight: 80  				# 权重值(1-100),数值越大优先级越高
        preference:  				# 偏好条件
          matchExpressions:  		# 标签匹配规则
          - key: app  				# 节点标签键
            operator: In  			# 操作符(包含在values列表中)
            values:  				# 期望的标签值
            - web  					# 优先调度到app=web的节点(权重80)
      - weight: 20  				# 次要权重
        preference:
          matchExpressions:
          - key: tier  				# 次级优先标签键
            operator: In  
            values:
            - frontend  			# 其次考虑tier=frontend的节点(权重20)

# 关键字段说明:
# 1. preferredDuringSchedulingIgnoredDuringExecution 表示:
#    - preferredDuringScheduling: 调度时优先考虑(非强制)
#    - IgnoredDuringExecution: Pod运行后节点标签变化不影响已调度Pod
#
# 2. weight 权重特点:
#    - 相对值(80 vs 20表示4倍优先级差异)
#    - 仅影响调度器评分,不保证绝对调度
#    - 所有weight累加不需要等于100
#
# 3. 与requiredDuringScheduling的区别:
#    - 若无满足preferred条件的节点,仍会调度到其他节点
#    - 调度器会选择综合评分最高的节点
#
# 典型应用场景:
# - 优先但不强制使用SSD节点
# - 多区域部署时优先选择低延迟区域
# - 优先使用有GPU的节点(但非必须)

# 使用建议:
# 1. 先标记节点标签:
# kubectl label nodes <node1> app=web
# kubectl label nodes <node2> tier=frontend
#
# 2. 验证调度结果:
# kubectl get pod test-node-affinity -o wide
#
# 3. 查看调度详情:
# kubectl describe pod test-node-affinity | grep -A 10 Events
#
# 4. 生产环境建议配合使用:
# - requiredDuringScheduling(硬性要求)
# - podAntiAffinity(避免同类Pod集中)
# - resource requests/limits(资源保障)

配置解析

  • 优先调度到有 app=web 标签的节点(权重80)
  • 其次考虑有 tier=frontend 标签的节点(权重20)
  • 若无匹配节点仍可调度到其他节点
  • 使用场景:优化性能但不强制要求

案例3:组合硬性和软性条件

yaml
apiVersion: v1
kind: Pod
metadata:
  name: combined-affinity
spec:
  affinity:  							# 亲和性配置,包含节点亲和性和Pod亲和性/反亲和性
    nodeAffinity:  						# 节点亲和性配置
      # 硬性要求部分(必须满足的条件)
      requiredDuringSchedulingIgnoredDuringExecution:  # 调度时必须满足的条件
        nodeSelectorTerms:  			# 节点选择条件列表
        - matchExpressions:  			# 标签匹配表达式列表
          - key: kubernetes.io/arch  	# 系统预定义的节点架构标签
            operator: In  				# 操作符:包含在values列表中
            values:  					# 允许的标签值
            - amd64  					# 必须运行在amd64架构的节点上
            # 注意:若不满足此条件,Pod将保持Pending状态

      # 软性偏好部分(优先考虑的条件)
      preferredDuringSchedulingIgnoredDuringExecution:  # 调度偏好(非强制)
      - weight: 1  						# 权重值(1-100),影响调度评分
        preference:  					# 偏好条件
          matchExpressions:  			# 标签匹配规则
          - key: disktype  				# 自定义磁盘类型标签
            operator: In  				# 操作符:包含在values列表中
            values:  					# 期望的标签值
            - ssd  						# 优先选择disktype=ssd的节点(但不强制)
            # 注意:若无SSD节点,仍可调度到其他满足硬性条件的节点

  containers:
  - name: nginx
    image: nginx
    # 生产环境建议添加resources配置:
    # resources:
    #   requests:
    #     cpu: "100m"
    #     memory: "128Mi"
    #   limits:
    #     cpu: "200m"
    #     memory: "256Mi"

# 关键字段说明:
# 1. requiredDuringSchedulingIgnoredDuringExecution:
#    - 这是硬性约束,节点必须满足条件才能被调度
#    - kubernetes.io/arch是Kubernetes自动添加的系统标签
#    - 多个matchExpressions之间是AND关系

# 2. preferredDuringSchedulingIgnoredDuringExecution:
#    - 这是软性偏好,调度器会优先考虑但不强制
#    - weight值用于多个偏好之间的优先级比较
#    - 即使没有满足偏好的节点,Pod仍会被调度

# 3. 组合使用策略:
#    - 先用required保证基本运行条件(如架构、区域)
#    - 再用preferred优化运行时性能(如SSD、GPU)

# 使用场景:
# - 必须运行在特定架构(如amd64)但优先使用高性能存储
# - 必须运行在特定区域但优先使用新型实例类型
# - 必须满足安全合规要求但优先使用资源充足的节点

# 操作建议:
# 1. 标记节点:
# kubectl label nodes <node-name> disktype=ssd
# kubectl get nodes --show-labels  # 查看标签

# 2. 验证调度:
# kubectl apply -f pod.yaml
# kubectl get pod -o wide  # 查看调度结果
# kubectl describe pod combined-affinity  # 查看详细事件

# 3. 生产建议:
# - 配合ResourceQuota使用防止资源耗尽
# - 结合PodDisruptionBudget保证高可用
# - 通过NodeSelector简化简单场景的配置

配置解析

  • 必须运行在 amd64 架构的节点上(硬性要求)
  • 优先选择有 SSD 磁盘的节点(软性偏好)
  • 使用场景:保证兼容性同时优化性能

节点亲和性操作符

节点亲和性支持多种匹配操作符:

操作符描述示例
In标签值在指定列表中values: ["web", "api"]
NotIn标签值不在指定列表中values: ["test"]
Exists标签必须存在(不检查值)不设置 values 字段
DoesNotExist标签必须不存在不设置 values 字段
Gt标签值大于指定值(数字比较)values: ["3"] (标签值 > 3)
Lt标签值小于指定值(数字比较)values: ["5"] (标签值 < 5)

数字比较示例

yaml
- key: gpu-count
  operator: Gt
  values: ["2"]  # 选择 GPU 数量大于2的节点

节点标记与管理命令

节点标签管理

bash
# 查看节点标签
kubectl get nodes --show-labels

# 添加/更新标签
kubectl label nodes <node-name> <label-key>=<label-value>

# 示例:标记节点为 web 类型
kubectl label node k8s-worker01 app=web

# 删除标签
kubectl label nodes <node-name> <label-key>-

验证调度结果

bash
# 查看 Pod 调度到的节点
kubectl get pod <pod-name> -o wide

# 查看调度失败原因
kubectl describe pod <pod-name>

# 查看节点详情(包括标签)
kubectl describe node <node-name>

Pod亲和

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

Pod亲和性核心概念

基本定义与作用

Pod亲和性是一种调度策略,允许用户定义新Pod与现有Pod之间的部署关系,包括:

  • 亲和性(Pod Affinity):使Pod倾向于与特定标签的Pod部署在同一拓扑域
  • 反亲和性(Pod Anti-Affinity):使Pod避免与特定标签的Pod部署在同一拓扑域

与节点亲和性不同,Pod亲和性关注的是Pod-to-Pod的关系而非Pod-to-Node的关系这种机制主要用于:

  • 实现服务间的紧密协同部署(如前端与缓存)
  • 保证服务的高可用性(分散部署相同服务的多个副本)
  • 优化网络通信性能(减少跨节点通信)
  • 满足数据局部性需求(如计算与存储的协同定位)

拓扑域(Topology Key)概念

拓扑域是理解Pod亲和性的关键概念,它定义了调度决策的范围边界,通过节点标签来划分:

  • kubernetes.io/hostname:节点级拓扑域(最细粒度)
  • failure-domain.beta.kubernetes.io/zone:可用区级拓扑域
  • failure-domain.beta.kubernetes.io/region:区域级拓扑域
  • 自定义标签:如rackswitch等物理拓扑标签

当使用topologyKey: "kubernetes.io/hostname"时,亲和性规则仅在单个节点范围内生效;而使用区域级标签时,规则会跨多个节点生效

Pod亲和性实现

硬性规则(Required)

测试pod

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app-backend
  labels:
    app: backend
spec:
  containers:
    - name: demo-pod
      image: nginx
      imagePullPolicy: Never

添加标签

bash
# 查看demo-app-backend创建的节点位置
kubectl get pod 
# 添加节点标签(拓扑)
kubectl label node k8s-node02 Region=bj

节点亲和性

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app-redis
  labels:
    app: redis
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        # Pod亲和性规则
        podAffinity:
          # 强制性的调度规则
          requiredDuringSchedulingIgnoredDuringExecution:
          # pod 标签选择器
          - labelSelector:
              matchLabels:
                app: backend
            # 节点拓扑标签
            topologyKey: Region
      containers:
      - name: redis
        image: redis:alpine3.22
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        ports:
        - containerPort: 6379
          name: redis

检测

bash
# 查看Deployment是否创建在和demo-app-backend相同的节点
kubectl get pod -owide

软性规则(Preferred)

yaml
# 偏好性的调度规则, 但不会影响已在节点上运行的Pod
preferredDuringSchedulingIgnoredDuringExecution:
  # 权重范围: 1~100, 权重值越大, 优先级越高
  - weight: 100
    podAffinityTerm:
      labelSelector:
        matchExpressions:
          - key: "app"
            operator: "In"
            values: ["db"]
      topologyKey: "kubernetes.io/hostname"

优先但不强制满足条件,通过weight(1-100)表示优先级

Pod反亲和性实现

测试pod

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app-backend
  labels:
    app: backend
spec:
  containers:
    - name: demo-pod
      image: nginx
      imagePullPolicy: Never

添加标签

bash
# 查看demo-app-backend创建的节点位置
kubectl get pod 
# 添加节点标签(拓扑)
kubectl label node k8s-node02 Region=bj

节点亲和性

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app-redis
  labels:
    app: redis
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        # Pod反亲和性规则
        podAntiAffinity:
          # 强制性的调度规则
          requiredDuringSchedulingIgnoredDuringExecution:
          # pod 标签选择器
          - labelSelector:
              matchExpressions:
                - key: app
                  operator: In
                  values:
                  - backend
            # 节点拓扑标签
            topologyKey: Region
      containers:
      - name: redis
        image: redis:alpine3.22
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        ports:
        - containerPort: 6379
          name: redis

检测

bash
# 查看Deployment是否创建在和demo-app-backend在不同的节点
kubectl get pod -owide

污点与容忍

污点(Taints)与容忍(Tolerations)是Kubernetes调度系统中的核心机制,用于实现节点与Pod之间的"选择性匹配",为生产环境提供了精细化的调度控制能力。

如果node节点有多个污点的话,在pod中需要全部设置。

污点(Taints)

污点是节点(Node)上的属性,用于排斥不符合条件的Pod被调度到该节点。

污点组成

每个污点包含三个部分:

  • key: 污点的标识符
  • value: 污点的值
  • effect: 污点的效果,决定如何排斥Pod

污点命名规范

  1. 标准化前缀

    使用 node-role.kubernetes.io/master作为键名,这是Kubernetes社区广泛认可的命名规范

  2. 语义化值

    • reserved:表示节点为系统保留资源
    • dedicated:表示专用节点(二选一)
  3. 效果选择

    NoSchedule(生产首选)比 NoExecute更温和,允许已有Pod继续运行

污点策略

策略说明
NoSchedule不容忍该污点的Pod不会被调度到该节点
PreferNoSchedule尽量避免调度不容忍的Pod,但不是强制的
NoExecute不容忍的Pod不会被调度到该节点,且已运行的Pod会被驱逐

污点操作命令

添加污点

bash
kubectl taint nodes <node-name> <key>=<value>:<effect>
# 示例:给master01添加dedicated专用污点
kubectl taint nodes k8s-master01 dedicated=master:NoSchedule

查看污点

bash
kubectl describe nodes <node-name> | grep Taints

删除污点

bash
kubectl taint nodes <node-name> <key>[:<effect>]-
# 示例:删除master01的dedicated污点
kubectl taint nodes k8s-master01 dedicated:NoSchedule-

容忍(Tolerations)

容忍是Pod上的配置,允许(但不强制)Pod被调度到带有特定污点的节点上。

容忍字段说明

字段说明可选值
key要匹配的污点键字符串
operator匹配操作符Exists(存在即可)或Equal(值相等)
value要匹配的污点值字符串
effect要匹配的污点效果NoSchedule, PreferNoSchedule, NoExecute
tolerationSeconds仅对NoExecute有效,指定被驱逐前的等待时间秒数

容忍配置

NoSchedule

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app
spec:
  containers:
    - name: demo-pod
      image: nginx
      imagePullPolicy: IfNotPresent
  # pod 容忍
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "master"
    # 污点策略
    effect: "NoSchedule"

Exists

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app
spec:
  containers:
    - name: demo-pod
      image: nginx
      imagePullPolicy: IfNotPresent
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "master"
    effect: "Exists"

带延迟的NoExecute容忍

yaml
apiVersion: v1
kind: Pod
metadata:
  name: demo-app
spec:
  containers:
    - name: demo-pod
      image: nginx
      imagePullPolicy: IfNotPresent
  tolerations:
  - key: "dedicated"
    operator: "Equal"
    value: "master"
    effect: "NoExecute"
    tolerationSeconds: 3600  # 1小时后才被驱逐