Pod 驱逐策略与优先级
你的集群内存不足了,谁的 Pod 会被驱逐?为什么某些关键服务总是「运气好」不会被驱逐?
理解 Pod 驱逐机制,是保障集群稳定运行的关键。
Kubernetes 如何决定驱逐顺序
当节点资源紧张时,Kubernetes 按照以下顺序决定驱逐优先级:
┌─────────────────────────────────────────────────────────────────────┐
│ Pod 驱逐优先级 │
│ │
│ 优先级从低到高: │
│ │
│ 1. BestEffort(最低优先级) │
│ - 未设置 resources 的 Pod │
│ - QoS 等级:BestEffort │
│ │
│ 2. Burstable │
│ - 设置了 resources,但 request != limit │
│ - QoS 等级:Burstable │
│ │
│ 3. Guaranteed(最高优先级) │
│ - resources 的 request == limit │
│ - QoS 等级:Guaranteed │
│ │
│ 同优先级 Pod:随机选择 │
│ │
└─────────────────────────────────────────────────────────────────────┘QoS 等级判定
bash
# Guaranteed Pod
# 条件:所有容器都设置了 resources,且 request == limit
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "100m" # request == limit
# Burstable Pod
# 条件:至少一个容器设置了 resources,但不完全满足 Guaranteed
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m" # request != limit
# BestEffort Pod
# 条件:所有容器都未设置 resources
# 无任何 resources 配置资源不足时的驱逐场景
内存压力(Memory Pressure)
bash
# 节点内存不足时的驱逐顺序
kubectl describe node <node-name> | grep -A 10 "Conditions"
# 输出:
# Type Status
# MemoryPressure True ← 内存压力
# DiskPressure False
# PIDPressure False
# NetworkUnavailable False
# 节点状态为 MemoryPressure 时,kubelet 开始驱逐 Pod磁盘压力(Disk Pressure)
bash
# 磁盘空间不足
# - 镜像层占满磁盘
# - 日志文件过多
# - emptyDir 空间耗尽
# 排查
kubectl describe node <node-name> | grep "Conditions"
df -h
docker system dfPID 压力(PID Pressure)
bash
# 进程数过多
# 防止 fork 炸弹攻击
# 建议为 Pod 设置 pids limit
kubectl describe node <node-name> | grep "Conditions"
# Type Status
# PIDPressure True
# 解决方案
# 1. 限制 Pod 的 PID 数量
# 2. 排查异常进程Pod 优先级(Priority)
PriorityClass
yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 10000 # 优先级值,越大越高
globalDefault: false # 是否作为默认优先级
description: "生产环境关键服务"yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: medium-priority
value: 5000
description: "普通服务"yaml
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority
value: 1000
description: "测试环境服务"使用优先级
yaml
apiVersion: v1
kind: Pod
metadata:
name: critical-service
spec:
priorityClassName: high-priority
containers:
- name: nginx
image: nginx:alpine优先级对调度的影响
bash
# 高优先级 Pod 可以「抢占」低优先级 Pod 的资源
# 当集群资源不足时:
# 1. 高优先级 Pod 无法调度
# 2. 系统驱逐低优先级 Pod
# 3. 高优先级 Pod 调度成功
# 查看抢占决策
kubectl describe pod high-priority-pod | grep -A 10 "Events"
# Warning FailedScheduling ... Pod was rejected, pod is pending but cluster has insufficient free resource抢占调度(Preemption)
bash
# 抢占调度的工作流程
# 1. 高优先级 Pod 调度失败(Pending)
# 2. Scheduler 寻找可以驱逐低优先级 Pod 的节点
# 3. 驱逐低优先级 Pod
# 4. 高优先级 Pod 调度成功
# 查看被抢占的 Pod
kubectl get events --field-selector reason=Preemption
# 查看抢占后被驱逐的 Pod
kubectl get events --field-selector reason=Preempted优雅驱逐配置
tolerationSeconds
yaml
apiVersion: v1
kind: Pod
spec:
tolerations:
- key: dedicated
operator: Exists
effect: NoExecute
tolerationSeconds: 3600 # 节点被标记 NoExecute 后,3600 秒后才开始驱逐节点压力驱逐延迟
yaml
# kubelet 配置
# --eviction-pressure-transition-period 默认 5 分钟
# 节点进入压力状态后,等待一段时间才触发驱逐
# 给 Pod 足够时间响应 SIGTERM
# 调整 kubelet 配置
kubectl edit configmap kubelet-config -n kube-systemPod 中断预算(PDB)
PDB 确保在集群发生变更时,关键服务的最小副本数:
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
# 最少保持 2 个 Pod 运行
minAvailable: 2
# 或者使用百分比
# minAvailable: 50%
selector:
matchLabels:
app: webyaml
# 使用 maxUnavailable
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
maxUnavailable: 1 # 最多有 1 个 Pod 不可用
selector:
matchLabels:
app: webPDB 工作原理
┌─────────────────────────────────────────────────────────────────────┐
│ Pod 中断预算工作原理 │
│ │
│ Deployment 配置:replicas=5 │
│ PDB 配置:minAvailable=3 │
│ │
│ 允许同时中断的 Pod 数 = 5 - 3 = 2 │
│ │
│ 节点维护场景: │
│ - 节点 A 需要维护 │
│ - 节点 A 上有 3 个 web Pod │
│ - 系统最多驱逐 2 个 Pod │
│ - 剩余 3 个 Pod 保证服务可用 │
│ │
└─────────────────────────────────────────────────────────────────────┘查看 PDB 状态
bash
# 查看 PDB 状态
kubectl get pdb
# 输出:
# NAME MINAVAILABLE MAXUNAVAILABLE ALLOWEDDISRUPTIONS
# web-pdb 2 N/A 3
# 查看 PDB 详情
kubectl describe pdb web-pdb
# 查看允许的中断次数
kubectl exec -it web-deployment-xxx -- kubectl get pdb常见驱逐场景
场景1:节点缩容
bash
# 缩减节点池
# 节点上的 Pod 需要重新调度
# 过程:
# 1. 节点被标记为不可调度
kubectl cordon node-1
# 或
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data
# 2. Pod 被驱逐到其他节点
# 3. 考虑 PDB 约束
# 4. 逐个驱逐,直到满足 PDB场景2:资源不足
bash
# 原因:
# - 节点资源不足(内存/磁盘/CPU)
# - Pod 请求的资源超过节点可用
# 表现:
# - Pod 处于 Pending
# - 现有 Pod 被驱逐
# 解决方案:
# 1. 增加节点
# 2. 降低 Pod 资源请求
# 3. 配置资源配额(ResourceQuota)
# 4. 使用 Cluster Autoscaler场景3:节点异常
bash
# 节点 NotReady
kubectl get nodes
# 输出:
# NAME STATUS ROLES AGE
# node-1 NotReady worker 100d
# kubelet 无法与 API Server 通信
# 节点上的 Pod 被标记为 Terminating
# Controller Manager 开始重新调度
# 等待时间(默认 40 秒)
# --pod-eviction-timeout 40s驱逐调试
bash
# 查看驱逐事件
kubectl get events --field-selector reason=Eviction
# 查看 Pod 被驱逐原因
kubectl describe pod <pod-name> | grep -A 10 "Events"
# 查看节点压力状态
kubectl describe node <node-name> | grep -A 10 "Conditions"
# 查看 kubelet 日志
kubectl logs -n kube-system kubelet-<node-name> --tail=100
# 查看 Pod 的 QoS 等级
kubectl get pod <pod-name> -o jsonpath='{.status.qosClass}'最佳实践
1. 设置合理的资源请求
yaml
# 推荐:为所有 Pod 设置资源请求
# 确保调度器能正确决策
# 确保 QoS 等级正确
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"2. 使用优先级类
yaml
# 为关键服务设置高优先级
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: production-critical
value: 100000
globalDefault: false
---
apiVersion: v1
kind: Pod
spec:
priorityClassName: production-critical3. 配置 PDB
yaml
# 为关键服务配置 PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: critical-app-pdb
spec:
minAvailable: 2 # 始终保留至少 2 个副本
selector:
matchLabels:
app: critical-app4. 配置优雅终止
yaml
spec:
terminationGracePeriodSeconds: 60
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]面试追问
- Kubernetes 驱逐 Pod 的顺序是什么?依据是什么?
- 什么是 QoS 等级?Guaranteed、Burstable、BestEffort 怎么判定?
- Pod 优先级是怎么实现的?高优先级 Pod 可以抢占低优先级的吗?
- PodDisruptionBudget 是怎么工作的?它能保证什么?
- 节点内存不足时,kubelet 是怎么决定驱逐哪些 Pod 的?
"Pod 驱逐看似是 Kubernetes 自动处理的,但理解其机制才能设计出稳定可靠的系统。设置合理的资源请求、使用优先级、配置 PDB——这些都是在为『万一』做准备,而 Kubernetes 生产环境,『万一』总会发生。"
