使用 `docker stats` 与 `cadvisor` 定位 CPU 热点容器

解读

国内一线/准一线企业在云原生面试中,高频出现“线上 CPU 飙高,如何 5 分钟内定位到具体容器”这一场景题。
面试官真正想考察的是:

  1. 你是否能在不登录容器内部的前提下,先通过 Docker 原生工具快速缩小范围;
  2. 你是否知道 docker stats实时性字段盲区(无 per-core、无 cgroups v2 细项),并主动补位;
  3. 你是否能把 cadvisor 的多维指标容器元数据关联,完成二次下钻;
  4. 你是否具备自动化闭环意识:发现问题→定位根因→记录指标→固化到监控。
    答不到“自动化闭环”,基本只能给到中级评分。

知识点

  • docker stats 的采集原理:通过 Docker Engine API 读取 cgroup cpuacct.stat 与 cpu.stat,1 s 刷新一次,字段 CPU % = (delta usage / delta system) × 100。
  • cgroup v1 与 v2 的 CPU 指标差异:v1 分 cpuacct.usage_percpu、throttling stats;v2 统一为 cpu.stat。
  • cadvisor 的容器级 CPU 热点指标
    – container_cpu_usage_seconds_total{cpu=“total|0|1…”},可算 per-core;
    – container_cpu_cfs_throttled_periods_total,判断是否被限流;
    – container_spec_cpu_quota / period,反推 CPU limit。
  • PromQL 定位套路:
    rate(container_cpu_usage_seconds_total{name!~“POD|”}[1m])
    by (name, id) 找出突增容器;再 and on (id) increase(container_cpu_cfs_throttled_periods_total[1m]) > 0 判断是否因限流导致毛刺。
  • 国内混合云场景常见坑:
    – 宿主机开启超线程,top 看到的 200% 实际是单核跑满;
    – 部分发行版默认挂载cgroup v2,老版本 cadvisor 需加 --enable-cgroupv2 启动参数;
    – 安全合规要求非 root 运行 cadvisor,需加 --docker_only --housekeeping_interval=10s 降低权限与开销。

答案

现场回答采用“三段式”节奏,总时长控制在 3 分钟,既展示思路又给出可落地命令。

  1. 30 秒初筛:
    docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.Container}}" | sort -k2 -hr | head -10
    直接输出 CPU 占比最高的容器列表,快速锁定嫌疑容器

  2. 90 秒下钻:
    若宿主机已部署 cadvisor(国内公司普遍以 DaemonSet 方式跑在 K8s 每个节点),立即在 Prometheus 执行:
    topk(5, rate(container_cpu_usage_seconds_total{instance=~"节点IP:8080"}[1m]))
    拿到容器 ID 后,再查 per-core 热点:
    rate(container_cpu_usage_seconds_total{container_label_com_docker_swarm_service_name="可疑服务"}[1m]) by (cpu)
    如果某一核接近 100%,即可判定单线程热点;若所有核均匀上涨,则可能是多线程死循环或频繁 GC

  3. 60 秒闭环:
    将上述 PromQL 固化成 Grafana 面板,并加告警:
    rate(container_cpu_usage_seconds_total[1m]) / on (id) (container_spec_cpu_quota / container_spec_cpu_period) > 0.8
    连续 5 min 超过阈值即飞书/钉钉告警卡片附带容器日志链接,实现“定位→通知→复盘”自动化。

如是 Docker Swarm 环境,没有 Prometheus,可直接 curl 节点IP:8080/metrics | grep container_cpu_usage_seconds_total 用本地脚本排序,思路完全一致。

拓展思考

  1. 当容器 CPU 突增但 docker stats 显示正常,需考虑宿主机 steal 时间过高(国内公有云超卖场景)。此时应联合 node_cpu_seconds_total{mode="steal"} 判断,再决定是否升配或迁移节点。
  2. 若 cadvisor 指标延迟太大(默认 1 min HouseKeeping),可在启动参数加 --housekeeping_interval=5s --docker_only,但需评估cgroup 接口 QPS对宿主机 1% 以内的额外开销。
  3. 对于金融级安全要求,cadvisor 不允许宿主机直接暴露 8080,需通过NodeLocal Prometheus + TLS 双向认证采集,避免 metrics 接口泄露容器环境变量。
  4. 最终极方案是把 CPU 热点指标与持续剖析(pyroscope、parca)联动,实现“指标告警→一键下发 eBPF 火焰图→定位到函数”,把面试答案从“定位容器”提升到“定位代码行”,直接锁定资深专家评级。