构建 Docker 监控指标体系的核心目标,是在容器生命周期内持续获取准确、多维度的运行状态数据,从而在性能瓶颈、资源泄漏或异常退出发生前发出预警。与传统虚拟机监控不同,容器共享宿主机内核,拥有独立的 Namespace 和 Cgroup 限制,这决定了监控指标必须同时覆盖宿主机物理资源与容器逻辑资源两个层面。如果仅采集宿主机的 CPU 使用率,就无法判断具体是哪个容器引发了资源争抢。

一、Docker 监控的核心指标分类与采集原理
Docker 容器的可观测性建立在 Cgroup 文件系统之上。Linux 将每个容器的资源限制与使用情况记录在 /sys/fs/cgroup 目录下,例如 cpuacct.usage 记录 CPU 累计使用纳秒数,memory.usage_in_bytes 记录当前内存占用。Docker 守护进程本身通过 API 暴露部分状态,但更完整的指标通常由 cAdvisor 采集。cAdvisor 作为常驻 DaemonSet 或二进制运行,会自动发现本机容器,并周期性读取 Cgroup 与容器元数据,转换成 Prometheus 可抓取的格式。
从监控维度看,指标可分为四类。其一是计算类,包含容器 CPU 使用率、CPU 节流次数(throttling)、负载均值;其二是存储类,包含内存 RSS、缓存、交换分区、OOM 事件次数;其三是网络类,包含接收发送字节数、丢包数、错误数;其四是生命周期类,包含容器重启次数、退出码、运行状态。很多团队初期只配置 CPU 与内存告警,导致网络丢包或频繁重启问题长期隐蔽。下面是一段通过 cAdvisor 接口获取容器 CPU 指标的示例。
# 使用 curl 访问 cAdvisor 暴露的 Prometheus 接口
curl http://localhost:8080/metrics | grep container_cpu_usage_seconds_total
# 输出示例(已转义尖括号仅为说明,实际为纯文本)
# container_cpu_usage_seconds_total{name="web",image="nginx"} 12.34
需要注意的是,docker stats 命令虽然能实时展示容器资源,但其数据来自 Docker 守护进程的内存计算,刷新间隔与历史存储能力弱,不适合作为长期监控源。生产环境应优先采用 cAdvisor 加 Prometheus 的方案,将指标写入时序数据库以便回溯。
二、基于 Prometheus 的标签体系与查询实践
Prometheus 通过拉取(pull)模式从 cAdvisor 或 node-exporter 获取指标。最关键的是标签(label)设计。一个容器指标通常带有 container_label_ 前缀的业务标签、pod_name、namespace 等 Kubernetes 注入标签,以及 image 和 id。若标签缺失,当上百个容器运行时,你无法在 Grafana 里筛选特定服务。建议在容器启动时就通过 --label 写入环境、版本、负责人信息。
查询时常用 PromQL 计算速率与利用率。例如计算最近五分钟容器 CPU 平均使用率,可使用 rate(container_cpu_usage_seconds_total[5m])。而对于内存压力,不能简单看 container_memory_usage_bytes,因为其中包含了缓存。应结合 container_memory_working_set_bytes 判断真实工作压力,并与 Cgroup 限制 container_spec_memory_limit_bytes 对比。以下代码展示了 PromQL 告警规则示例。
groups:
- name: docker-memory-alert
rules:
- alert: ContainerMemoryNearLimit
expr: container_memory_working_set_bytes / container_spec_memory_limit_bytes > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: 容器内存使用超过限制 85%
在实践中,我们发现不少开发者误以为 container_spec_memory_limit_bytes 为 0 代表无限制,其实在 cAdvisor 中 0 常表示未设置或读取失败,此时若宿主机内存耗尽,容器会被 OOM Killer 终止。因此监控体系中必须增加一条校验规则:当限制为 0 且宿主机内存使用偏高时,主动通知集群管理员排查。
三、告警阈值设计与常见监控误区规避
静态阈值在容器环境往往失效。一个批处理容器可能在每天凌晨占用百分之百 CPU,而 Web 容器长期低于百分之十。若统一设置 CPU 大于百分之八十就告警,会产生大量噪声。更好的方式是按容器角色分组,采用动态基线,例如基于过去一周同时段使用率的中位数上浮百分之三十作为阈值。Prometheus 搭配 Alertmanager 可实现分级通知,将非核心服务告警发送至低频频道。
另一个典型误区是忽视退出码与重启次数。容器退出码 137 代表被 SIGKILL,多数是 OOM;退出码 1 通常是应用自身崩溃。如果监控只画曲线不采集 container_last_exit_code,排障时只能登录机器看日志。我们建议在看板中增加重启次数卡片,当某容器十分钟内重启超过三次即触发严重告警。以下 Python 片段演示如何从 Docker SDK 获取重启次数并上报。
import docker
client = docker.from_env()
for c in client.containers.list(all=True):
restart = c.attrs['RestartCount']
exit_code = c.attrs['State']['ExitCode']
if restart > 3:
print(f'容器 {c.name} 重启 {restart} 次,退出码 {exit_code}')
最后,网络指标常被低估。容器间通信经过桥接网卡,若某容器发送错误数持续增加,可能是 DNS 解析异常或下游服务拒绝连接。应将 container_network_errors_total 与业务黄金指标(延迟、错误率)关联分析。只有把计算、存储、网络、生命周期四类信号打通,并形成带有业务语义的标签体系和差异化告警,Docker 监控指标体系建设才算真正完整,能够在规模扩张时依然保持排障效率。