本文我向大家分享,我在一次公司业务故障处理时,如何通过分析下面这张截图和一些日志信息,成功处理一次 Kubernetes 集群里的 pod 频繁出现 eviction 的故障。
containerd
/var/lib/containerd
与 /var/lib/kubelet
位于同一块盘kube-state-metrics
与 Prometheus Operator;额外抓取 kubelet metrics
与 metrics/cadvisor
端点stdout/stderr
,无需 sidecar业务方报告某些命名空间的 Pod 间歇性被驱逐,Deployment 持续重建,波及面包含无状态与有状态服务。kubectl describe pod
的典型事件如下:
Warning Evicted kubelet The node was low on resource: ephemeral-storage.
这条信息在多家发行版与厂商的案例中高度一致,例如 Red Hat OpenShift 的知识库与社区贴都记录了相同的报错与上下文说明,包含 request=0
、using XXXKi
等具体文字片段,可据此快速判定为 ephemeral-storage
压力触发的节点级驱逐,而非 CPU/Memory 问题。
伴随节点侧 kubelet
日志出现 Eviction Manager 的判定与执行轨迹,例如:
eviction_manager.go:340 "Eviction manager: must evict pod(s) to reclaim" resourceName="ephemeral-storage"
eviction_manager.go:369 "Eviction manager: pods ranked for eviction" ...
eviction_manager.go:577 "Eviction manager: pod is evicted successfully" pod="ns/app-xxx"
这类 callstack/日志在社区长文与官方已知问题里均可见到同款关键字与函数文件名,足以佐证是 kubelet 的 Node-pressure Eviction 流程在工作。
更直观地,运维同学抓取了各节点 Current State vs Eviction Thresholds
的快照,可以看到 nodefs.available
、imagefs.available
、inodesFree
等信号与阈值的对比,imagefs.available
掉到 15% 以下就触发了驱逐控制环。这类截图在实践文章中亦有复现。
Kubernetes 官方把这种场景归类为 Node-pressure Eviction
。当 nodefs.available
、imagefs.available
、nodefs.inodesFree
、pid.available
等信号低于阈值,kubelet 会先尝试节点级回收(删 dead pods/containers
、回收未使用镜像),若无效才进入逐 Pod 驱逐排序与执行。阈值可分 evictionHard
与 evictionSoft
(含 GracePeriod
),回收还受 eviction-minimum-reclaim
影响以避免抖动。
这次事故的触发因子有两个:
ephemeral-storage
的 requests/limits
很多团队只给 CPU/Memory 设配额,却忘了本地临时存储。容器的日志、/tmp
、emptyDir
、镜像可写层都会消耗本地盘,超出节点阈值就会被判定为“挤占公共资源”
而被驱逐。 imagefs
/containerfs
压力触发时,kubelet 会先按 LRU 清理未用镜像;若清不下来,就按使用量排序驱逐 Pod。日志侧若未限制单容器日志大小与轮转份数,也会迅速吞噬本地盘与 inode
。 需要强调,描述里显示节点磁盘尚有空间
并不能反驳驱逐,因为触发条件看的是可用百分比与 inode
等多维信号,而非你肉眼看到的“还有几十 GB”
。类似的疑惑在社区讨论中屡见不鲜。
ephemeral-storage
驱逐kubectl describe pod <pod>
:Reason=Evicted
,Message=The node was low on resource: ephemeral-storage
。 eviction_manager.go
相关行,定位资源名为 ephemeral-storage
。(rakirahman.me)imagefs.available < 15%
)。inode
imagefs
是否与 nodefs
分盘(分盘能降低相互影响,官方博客有专门说明)。大日志/大临时文件/大编译缓存
;这部分属于 containerfs
。 metrics/cadvisor
的 container_fs_usage_bytes
与 inodes
相关指标,或用现成的导出器聚合 ephemeral-storage
用量。需注意不同运行时的指标完备度差异(例如早期 containerd
的磁盘指标覆盖不全).evictionSoft
与 eviction-minimum-reclaim
,让系统在缓冲区
内消化波动,而不是一跌破阈值就大杀四方
。示例与参数语义见官方与实战文章。 正面相撞
导致先触发驱逐才开始清理的尴尬。 ephemeral-storage
的 requests/limits
与命名空间级 ResourceQuota
。 以下 YAML/脚本在通用
kubeadm
/托管发行版上均可直接套用或少量调整。
ephemeral-storage
配额(Pod 级)apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: prod
spec:
replicas: 3
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: gateway
image: nginx:1.27
resources:
requests:
cpu: "100m"
memory: "256Mi"
ephemeral-storage: "2Gi"
limits:
cpu: "500m"
memory: "512Mi"
ephemeral-storage: "4Gi"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
sizeLimit: "2Gi"
官方文档明确 ephemeral-storage
可作为一等资源进行 requests/limits
管控,上述写法会直接参与调度与驱逐排序。
apiVersion: v1
kind: ResourceQuota
metadata:
name: rq-ephemeral
namespace: prod
spec:
hard:
requests.ephemeral-storage: "50Gi"
limits.ephemeral-storage: "100Gi"
社区给出了类似的配方,用于防止团队误配造成无限写盘
。
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "500Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
evictionSoft:
memory.available: "1Gi"
nodefs.available: "15%"
nodefs.inodesFree: "10%"
imagefs.available: "20%"
evictionSoftGracePeriod:
memory.available: "1m30s"
nodefs.available: "1m30s"
nodefs.inodesFree: "1m30s"
imagefs.available: "1m30s"
evictionMinimumReclaim:
nodefs.available: "1Gi"
imagefs.available: "2Gi"
containerLogMaxSize: "20Mi"
containerLogMaxFiles: 5
参数语义与官方参考一致:evictionSoft
叠加 GracePeriod
用于吸收短暂尖峰,evictionMinimumReclaim
避免回收一点就再次触发
的锯齿震荡;containerLogMax*
控制每容器日志大小与份数。
nodefs
的节点上,GC 会同时
删除 dead pod/container
与未用镜像;若存在独立的 imagefs
,两者各自清理,影响更可控。HighThresholdPercent/LowThresholdPercent
需拉开间距,减少频繁触发。 ephemeral-storage
接近上限如果集群已抓取 kubelet 的 cadvisor 指标,可以按容器可写层使用量与声明的 ephemeral-storage limit
做比值预警(不同环境指标来源略有差异,思路如下;若你的环境缺少此指标,可采用社区 k8s-ephemeral-storage-metrics
导出器):
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: ephemeral-storage-rules
namespace: monitoring
spec:
groups:
- name: k8s-ephemeral
rules:
- alert: ContainerEphemeralStorageNearLimit
expr: |
(container_fs_usage_bytes{image!=""}
/
on (namespace,pod,container)
group_left
kube_pod_container_resource_limits{resource="ephemeral_storage"})
> 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "容器临时存储使用超过 85%"
description: "{{ $labels.namespace }}/{{ $labels.pod }}/{{ $labels.container }}"
上述比值型告警依赖的两个度量在实践中常见:container_fs_usage_bytes
由 kubelet/cadvisor 暴露,kube_pod_container_resource_limits{resource="ephemeral_storage"}
由 kube-state-metrics
暴露,若你的运行时对磁盘指标支持欠缺,需要按环境调整或采用专门的 ephemeral-storage exporter
。
docker
的环境){
"log-driver": "json-file",
"log-opts": {
"max-size": "50m",
"max-file": "5"
}
}
在仍采用 docker
的节点上,直接用 daemon.json
控制容器日志体积与份数,避免日志把盘吃光。
kubectl describe pod
:The node was low on resource: ephemeral-storage. Container ... was using 8369512Ki, which exceeds its request of 0.
(来自 OpenShift/社区案例) kubelet
日志:Eviction manager: must evict pod(s) to reclaim resourceName="ephemeral-storage"
、pods ranked for eviction
、pod is evicted successfully
(来自实战文章与 kind 已知问题的日志样例) 上文开头配图展示了节点当前信号与阈值的对比界面,可作为
错误截图
的直观参照,用来佐证触发条件与阈值设置之间的关系。
ephemeral-storage
的 requests/limits
。这决定了谁更容易被驱逐
与能不能被调度进来
,别再只配 CPU/Memory。 nodefs/imagefs
与 inode
,而不是只看磁盘还剩多少 GB
。驱逐阈值按百分比/绝对值/可用 inode
等维度判断,表象空间还很多
并不能免责。 一碰就驱逐
的抖动。 containerLogMax*
与运行时配置控制单容器日志规模,必要时做压缩与保留天数限制。 imagefs
与 nodefs
分盘,镜像与容器可写层互不拖累;若只有一块盘,更要上好告警阈值。 ResourceQuota
限制 requests/limits.ephemeral-storage
的总量,避免团队内部某个任务失控写盘
拖垮全局。 ephemeral-storage
相关的告警,无论是直接抓 kubelet/cadvisor,还是引入专门 exporter,关键是尽早预警,留出处置窗口
.ephemeral-storage
是 Kubernetes 里极易被忽略但杀伤力巨大的第三资源。没有配额,它就像共享厨房的冰箱:谁都能塞,塞满了大家都得饿肚子。给关键工作负载补上 requests/limits
,把阈值与最小回收量调得合理,再把日志与镜像的增长曲线
用监控盯住,你的集群会安静许多,运维夜里也能睡得踏实。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。