4. 故障根因分析(一):CoreDNS Pod 资源不足导致 OOM 或 CPU 节流
在 Kubernetes 集群中,CoreDNS 作为集群 DNS 的基石,其稳定性直接决定服务发现与域名解析的成败。当集群规模增长或流量突发时,CoreDNS Pod 极易因资源配额设置不当而陷入 OOM(Out of Memory) 或 CPU 节流(Throttling) 状态。本节将深入剖析这两种资源瓶颈的触发机制、典型表现及根因定位方法。
4.1 资源不足的两种典型场景
CoreDNS 进程对内存和 CPU 的消耗并非线性,而是与缓存条目数、并发查询量、日志级别及插件链复杂度强相关。以下表格对比了两种资源瓶颈的核心差异:
| 瓶颈类型 | 触发条件 | 典型现象 | 对 Pod 的影响 |
|---|---|---|---|
| OOM(内存耗尽) | DNS 缓存膨胀、大量并发查询导致内存分配超过 limits.memory |
Pod 频繁重启(CrashLoopBackOff)、dns_query_duration_seconds 突增 |
进程被内核 OOM Killer 强制终止,DNS 解析中断 |
| CPU 节流 | CPU 使用率持续触及 limits.cpu,CFS 配额耗尽 |
查询延迟升高、container_cpu_cfs_throttled_seconds_total 持续增长 |
请求排队,超时重试,上游 DNS 压力放大 |
关键警示: 很多团队只关注 Pod 是否存活,却忽略了 CPU 节流导致的“慢而不死”状态。这种状态下 Pod 仍在运行,但 DNS 响应延迟可能从毫秒级飙升到秒级,引发大规模超时雪崩。
4.2 OOM 根因分析:缓存膨胀与内存泄漏
CoreDNS 默认使用 cache 插件进行 DNS 响应缓存。当集群中服务数量巨大(例如 5000+ Service)或存在大量随机域名查询(如恶意扫描、错误配置),缓存条目会迅速膨胀。若 limits.memory 设置过小(如 64Mi),Pod 将频繁触发 OOM。
定位 OOM 问题的标准步骤:
- 检查 Pod 重启次数与原因:
kubectl get pods -n kube-system -l k8s-app=kube-dns,观察RESTARTS列。 - 查看上次退出状态:
kubectl describe pod <coredns-pod> -n kube-system,在Last State中查找Reason: OOMKilled。 - 分析内存使用趋势:通过 Prometheus 查询
container_memory_working_set_bytes{container="coredns"},观察是否在重启前呈阶梯式增长。 - 检查缓存命中率与条目数:CoreDNS 暴露
coredns_cache_entries_total和coredns_cache_hits_total指标,若条目数持续上升且命中率低,说明缓存策略或查询模式异常。
实战案例: 某电商集群 CoreDNS 内存限制为 128Mi,大促期间因商品搜索服务频繁解析不存在的域名(
.com 后缀拼写错误),导致 cache 插件为每个 NXDOMAIN 响应创建缓存条目,内存使用量在 10 分钟内从 60Mi 飙升至 130Mi,触发 OOM。
4.3 CPU 节流根因分析:CFS 配额与并发瓶颈
Kubernetes 使用 Completely Fair Scheduler (CFS) 的配额机制来限制 Pod 的 CPU 使用。当 CoreDNS 在 cpu.cfs_period_us(默认 100ms)内消耗的 CPU 时间超过 cpu.cfs_quota_us(由 limits.cpu 计算得出),进程会被强制节流,直到下一个周期才能继续运行。
CPU 节流的典型特征:
- 延迟抖动:P99 DNS 解析延迟从 5ms 跳变到 500ms 以上。
- 节流指标增长:
container_cpu_cfs_throttled_seconds_total持续非零。 - 并发请求堆积:CoreDNS 的
coredns_dns_requests_inflight指标持续接近或达到上限。
以下 SVG 展示了 CPU 节流如何导致 DNS 请求排队与超时扩散:
4.4 资源瓶颈的快速诊断命令
以下命令组合可以帮助 SRE 在 1 分钟内完成初步根因定位:
# 1. 查看 CoreDNS Pod 资源使用与限制
kubectl top pod -n kube-system -l k8s-app=kube-dns
# 2. 检查 OOM 历史
kubectl describe pod <coredns-pod> -n kube-system | grep -A 10 "Last State"
# 3. 查看 CPU 节流指标(需安装 metrics-server 或 Prometheus)
# 通过 cAdvisor 接口直接获取
kubectl get --raw /api/v1/nodes/<node-name>/proxy/metrics/cadvisor | grep "coredns" | grep "cfs_throttled"
# 4. 检查 CoreDNS 自身指标(需暴露 9153 端口)
kubectl port-forward -n kube-system pod/<coredns-pod> 9153:9153 &
curl -s http://localhost:9153/metrics | grep -E "coredns_cache|coredns_dns_requests_inflight"
4.5 资源限制的常见误区
团队在配置 CoreDNS 资源时,常陷入以下误区:
- 误区一:requests 等于 limits —— 导致 Pod 无法利用节点空闲的 CPU 或内存资源,在流量高峰时更容易触发节流或 OOM。
- 误区二:只设置 requests,不设置 limits —— 单个 CoreDNS Pod 可能抢占节点所有资源,影响其他系统组件。
- 误区三:内存限制设置过低,且未开启 swap —— Kubernetes 默认禁止容器 swap,内存超限即 OOM,无缓冲余地。
- 误区四:忽略 cache 插件的内存开销 —— 默认 cache 大小为 10000 条,每条约 2KB,仅缓存就需 20Mi,加上插件栈和连接池,64Mi 极易耗尽。
推荐实践: 初始设置
requests.cpu: 100m、limits.cpu: 500m、requests.memory: 70Mi、limits.memory: 256Mi。通过 Prometheus 监控实际使用量后,再基于 P99 使用率进行微调。同时开启 cache 插件的 prefetch 选项,减少突发查询对 CPU 的冲击。