好的,这是一个非常核心的Kubernetes话题。Kubernetes提供了非常丰富和灵活的调度方式,从最简单到最复杂,可以满足各种部署需求。
Pod的调度方式主要可以分为以下几大类:
1. 自动调度:最基本的调度
这是最常见的方式。您只需定义一个Pod(通常通过Deployment、StatefulSet等控制器来管理),不指定任何节点相关的约束。那么调度器(kube-scheduler)会自动为您选择一个最合适的Node来运行Pod。
调度器基于其调度算法和策略进行决策,主要考虑两大因素:
- 资源需求与限制(Resources Requests/Limits):确保Node有足够的CPU和内存资源来运行Pod。
- 硬件/软件约束(Hardware/Software Constraints):Pod是否要求特定的操作系统、架构(如amd64/arm64)等。
这是默认且最常用的方式,体现了Kubernetes的声明式API和自动化运维的优势。
2. 定向调度:将Pod分配到特定节点
这种方式允许您显式地告诉Kubernetes将Pod调度到某一个或某一类Node上。
a) nodeName
最直接的方式,直接在Pod Spec中指定节点的名称。这会绕过调度器,直接强制将Pod部署到指定节点。
- 缺点:如果该节点不存在或不资源不足,Pod会运行失败。
- 适用场景:调试或非常特殊的静态环境,一般不推荐生产使用。
apiVersion: v1
kind: Pod
metadata:name: nginx
spec:containers:- name: nginximage: nginxnodeName: k8s-node-01 # 直接指定节点主机名
b) nodeSelector
通过为Node打上标签(Label),并为Pod指定对应的标签选择器(Selector),来实现简单的定向调度。
- 步骤:
- 给Node打标签:
kubectl label nodes <node-name> disktype=ssd - 在Pod Spec中定义
nodeSelector。
- 给Node打标签:
apiVersion: v1
kind: Pod
metadata:name: nginx-ssd
spec:containers:- name: nginximage: nginxnodeSelector:disktype: ssd # 只会调度到带有 disktype=ssd 标签的节点上
3. 亲和性与反亲和性 (Affinity/Anti-affinity):更高级的定向调度
这是nodeSelector的升级版,提供了更强大、更灵活的表达能力。它通过 affinity 字段来定义。
a) 节点亲和性 (Node Affinity)
类似于 nodeSelector,但语法更强大,支持软偏好(soft/preferred) 和硬要求(hard/required) 规则,以及更丰富的操作符(In, NotIn, Exists, Gt, Lt等)。
requiredDuringSchedulingIgnoredDuringExecution(硬策略):必须满足的条件,不满足则不调度。preferredDuringSchedulingIgnoredDuringExecution(软策略):偏好满足的条件,不满足也会调度。
apiVersion: v1
kind: Pod
metadata:name: with-node-affinity
spec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: topology.kubernetes.io/zoneoperator: Invalues:- ap-southeast-1apreferredDuringSchedulingIgnoredDuringExecution:- weight: 1preference:matchExpressions:- key: another-node-labeloperator: Invalues:- another-node-label-valuecontainers:- name: nginximage: nginx
b) Pod间亲和性与反亲和性 (Inter-Pod Affinity/Anti-affinity)
这是最强大的调度策略之一,它根据已经在节点上运行的Pod的标签来调度新Pod,而不是根据Node的标签。
- Pod亲和性 (Pod Affinity):将Pod调度到已经有某类Pod运行的节点上(例如,将Web服务部署到已经有Redis缓存的节点上,减少网络延迟)。
- Pod反亲和性 (Pod Anti-affinity):让Pod远离某类Pod,避免部署到同一个节点、机架或可用区(例如,保证同一应用的两个实例不在同一个节点或可用区,实现高可用)。
# 使用反亲和性实现高可用:确保同一个应用的Pod不被调度到同一个节点
apiVersion: apps/v1
kind: Deployment
metadata:name: web-server
spec:replicas: 3selector:matchLabels:app: web-storetemplate:metadata:labels:app: web-storespec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- web-storetopologyKey: kubernetes.io/hostname # 拓扑域为“主机名”,即不能在同一台机器containers:- name: web-appimage: nginx:latest
4. 污点和容忍度 (Taints and Tolerations):让节点排斥Pod
这与亲和性的作用相反。亲和性是“Pod吸引Pod”,而污点和容忍度是“Node排斥Pod”。
- 污点 (Taint):应用于Node上,表示该节点拒绝不能“容忍”这个污点的Pod。
- 容忍度 (Toleration):应用于Pod上,允许(但非强制)Pod调度到带有对应污点的Node上。
常见应用场景:
- 专用节点:将某些节点专用于特定团队或特定类型的任务(如GPU机器学习)。
- 边缘节点/有问题的节点:给即将维护或资源耗尽的节点打上污点 (
NoSchedule),阻止新Pod调度上来。 - Master节点:Kubernetes默认给Master节点打上了
node-role.kubernetes.io/control-plane:NoSchedule污点,以防止普通业务Pod调度到Master上。
给Node打污点:
kubectl taint nodes node01 key=value:NoSchedule
在Pod上配置容忍度:
apiVersion: v1
kind: Pod
metadata:name: my-pod
spec:containers:- name: nginximage: nginxtolerations:- key: "key"operator: "Equal"value: "value"effect: "NoSchedule"
5. 其他调度方式
DaemonSet:在每个节点上运行一个Pod副本
这是一种特殊的控制器,它确保所有(或匹配的)节点上都运行一个且只有一个指定的Pod副本。常用于运行系统级别的守护进程,如:
- 日志收集器(Fluentd, Filebeat)
- 节点监控代理(Prometheus Node Exporter)
- 网络插件(Calico, Cilium)
静态Pod (Static Pod)
由特定节点上的 kubelet 守护进程直接管理,不需要通过API服务器进行调度。Pod定义文件放在节点的特定目录(如 /etc/kubernetes/manifests)下。kubelet 会定期扫描该目录并创建/删除Pod。
- 主要用途:用于部署Kubernetes自身的核心组件,如
kube-apiserver,kube-scheduler,kube-controller-manager等(常用在kubeadm搭建的集群中)。
总结
| 调度方式 | 核心思想 | 适用场景 |
|---|---|---|
| 自动调度 | 由调度器全权决定 | 最通用的场景,无特殊需求的应用 |
| nodeSelector | 简单标签匹配 | 需要调度到具有特定硬件(如SSD、GPU)的节点 |
| 节点亲和性 | 更丰富的节点标签匹配规则(软/硬策略) | 复杂的节点选择需求,如优先选择某个可用区 |
| Pod间亲和/反亲和 | 根据已有Pod来调度新Pod | 高可用(分散部署)、低延迟(集中部署) |
| 污点和容忍度 | 让节点排斥Pod | 专用节点、隔离故障节点、保护Master节点 |
| DaemonSet | 每个节点运行一个Pod | 系统级守护进程(日志、监控、网络) |
| 静态Pod | 由kubelet直接管理 | 部署Kubernetes自身系统组件 |
在实际生产环境中,通常会组合使用多种策略。例如,先使用污点隔离出专用GPU节点,然后使用节点亲和性或nodeSelector将机器学习任务Pod调度到这些节点上,同时使用Pod反亲和性确保这些任务自身不会堆积在同一个节点上。
