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 问题的标准步骤:

  1. 检查 Pod 重启次数与原因:kubectl get pods -n kube-system -l k8s-app=kube-dns,观察 RESTARTS 列。
  2. 查看上次退出状态:kubectl describe pod <coredns-pod> -n kube-system,在 Last State 中查找 Reason: OOMKilled。
  3. 分析内存使用趋势:通过 Prometheus 查询 container_memory_working_set_bytes{container="coredns"},观察是否在重启前呈阶梯式增长。
  4. 检查缓存命中率与条目数: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 请求排队与超时扩散:

CoreDNS CPU 节流导致请求排队与超时扩散 客户端请求 CoreDNS 正常处理 响应返回 高并发请求涌入 CPU 配额耗尽 CFS 节流开始 请求排队等待 客户端重试 排队超时 DNS 解析失败 结果:应用层 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 的冲击。