- 可观测性
- 指标监控
- 云原生
【免费下载链接】cadvisor
Analyzes resource usage and performance characteristics of running containers.
cAdvisor(Container Advisor)在分析运行中容器的资源使用与性能特征时,对外暴露了一套 REST API。官方在仓库的 client 目录中提供了一套 Go 语言实现的 REST API 客户端,它把api/v1.3下的机器信息、容器信息、子容器与事件等端点封装成可直接调用的 Go 方法。本文以 client/README.md 为主线,结合 client/client.go 源码、client/client_test.go 测试与 info/v1 数据结构,带你掌握如何在自己的 Go 项目中初始化客户端、查询机器与容器监控数据,并理解其底层 HTTP 调用机制。
快速开始:创建 cAdvisor 客户端
官方客户端的使用方式非常简洁。在 Go 项目中引入github.com/google/cadvisor/client包后,通过NewClient创建客户端实例,参数是 cAdvisor REST 端点的根地址:
import "github.com/google/cadvisor/client" client, err := client.NewClient("http://192.168.59.103:8080/")其中192.168.59.103:8080需要替换为你实际部署的 cAdvisor 服务地址(cAdvisor 默认监听8080端口)。docs/clients.md 中给出了相同的引入方式与调用client.MachineInfo()的最小示例。
从 client/client.go 的源码可以看到,NewClient在构造时会做两件事:
- URL 规范化:如果传入的 URL 末尾没有
/,会自动补上,避免后续路径拼接出错; - 拼接 API 版本前缀:客户端内部实际访问的是
${url}api/v1.3/,也就是说所有请求都指向 cAdvisor 的 v1.3 版本 REST 接口,这一前缀在 newClient 中通过fmt.Sprintf("%sapi/v1.3/", url)生成,并保存在Client结构体的baseURL字段中。
Client结构体本身只有两个字段(client/client.go#L37-L41):baseURL和httpClient,默认复用http.DefaultClient,无需额外配置即可开始使用。
查询机器信息:MachineInfo
MachineInfo()方法返回整台宿主机(cAdvisor 所在节点)的基础信息,封装为v1.MachineInfo结构体,所有字段都会被填充完整:
mInfo, err := client.MachineInfo()client/README.md 给出了一个典型的返回值示例(Go 调试器格式):
(*v1.MachineInfo)(0xc208022b10)({ NumCores: (int) 4, MemoryCapacity: (int64) 2106028032, Filesystems: ([]v1.FsInfo) (len=1 cap=4) { (v1.FsInfo) { Device: (string) (len=9) "/dev/sda1", Capacity: (uint64) 19507089408 } } })对应到实际数据模型,MachineInfo定义在 lib/model/machine.go#L182-L251,通过 info/v1/machine.go#L55 的别名导出为v1.MachineInfo。其核心字段包括:
| 字段 | JSON 键 | 含义 |
|---|---|---|
NumCores | num_cores | 机器 CPU 核心数(含超线程逻辑核) |
NumPhysicalCores | num_physical_cores | 物理核心数 |
NumSockets | num_sockets | CPU 插槽数 |
CpuFrequency | cpu_frequency_khz | 核心最大时钟频率(KHz) |
MemoryCapacity | memory_capacity | 机器内存总量(字节) |
SwapCapacity | swap_capacity | 交换分区总量(字节) |
HugePages | hugepages | 大页信息列表 |
Filesystems | filesystems | 文件系统列表(见下) |
DiskMap | disk_map | 磁盘设备信息映射 |
NetworkDevices | network_devices | 网络设备列表 |
Topology | topology | CPU/内存 NUMA 拓扑层次 |
MachineID/SystemUUID/BootID | 同名 | 机器、系统与启动标识 |
CloudProvider/InstanceType/InstanceID | 同名 | 云厂商、实例类型与实例 ID |
上例中的Filesystems是[]v1.FsInfo切片,每个元素对应一块文件系统(lib/model/machine.go#L21-L40),关键字段有Device(块设备名,如/dev/sda1)、Capacity(文件系统总字节数)、Type(设备类型)、Inodes(可用 inode 数)。DeviceMajor/DeviceMinor用于与 blkio 统计关联,序列化为 JSON 时会被省略(json:"-")。
在 client/client_test.go#L67-L92 的TestGetMachineinfo中,测试通过httptest模拟/api/v1.3/machine端点,构造了包含NumCores: 8、MemoryCapacity: 31625871360与磁盘映射的返回数据,然后调用client.MachineInfo()并用reflect.DeepEqual校验结果,可以直观看到该方法的预期行为。
查询容器信息:ContainerInfo
要获取某个具体容器的完整信息,使用ContainerInfo方法。它接收容器名称(绝对路径)和一个查询请求ContainerInfoRequest:
request := v1.ContainerInfoRequest{NumStats: 10} sInfo, err := client.ContainerInfo("/docker/d9d3eb10179e6f93a...", &request)返回值为v1.ContainerInfo结构体(lib/model/container.go#L141-L152),其中ContainerReference内嵌字段唯一标识该容器(Id、Name、Aliases、Namespace),Spec描述容器的规格(CPU/内存/网络/文件系统限制等),Stats是按时间序列排列的历史统计数据切片,Subcontainers则列出直接的子容器引用。
理解 ContainerInfoRequest 查询参数
ContainerInfoRequest定义在 lib/model/container.go#L110-L124,控制返回数据的时间范围与采样数量,是控制请求开销的关键:
| 字段 | JSON 键 | 含义与默认值 |
|---|---|---|
NumStats | num_stats | 返回的最大统计样本数;-1表示返回当前所有可用统计;默认 60 |
Start | start | 查询起始时间(time.Time),省略时视为时间起点 |
End | end | 查询结束时间,省略时默认为当前时间 |
如果你不指定任何字段,也可以直接调用 info/v1/container.go#L38-L42 中定义的DefaultContainerInfoRequest(),它返回NumStats: 60的默认请求,即最近 60 个统计样本。
底层调用细节
ContainerInfo的实现(client/client.go#L95-L103)会拼接出api/v1.3/containers/{name}的 URL(见 containerInfoURL),然后将查询参数以 JSON 形式 POST 给服务端(详见下文 HTTP 层)。测试 TestGetContainerInfo 用NumStats: 3的请求查询/some/container,并断言服务端收到的 POST 体与预期请求完全一致,验证了请求参数的序列化与传递链路。
递归查询子容器:SubcontainersInfo
与ContainerInfo只返回单个容器不同,SubcontainersInfo会递归返回指定容器及其内部所有子容器的信息(client/client.go#L105-L115):
request := v1.ContainerInfoRequest{NumStats: 10} sInfo, err := client.SubcontainersInfo("/docker", &request)请求/docker会返回 Docker 运行时下的所有容器及其嵌套子容器。该方法与ContainerInfo的差异在于:
- 请求的端点不同:
api/v1.3/subcontainers/{name}(见 subcontainersInfoURL); - 返回类型不同:返回的是
[]v1.ContainerInfo切片,其中第一个元素是所查容器自身的信息,其后跟随各层级的子容器信息,每个元素的Subcontainers字段都会被填充。
测试 TestGetSubcontainersInfo 模拟了父容器/some/container及其两个子容器sub1、sub2的返回数据,验证客户端能正确解析出 3 个ContainerInfo且顺序与内容均无误。
更多客户端能力:Docker 容器与事件
除 README 重点讲解的三种方法外,client/client.go 还提供了面向 Docker 与事件的两组实用 API。
Docker 专属查询
DockerContainer(name, query):按名称查询单个 Docker 容器(client/client.go#L119-L133)。底层访问api/v1.3/docker/{name},由于该端点返回的是map[string]v1.ContainerInfo,方法内部会校验 map 中恰好只有一个元素并取出;AllDockerContainers(query):查询全部 Docker 容器(client/client.go#L136-L147),访问api/v1.3/docker/,将返回的 map 转换为[]v1.ContainerInfo切片。
事件查询:静态与流式
事件 API 支持两种模式(事件类型定义见 info/v1/container.go#L134-L139,包括oom、oomKill、containerCreation、containerDeletion):
// 静态:返回满足条件的所有历史事件 einfo, err := staticClient.EventStaticInfo("?oom_events=true") // 流式:持续将发生的事件送入 channel einfo := make(chan *info.Event) go func() { err = streamingClient.EventStreamingInfo( "?creation_events=true&stream=true&oom_events=true&deletion_events=true", einfo) }() for ev := range einfo { // 处理每个事件 }EventStaticInfo(client/client.go#L60-L68)访问api/v1.3/events/{name},一次性返回满足条件的[]*v1.Event;EventStreamingInfo(client/client.go#L72-L78)通过 getEventStreamingData 保持连接,用json.Decoder逐条解码事件流并送入传入的 channel,直至连接关闭;注意流式模式要求请求参数中包含stream=true,否则无法正确解析事件流。
仓库中的 client/clientexample/main.go 是一个完整的可运行示例,它依次演示了静态事件查询(?oom_events=true)与流式事件订阅(同时订阅创建、删除与 OOM 事件),可直接作为事件客户端的使用模板。
底层实现:统一的 HTTP 请求处理与错误语义
所有查询方法最终都汇聚到httpGetJSONData(client/client.go#L169-L202),理解它有助于排查调用中的各类异常:
- 请求方式:若携带
postData(即ContainerInfoRequest查询参数),则以application/json发起 POST;否则发起 GET(如机器信息); - 响应校验:读取响应体后,若 HTTP 状态码不是 200,直接返回包含响应正文的错误信息,例如
request "..." failed with error: "..."(对应测试 TestRequestFails 验证的失败场景); - JSON 反序列化:将响应体
json.Unmarshal到目标结构体,失败时错误信息中会附带原始响应正文,便于定位服务端返回异常数据的问题; - 网络层错误:请求发送失败、响应体为空等情况均会被包装为带明确上下文(所请求的信息名与 URL)的错误返回。
因此在实践中,每个客户端方法的调用都应检查err是否为nil,并且可以根据错误字符串中是否包含目标 URL 或响应正文快速判断是网络问题、服务端 500 还是数据格式不匹配。
如何在自己的 Go 项目中使用
cAdvisor 客户端是一个普通 Go 包,可以直接集成到你的监控、调度或运维平台中:
import ( "fmt" "github.com/google/cadvisor/client" v1 "github.com/google/cadvisor/info/v1" ) func main() { client, err := client.NewClient("http://localhost:8080/") if err != nil { panic(err) } // 机器信息 mInfo, err := client.MachineInfo() if err == nil { fmt.Printf("cores=%d memory=%d\n", mInfo.NumCores, mInfo.MemoryCapacity) } // 最近 60 个统计样本(默认值) req := v1.DefaultContainerInfoRequest() cInfo, err := client.ContainerInfo("/", &req) if err == nil { fmt.Printf("container %s, stats samples: %d\n", cInfo.Name, len(cInfo.Stats)) } // 递归查询子容器 subs, err := client.SubcontainersInfo("/docker", &req) if err == nil { fmt.Printf("docker subcontainers: %d\n", len(subs)) } }MachineInfo可用于节点层面的容量评估与资源总量展示;ContainerInfo适合按容器查询其 CPU/内存/网络等历史统计(如容器级监控面板的数据源);SubcontainersInfo("/docker", ...)则是枚举某个运行时下全部容器清单的便捷途径。与 v2 客户端(见 client/v2/client.go)相比,v1 客户端直接对应 cAdvisor 的api/v1.3接口,返回结构以「机器/容器 + 历史统计序列」的经典模型呈现,是理解 cAdvisor 数据模型的良好起点。
验证与测试
仓库为客户端提供了完善的测试覆盖(client/client_test.go):
cadvisorTestClient工具函数(client/client_test.go#L34-L63)用httptest.NewServer构造本地 mock 服务,并校验 POST 请求体的NumStats、Start、End是否与预期一致;TestGetMachineinfo验证机器信息 JSON 解析的正确性;TestGetContainerInfo与TestGetSubcontainersInfo使用 info/v1/test 的GenerateRandomContainerInfo生成随机容器数据,并通过ContainerInfo.Eq()(lib/model/container.go#L160-L190)进行带时间容差的深度比较;TestRequestFails验证服务端返回 500 时客户端错误信息的正确性。
这些测试既保证了客户端的可靠性,也为我们阅读数据结构、理解请求参数语义提供了现成的参考样例。你可以在仓库根目录执行go test ./client/...来运行客户端相关的全部测试(需要 Go 环境)。
- 可观测性
- 指标监控
- 云原生
【免费下载链接】cadvisor
Analyzes resource usage and performance characteristics of running containers.
相关推荐
cAdvisor API Clients 实战指南:使用官方 Go 客户端对接容器监控 REST API
cAdvisor API Clients 实战指南:使用官方 Go 客户端对接容器监控 REST API cAdvisor(Container Advisor)
可观测性指标监控云原生使用 cAdvisor v2 REST API 的 Go 客户端库:从初始化到容器统计的完整实战指南
使用 cAdvisor v2 REST API 的 Go 客户端库:从初始化到容器统计的完整实战指南 本篇技术指南以 cAdvisor 仓库中 client/v
可观测性指标监控云原生终极指南:如何通过cAdvisor REST API轻松获取容器监控数据
终极指南:如何通过cAdvisor REST API轻松获取容器监控数据 cAdvisor是一款强大的容器监控工具,能够分析运行中容器的资源使用情况和性能特征。
可观测性指标监控云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考