在现代应用部署中,ref="/tag/2020/" style="color:#8B0506;font-weight:bold;">Kubernetes 已经成了“标配”。不管是电商大促时的流量高峰,还是公司内部服务的日常运行,背后很可能都有一套 Kubernetes 集群在默默支撑。而让这些服务稳定高效运行的关键之一,就是资源调度。
调度不是随便安排
你可能以为,只要节点上有空余 CPU 和内存,Pod 就能顺利启动。其实没那么简单。Kubernetes 的调度器(kube-scheduler)要做的,是给每个待运行的 Pod 找到最合适的节点,这个过程要考虑资源需求、亲和性、污点容忍、拓扑分布等多个因素。
比如,一个视频处理服务需要大量 CPU,而另一个数据库服务对磁盘 IO 要求高。如果把它们塞进同一台机器,互相抢资源,结果就是谁都跑不顺。调度器要避免这种情况,就像物业安排租户,不能让开直播的和要午睡的住隔壁。
资源请求与限制是基础
每个 Pod 都可以声明自己的资源需求:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
requests 是调度依据——调度器只会把 Pod 分配到能满足这些请求的节点上。limits 则是运行时的“天花板”,防止某个容器吃光资源影响他人。这就像租房时说好用电额度,超了会跳闸,但不会让整栋楼停电。
亲和性让服务更懂配合
有些服务最好在一起,比如前端和后端;有些则最好分开,比如两个关键数据库实例。NodeAffinity 和 PodAffinity 就是用来表达这种“社交偏好”的。
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: kubernetes.io/hostname
上面这段配置的意思是:已经运行了 Redis 的节点,不要再调度新的 Redis 实例上去。这样能避免单点故障,提升可用性。
污点和容忍控制谁能留下
某些节点可能专用于特定任务,比如 GPU 节点只跑 AI 模型。通过给节点加污点(Taint),可以拒绝普通 Pod 调度进来。
kubectl taint nodes node-1 gpu=used:NoSchedule
只有明确声明能容忍这个污点的 Pod 才能调度上去:
tolerations:
- key: "gpu"
operator: "Equal"
value: "used"
effect: "NoSchedule"
这就像贴了“谢绝推销”的门牌,只有持通行证的人才能进门。
调度也可以自定义
默认调度器够用,但在复杂场景下,可能需要自己写调度插件,或者部署多个调度器并行工作。比如订单系统高峰期优先调度,日志收集服务可以往后排。
Kubernetes 提供了调度框架(Scheduling Framework),允许你在“过滤”、“打分”等阶段插入自定义逻辑。就像快递分拣线,可以根据包裹目的地、重量、时效自动分道。
资源调度看似隐形,却直接影响着服务的响应速度和稳定性。理解它的工作方式,能让运维和开发更从容地应对变化,也让系统在压力之下依然保持节奏。