详细拆解如何获取宿主机上 PID 为 29139
的容器对应的 container_fs_reads_total
计数器,并计算其每秒读取速率(IOPS)的具体过程。本文展示从操作系统底层到监控指标的转化。
核心目标: 获取 PID 29139 容器每秒的磁盘读操作次数 (Read IOPS)。
依赖项:
- 宿主机访问权限(能查看
/proc
和/sys/fs/cgroup
) cAdvisor
运行中(通常内置于 kubelet)Prometheus
配置抓取该节点上的 cAdvisor/metrics
详细步骤流程:
阶段 1: 确定目标容器在宿主机上的资源视图(PID -> cgroup)
-
根据 PID 找到其 cgroup 路径:
-
查看进程的
cgroup
信息:cat /proc/29139/cgroup
-
输出示例 (cgroup v1):
12:memory:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 11:devices:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 10:hugetlb:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 9:perf_event:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 8:blkio:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 7:freezer:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 6:net_cls:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 5:cpuacct,cpu:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 4:cpuset:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 3:pids:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID> 2:rdma:/ 1:name=systemd:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID>
-
关键识别: 找到与
blkio
控制器相关联的行(例如上面的第8行)。记录其路径:/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID>
(实际路径中的<PodUID>
和<ContainerRuntimeID>
是具体的长ID)。这就是该进程(容器)在blkio
子系统下的 cgroup 相对路径。
-
-
定位 blkio cgroup 统计文件 (cgroup v1 示例):
-
将相对路径拼接到
/sys/fs/cgroup/blkio/
下:cd /sys/fs/cgroup/blkio/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID>
-
在这个目录下,找到核心统计文件:
blkio.throttle.io_serviced
- (如果系统使用 cgroup v2 ,
blkio
控制器被合并,关键文件通常是io.stat
,路径类似/sys/fs/cgroup/<SAME_RELATIVE_PATH>/io.stat
)
- (如果系统使用 cgroup v2 ,
-
查看实时统计:
cat blkio.throttle.io_serviced
-
输出示例:
8:0 Read 123456 8:0 Write 78901 8:0 Sync 0 8:0 Async 202357 ...(其他设备号) Total 0
-
关键提取: 这里
Read 123456
表示设备8:0
(major:minor) 上发生的 累计读操作总次数 。这个值直接对应于我们将要获取的container_fs_reads_total
计数器的瞬时值。
-
阶段 2: cAdvisor 的视角
-
cAdvisor 周期性扫描:
- cAdvisor 运行在节点上(通常由 kubelet 托管)。
- 每隔 10 秒,cAdvisor 会执行一次采集循环。
- cAdvisor 发现节点上的所有容器,包括 PID
29139
所属的容器。它知道该容器的:- cgroup 路径:
/sys/fs/cgroup/blkio/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID>
- 容器名称(从容器运行时或 cgroup 路径解析)。
- 所属 Pod 名称(解析自 cgroup 路径或 Kubernetes API)。
- Namespace。
- 容器 ID (
<ContainerRuntimeID>
)。 - 镜像名称。
- 节点名称(hostname)。
- cgroup 路径:
-
cAdvisor 读取统计文件:
- cAdvisor 在每次采集循环中,打开文件
/sys/fs/cgroup/blkio/kubepods/burstable/pod<PodUID>/<ContainerRuntimeID>/blkio.throttle.io_serviced
。 - 它解析文件内容。
- 对于每一行包含
Read
的操作(忽略Sync
/Async
/Total
),提取设备号和计数值(如示例中的123456
)。 - 聚合/选择:
- 如果按设备统计(且
device
标签被启用),则为每个设备生成一个时间序列点。 - 通常情况下,如果未指定设备过滤,cAdvisor 会将同一 cgroup 下所有设备的
Read
计数 相加 得到该容器总的读操作数。 这就是我们通常关注的container_fs_reads_total
值,不区分设备。
- 如果按设备统计(且
- cAdvisor 在每次采集循环中,打开文件
-
生成并暴露指标:
- cAdvisor 使用当前采集时间戳(例如
T1=1680000000
)和计算得到的总读计数123456
。 - 它构造一个 Prometheus Counter 指标样本:
container_fs_reads_total{container="<ContainerName>", id="<ContainerRuntimeID>", image="<ImageName>", name="<K8sContainerName>", namespace="<PodNamespace>", node="<NodeHostname>", pod="<PodName>"} 123456
- 经过约 10 秒后(在时间戳
T2 = T1 + 10
),cAdvisor 再次采集:- 读取同一个文件,得到新的累计值,例如
135678
。 - 构造新样本:
... reads_total ... 135678
- 读取同一个文件,得到新的累计值,例如
- cAdvisor 将所有容器的指标合并,通过其 HTTP 服务(例如:
http://<NodeIP>:10250/metrics/cadvisor
)暴露/metrics/cadvisor
端点。
- cAdvisor 使用当前采集时间戳(例如
阶段 3: Prometheus 抓取与存储
- Prometheus 周期性抓取:
- Prometheus 配置了
scrape_config
,定期(例如每 15s)向http://<NodeIP>:10250/metrics/cadvisor
发送 HTTP GET 请求。 - 假设在时间
T_p1
(在T1
和T2
之间)抓取一次,它获取到的目标容器的container_fs_reads_total
值是123456
。Prometheus 将这个样本存储下来,记录抓取时间T_p1
和值123456
。 - 大约 15s 后,在时间
T_p2
(在T2
和T3
之间)抓取第二次,获取到值135678
。同样存储(T_p2, 135678)
。
- Prometheus 配置了
阶段 4: 计算每秒读取速率 (Read IOPS)
- 使用 PromQL 查询速率:
- 用户在 Prometheus UI 或 Grafana 等工具中编写查询:
rate(container_fs_reads_total{id="<ContainerRuntimeID>"}[5m])
- 解读:
container_fs_reads_total{id="<ContainerRuntimeID>"}
:精确过滤出我们要查询的容器(用id
标签是最准确的)。也可以组合namespace
,pod
,container
等标签。[5m]
:定义一个回溯的时间窗口(此处是 5 分钟)。这是计算速率的关键。rate()
:PromQL 函数,用于计算计数器 (counter
) 在指定时间窗口[5m]
内的 平均每秒增长率。
- 计算过程 (简化逻辑,非精确算法):
- Prometheus 在评估此查询时(例如在时间
T_now
),会在[T_now - 5m, T_now]
的时间窗口内,找到所有符合条件的container_fs_reads_total
样本点 (假设抓取了多个点:(T_p1, V1=123456)
,(T_p2, V2=135678)
,(T_p3, V3=147890)
, ...)。 - 它识别出窗口中最早的样本点 (
(T_first, V_first)
) 和最晚的样本点 ((T_last, V_last)
)。 - 计算计数器增量:
Delta = V_last - V_first
- 计算时间增量(秒):
TimeDelta_seconds = T_last - T_first
- 计算平均每秒速率:
Rate = Delta / TimeDelta_seconds
- Prometheus 在评估此查询时(例如在时间
- 结果:
- 此
Rate
值就是目标容器在最近 5 分钟窗口内的 平均每秒磁盘读操作次数 (Read IOPS)。这直观地反映了该容器的磁盘读负载强度。
- 此
- 用户在 Prometheus UI 或 Grafana 等工具中编写查询:
总结流程图:
宿主机 PID 29139 -> /proc/29139/cgroup -> blkio cgroup路径 (e.g., /sys/fs/cgroup/blkio/kubepods/.../<ID>)
|
V
定期读取 /sys/fs/cgroup/blkio/.../<ID>/blkio.throttle.io_serviced (cAdvisor, e.g. 10s)
| (解析 Read 总计数)
V
构造指标 container_fs_reads_total{..., id="<ID>", ...} <CounterValue> (cAdvisor)
|
V
暴露于 http://<NodeIP>:10250/metrics/cadvisor (cAdvisor)
|
V
抓取 (Prometheus, e.g. 15s) -> 存储 (Timestamp, <CounterValue>)
|
V
查询: rate(container_fs_reads_total{id="<ID>"}[5m]) (PromQL)
|
V
结果:目标容器最近 5 分钟的平均每秒读操作次数 (Read IOPS)
关键点强调:
-
/proc/<pid>/cgroup
是关联 PID 到 cgroup 的桥梁。 -
blkio.throttle.io_serviced
(v1) 或io.stat
(v2) 是核心数据源文件,提供累计读计数。 - cAdvisor 是数据采集、标签附加和指标暴露的关键组件。
- Prometheus 抓取并存储时间序列数据。
-
rate(...[window])
是计算平均每秒速率(IOPS)的标准方法,必须指定一个合理的评估窗口(如 1m, 5m)。 -
id
标签是利用容器运行时 ID 精确过滤特定容器指标的最可靠方式。