集群调度
1、kubernetes 调度机制
各组件(如 controller-manager
、scheduler
、kubelet
)通过监听 API Server 事件协同工作。
1.1 default-scheduler 调度策略
1.1.1 预选策略(predicates):过滤不满足条件的节点
- PodFitsResources:检查节点剩余资源是否满足
requests
。 - PodFitsHostPorts:检查节点端口是否冲突。
- NoDiskConflict:检查存储卷冲突。
1.1.2 优选策略(Priorities):计算节点优先级。
- LeastRequestedPriority:优先选择资源利用率低的节点。
- BalancedResourceAllocation:优先选择 CPU/内存使用均衡的节点。
- ImageLocalityPriority:优先选择已缓存镜像的节点。
1.1.3 打分评定最终调度节点
2、简单标签操作命令
# 添加/修改标签
kubectl label -n <namespace> <resource-type> <resource-name> key=value [--overwrite]
# 删除标签
kubectl label -n <namespace> <resource-type> <resource-name> key-
# 查看标签
kubectl get <resource-type> -n <namespace> --show-labels
kubectl get <resource-type> -n <namespace> -l key=value
2.1 指定node节点部署pod
nodeName
:直接指定节点名称。
spec:
nodeName: node01
nodeSelector
:通过节点标签选择。
spec:
nodeSelector:
disktype: ssd
- 亲和性(Affinity):
- 节点亲和性:匹配节点标签。
- Pod 亲和性/反亲和性:匹配其他 Pod 的标签。
- 污点与容忍(Taint & Toleration):
- 节点设置污点(
kubectl taint nodes node01 key=value:NoSchedule
)。 - Pod 配置容忍以调度到污点节点。
3、kube-scheduler
3.1 调度过程
Kubernetes 的调度器(Scheduler)负责将定义的 Pod 分配到集群的节点上。调度过程主要关注公平性、资源高效利用、效率和灵活性。调度器运行为一个独立的程序,持续监听 APIServer,并处理 spec.nodeName 为空的 Pod。
调度过程分为以下几个步骤:
Kubernetes 的调度器(Scheduler)负责将定义的 Pod 分配到集群的节点上。调度过程主要关注公平性、资源高效利用、效率和灵活性。调度器运行为一个独立的程序,持续监听 APIServer,并处理 spec.nodeName 为空的 Pod。
调度过程分为以下几个步骤:
-
Predicate(过滤阶段):
- 调度器首先会过滤掉不满足条件的节点。
- 常见的 Predicate 算法包括:PodFitsResources(检查节点资源是否足够)、PodFitsHost(检查节点名称是否与 Pod 指定的 NodeName 匹配)、PodFitsHostPorts(检查节点端口是否与 Pod 请求的端口冲突)、PodSelectorMatches(过滤掉与 Pod 指定的 label 不匹配的节点)和 NoDiskConflict(检查已挂载的 volume 是否与 Pod 指定的 volume 冲突)。
-
Priorities(优选阶段):
- 如果有多个节点满足条件,调度器会根据优先级对节点进行排序。
- 优先级由一系列键值对组成,表示不同的优先级项目和其权重。
- 常见的优先级选项包括:LeastRequestedPriority(倾向于资源使用比例更低的节点)、BalancedResourceAllocation(倾向于 CPU 和 Memory 使用率更接近的节点)和 ImageLocalityPriority(倾向于已经有要使用镜像的节点)。
-
Binding(绑定阶段):
- 调度器选择优先级最高的节点,并创建一个 binding,表明该 Pod 应该被调度到哪个节点上。
3.1 Kubernetes Scheduler 工作原理
Scheduler 是 Kubernetes 的核心组件,负责将 Pod 分配到集群的合适节点上。其调度过程主要关注以下方面:
- 公平性:确保每个节点都能被分配资源。
- 资源高效利用:最大化集群资源的利用率。
- 效率:快速调度大批量的 Pod。
- 灵活性:允许用户根据需求自定义调度逻辑。
Scheduler 启动后会持续监听 APIServer,获取 spec.nodeName 为空的 Pod,并为每个 Pod 创建一个 binding,指明其应部署的节点。
3.2 示例操作 :指定节点调度
使用 nodeName 指定调度节点
- 创建一个 Deployment,指定
nodeName
为node01
。 - 应用 YAML 文件后,所有 Pod 都会被调度到
node01
上。 - 通过
kubectl describe pod
查看 Pod 事件,发现未经过 Scheduler 调度分配。
使用 pod.spec.nodeName:
- 通过在 Pod 定义中指定 nodeName,可以直接将 Pod 调度到指定的节点上,这会跳过调度器的调度策略。
- 示例 YAML 配置如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
nodeName: node01
containers:
- name: myapp
image: soscscs/myapp:v1
ports:
- containerPort: 80
3.3 修改和删除label
- 使用
kubectl label
命令修改和删除节点标签。 - 修改节点的 label 需要使用
--overwrite
参数:
kubectl label nodes node02 myname=a --overwrite
删除节点的 label 只需在命令行最后指定 label 的 key 名,并在其后加上减号:
kubectl label nodes node02 myname-
可以使用 -l
参数根据 label 查询节点:
kubectl get node -l myname=a
4、亲和性和反亲和性
4.1 node节点亲和性概述
在 Kubernetes 中,亲和性(Affinity)和反亲和性(Anti-Affinity)用于定义 Pod 调度到节点的规则。主要分为两类:
- 节点亲和性(Node Affinity):定义 Pod 与节点的关系。
- Pod 亲和性(Pod Affinity)和Pod 反亲和性(Pod Anti-Affinity):定义 Pod 与 Pod 之间的关系。
每种亲和性都可以进一步细分为硬策略和软策略:
- 硬策略(requiredDuringSchedulingIgnoredDuringExecution):必须满足的条件,不满足则 Pod 无法调度。
- 软策略(preferredDuringSchedulingIgnoredDuringExecution):优先满足的条件,不满足时仍会调度 Pod,但会尽量满足。
4.2 键值运算关系
在定义亲和性规则时,可以使用以下键值运算关系:
In
:label 的值在某个列表中NotIn
:label 的值不在某个列表中Gt
:label 的值大于某个值(数值比较)Lt
:label 的值小于某个值(数值比较)Exists
:某个 label 存在DoesNotExist
:某个 label 不存在
示例
4.2.1 节点亲和硬策略
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02
可见该文件中定义了一个 Pod,要求该Pod调度到 kubernetes.io/hostname
不为 node02
的节点上。
如果所有节点都不满足条件,Pod 将一直处于 Pending 状态。
4.2.2 节点亲和软策略
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node01
这个文件中定义了的Pod,被优先调度到 kubernetes.io/hostname
为 node01
的节点上。
但不满足时也会调度到其他节点。
4.2.3 硬策略和软策略结合
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: myname
operator: In
values:
- a
这个文件定义的 Pod,首先要求调度到 kubernetes.io/hostname
不为 node02
的节点上,然后在满足硬策略的基础上,优先调度到 myname
为 a
的节点上。
4.3 pod的亲和性和反亲和性
Pod 亲和性(Pod Affinity)和反亲和性(Pod Anti-Affinity)是用于定义 Pod 调度策略的两种机制。
可以使 Pod 可以根据其他 Pod 的标签和位置来决定自己的调度位置。
调度策略与匹配标签
- nodeAffinity:基于节点的标签进行调度。不支持拓扑域。
- podAffinity:基于其他 Pod 的标签进行调度,并支持拓扑域。
- podAntiAffinity:基于其他 Pod 的标签进行调度,但要求不在同一拓扑域。
操作符与拓扑域支持
- 操作符:
In
,NotIn
,Exists
,DoesNotExist
,Gt
,Lt
(对于 nodeAffinity 的特定场景)。 - 拓扑域支持:podAffinity 和 podAntiAffinity 支持拓扑域,通过
topologyKey
指定。
4.4 实际调度
-
给节点打标签:
kubectl label nodes node01 myname=a kubectl label nodes node02 myname=a
-
创建第一个 Pod:
apiVersion: v1 kind: Pod metadata: name: myapp01 labels: app: myapp01 spec: containers: - name: with-node-affinity image: soscscs/myapp:v1
kubectl apply -f pod3.yaml
-
使用 Pod 亲和性调度第二个 Pod:
apiVersion: v1 kind: Pod metadata: name: myapp02 labels: app: myapp02 spec: containers: - name: myapp02 image: soscscs/myapp:v1 affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - myapp01 topologyKey: myname
kubectl apply -f pod4.yaml
myapp02
将被调度到与myapp01
相同的拓扑域(myname=a
的节点)上。
-
使用 Pod 反亲和性调度第三个 Pod:
-
示例 1:首选调度(Preferred)
apiVersion: v1 kind: Pod metadata: name: myapp10 labels: app: myapp10 spec: containers: - name: myapp10 image: soscscs/myapp:v1 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - myapp01 topologyKey: kubernetes.io/hostname
kubectl apply -f pod5.yaml
myapp10
将尽量避免与myapp01
在同一节点上调度(kubernetes.io/hostname
表示节点级别)。
-
示例 2:强制调度(Required)
apiVersion: v1 kind: Pod metadata: name: myapp20 labels: app: myapp20 spec: containers: - name: myapp20 image: soscscs/myapp:v1 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - myapp01 topologyKey: myname
kubectl apply -f pod6.yaml
myapp20
强制要求不在与myapp01
相同的拓扑域上调度。如果所有节点都在同一拓扑域,Pod 将保持 Pending 状态。
-
-
调整节点标签以允许调度:
kubectl label nodes node02 myname=b --overwrite
- 修改
node02
的标签后,myapp20
可以被调度到node02
上,因为它现在处于不同的拓扑域。
- 修改
4.5 总结
三种亲和性类型
类型 | 定义 | 策略 |
---|---|---|
Node Affinity | 根据节点的标签,将 Pod 调度到满足条件的节点上。 | - 硬策略 (requiredDuringSchedulingIgnoredDuringExecution ):必须满足条件,否则 Pod 处于 Pending 状态。- 软策略 ( preferredDuringSchedulingIgnoredDuringExecution ):优先满足条件,不满足仍可调度。 |
Pod Affinity | 根据同一命名空间下其他 Pod 的标签,将 Pod 调度到与指定 Pod 在同一拓扑域的节点上。 | - 硬策略:必须与指定 Pod 在同一拓扑域。 - 软策略:优先与指定 Pod 在同一拓扑域。 |
Pod Anti-Affinity | 根据同一命名空间下其他 Pod 的标签,将 Pod 调度到与指定 Pod 不同拓扑域的节点上。 | - 硬策略:必须与指定 Pod 在不同拓扑域。 - 软策略:优先与指定 Pod 在不同拓扑域。 |
拓扑域判断规则
亲和性类型 | 规则 | topologyKey 作用 | 示例 topologyKey 值 |
---|---|---|---|
Pod Affinity | Pod 必须或优先调度到与目标 Pod 同一拓扑域的节点上。 | 通过节点标签的键(如 kubernetes.io/hostname )判断是否属于同一逻辑域(如同一主机、可用区)。 | - kubernetes.io/hostname (节点主机名)- failure-domain.beta.kubernetes.io/zone (可用区) |
Pod Anti-Affinity | Pod 必须或优先调度到与目标 Pod 不同拓扑域的节点上。 | 通过节点标签的键确定逻辑域,确保 Pod 分布在不同域中以提高容灾能力。 | - kubernetes.io/hostname - topology.kubernetes.io/region (区域) |
Node Affinity | 不依赖 topologyKey ,直接通过节点标签匹配调度。 | 无 |