深入探索 cAdvisor:容器监控利器
1. 引言
在容器化技术盛行的今天,对容器的资源使用和性能进行监控变得至关重要。cAdvisor(Container Advisor)作为一个开源项目,正是为满足这一需求而诞生的。它可以收集运行中容器的资源使用和性能数据,尤其对 Docker 容器的支持十分出色。
2. cAdvisor 简介
cAdvisor 是一个用于收集容器资源使用和性能数据的开源项目,其完整源代码可在 https://github.com/google/cadvisor 找到,本文使用的是 v0.39.3 版本。选择该项目的原因在于它能进一步探索系统调用监控文件系统、使用 cgroups 以及通过 /proc 和 /sys 收集机器信息等主题。
3. 运行 cAdvisor
要在本地运行 cAdvisor,可按以下步骤操作:
1. 下载源代码 :使用以下命令下载 cAdvisor 的源代码。
GO111MODULE=off go get github.com/google/cadvisor
此命令会使用 go get 从指定 URL 下载源代码, GO111MODULE=off 环境变量会让 Go 工具将模块(google/cadvisor)存储在 GOPATH 目录中。
2. 构建项目 :进入 GOPATH/src/github.com/google/cadvisor/cmd 目录,运行以下命令构建项目。
go build -o cadvisor
这将生成一个名为 cadvisor 的可执行文件。
3. 查看参数 :运行以下命令查看 cAdvisor 可接受的不同参数。
./cadvisor –help
输出结果包含众多参数,如 -add_dir_header 、 -boot_id_file 、 -v 等,这里不一一赘述,可使用其默认值。
4. 运行 cAdvisor :由于 cAdvisor 需要 root 权限才能运行,可使用以下命令启动。
sudo ./cadvisor -v 9
默认情况下,cAdvisor 使用 8080 端口运行应用程序。若该端口已被其他应用占用,可使用 -port 标志指定不同端口。
sudo ./cadvisor -port <port_number>
启动后,终端会输出大量日志信息。
4. 访问 cAdvisor 网页界面
当 cAdvisor 成功运行后,打开浏览器,输入 http://localhost:8080 即可访问其用户界面。界面展示了丰富的数据,如系统切片、内存和磁盘使用情况、正在运行的进程信息以及 Docker 容器信息等。以下是界面主要信息的介绍:
- 子容器视图 :展示了名为 subcontainers 的子目录,提供了重要的统计和性能信息,用于报告目的。
- 系统服务视图 :点击 system.slice 链接,可查看本地机器上运行的不同服务。
- 资源使用情况 :界面显示了内存和磁盘使用的百分比。
- 进程信息 :展示了正在运行的进程的名称、CPU 使用、内存使用、运行时间等信息。
- Docker 容器信息 :点击 Docker Containers 链接,可查看本地运行的所有 Docker 容器,点击具体容器可查看其相关指标。
5. cAdvisor 架构
cAdvisor 的架构包含多个组件,各组件协同工作以实现容器监控功能。以下是主要组件及其功能:
| 组件 | 功能 |
| ---- | ---- |
| Events Channel | 用于报告容器的创建或删除事件 |
| InMemoryCache | 存储被监控容器的相关指标信息 |
| Container Watcher | 监控容器活动 |
| Containers | 被 cAdvisor 监控的不同容器 |
| Machine Info | 与 cAdvisor 运行所在本地机器相关的信息 |
| Plugins | 支持不同的容器技术,如 Docker、Mesos、CRIO、Systemd 和 ContainerD |
| Handlers | 处理 cAdvisor 暴露的指标和其他相关 API 的 HTTP 请求 |
6. cAdvisor 初始化
和其他 Go 应用一样,cAdvisor 的入口点是 main.go 。 main() 函数执行以下初始化步骤:
1. 设置缓存 :初始化用于存储容器及其指标的缓存。
memoryStorage, err := NewMemoryStorage()
if err != nil {
klog.Fatalf("Failed to initialize storage driver: %s", err)
}
- 设置 Manager :Manager 是 cAdvisor 的核心组件,负责监控容器的主要处理工作。
resourceManager, err := manager.New(memoryStorage, sysFs, housekeepingConfig, includedMetrics, &collectorHttpClient, strings.Split(*rawCgroupPrefixWhiteList, ","), *perfEvents)
- 设置 HTTP 处理程序 :允许 Web 用户界面获取不同容器的指标数据。
cadvisorhttp.RegisterPrometheusHandler(mux, resourceManager, *prometheusEndpoint, containerLabelFunc, includedMetrics)
rootMux := http.NewServeMux()
- 启动 Manager :开始收集容器和指标。
缓存管理由 InMemoryCache 负责,其定义如下:
type InMemoryCache struct {
lock sync.RWMutex
containerCacheMap map[string]*containerCache
maxAge time.Duration
backend []storage.StorageDriver
}
7. Manager 组件
Manager 是 cAdvisor 的核心,负责容器的初始化、维护和指标报告。其接口定义如下:
type Manager interface {
Start() error
Stop() error
GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
GetContainerInfoV2(containerName string, options v2.RequestOptions) (map[string]v2.ContainerInfo, error)
SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error)
AllDockerContainers(query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error)
DockerContainer(dockerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error)
GetContainerSpec(containerName string, options v2.RequestOptions) (map[string]v2.ContainerSpec, error)
GetDerivedStats(containerName string, options v2.RequestOptions) (map[string]v2.DerivedStats, error)
GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error)
Exists(containerName string) bool
GetMachineInfo() (*info.MachineInfo, error)
GetVersionInfo() (*info.VersionInfo, error)
GetFsInfoByFsUUID(uuid string) (v2.FsInfo, error)
GetDirFsInfo(dir string) (v2.FsInfo, error)
GetFsInfo(label string) ([]v2.FsInfo, error)
GetProcessList(containerName string, options v2.RequestOptions) ([]v2.ProcessInfo, error)
WatchForEvents(request *events.Request) (*events.EventChannel, error)
GetPastEvents(request *events.Request) ([]*info.Event, error)
CloseEventChannel(watchID int)
DockerInfo() (info.DockerStatus, error)
DockerImages() ([]info.DockerImage, error)
DebugInfo() map[string][]string
}
Manager 使用不同容器技术的插件,例如 Docker 插件负责与 Docker 引擎通信,其代码位于 container/docker/plugin.go 文件中。
8. 容器监控流程
Manager 在监控容器前,需要先确定要监控的容器。这一过程在 Start() 函数调用时完成,主要步骤如下:
1. 注册容器工厂 :调用 raw.Register() 函数注册原始容器工厂。
err := raw.Register(m, m.fsInfo, m.includedMetrics, m.rawContainerCgroupPathPrefixWhiteList)
if err != nil {
klog.Errorf("Registration of the raw container factory failed: %v", err)
}
- 创建容器监控器 :创建
rawContainerWatcher并将其添加到containerWatchers列表中。
rawWatcher, err := raw.NewRawContainerWatcher()
if err != nil {
return err
}
m.containerWatchers = append(m.containerWatchers, rawWatcher)
- 创建根容器 :调用
m.createContainer("/", watcher.Raw)创建根容器。
err = m.createContainer("/", watcher.Raw)
if err != nil {
return err
}
- 检测子容器 :调用
m.detectSubcontainers("/")检测/sys/fs/cgroup目录下的子目录,并将其作为容器进行监控。
err = m.detectSubcontainers("/")
if err != nil {
return err
}
- 启动容器监控 :调用
watchForNewContainers()函数启动所有容器监控器。
func (m *manager) watchForNewContainers(quit chan error) error {
watched := []watcher.ContainerWatcher{}
for _, watcher := range m.containerWatchers {
err := watcher.Start(m.eventsChannel)
if err != nil {
for _, w := range watched {
stopErr := w.Stop()
// 处理停止错误
}
return err
}
watched = append(watched, watcher)
}
err := m.detectSubcontainers("/")
// 处理错误
return nil
}
9. 监控文件系统
cAdvisor 使用 Linux 内核提供的 inotify API( https://linux.die.net/man/7/inotify )来监控文件系统事件,如文件的创建或删除。其工作流程如下:
1. 启动监控 :在 watchForNewContainers 函数调用时,会调用 container/raw/watcher.go 中的 Start 函数启动 inotify 监控。
func (w *rawContainerWatcher) Start(events chan watcher.ContainerEvent) error {
watched := make([]string, 0)
for _, cgroupPath := range w.cgroupPaths {
_, err := w.watchDirectory(events, cgroupPath, "/")
// 处理错误
watched = append(watched, cgroupPath)
}
go func() {
for {
select {
case event := <-w.watcher.Event():
err := w.processEvent(event, events)
// 处理错误
case err := <-w.watcher.Error():
// 处理错误
case <-w.stopWatcher:
err := w.watcher.Close()
// 处理错误
}
}
}()
return nil
}
- 处理事件 :
w.processEvent()函数将接收到的 inotify 事件转换为内部事件,如watcher.ContainerAdd和watcher.ContainerDelete。
func (w *rawContainerWatcher) processEvent(event *inotify.Event, events chan watcher.ContainerEvent) error {
var eventType watcher.ContainerEventType
switch {
case (event.Mask & inotify.InCreate) > 0:
eventType = watcher.ContainerAdd
case (event.Mask & inotify.InDelete) > 0:
eventType = watcher.ContainerDelete
// 其他情况处理
}
switch eventType {
case watcher.ContainerAdd:
alreadyWatched, err := w.watchDirectory(events, event.Name, containerName)
// 处理错误
case watcher.ContainerDelete:
lastWatched, err := w.watcher.RemoveWatch(containerName, event.Name)
// 处理错误
default:
return fmt.Errorf("unknown event type %v", eventType)
}
events <- watcher.ContainerEvent{
EventType: eventType,
Name: containerName,
WatchSource: watcher.Raw,
}
return nil
}
10. 从 /sys 和 /proc 收集信息
cAdvisor 通过 /sys 和 /proc 文件系统收集机器信息,并将其作为指标信息的一部分进行报告。以下是一些关键函数及其功能:
- 收集内存信息 : GetMachineMemoryCapacity() 函数通过读取 /proc/meminfo 文件并解析其中的信息来获取机器的内存容量。
func GetMachineMemoryCapacity() (uint64, error) {
out, err := ioutil.ReadFile("/proc/meminfo")
if err != nil {
return 0, err
}
memoryCapacity, err := parseCapacity(out, memoryCapacityRegexp)
if err != nil {
return 0, err
}
return memoryCapacity, err
}
- 收集文件系统信息 :
GetGlobalFsInfo()函数调用GetFsInfoForPath()函数,后者又调用getDiskStatsMap("/proc/diskstats")来读取和解析/proc/diskstats文件中的信息。
func (i *RealFsInfo) GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, error) {
diskStatsMap, err := getDiskStatsMap("/proc/diskstats")
// 处理错误
return filesystems, nil
}
- 收集网络设备信息 :
GetNetworkDevices()函数通过/sys/class/net目录获取网络设备信息。
func GetNetworkDevices(sysfs sysfs.SysFs) ([]info.NetInfo, error) {
devs, err := sysfs.GetNetworkDevices()
// 处理错误
return netDevices, nil
}
综上所述,cAdvisor 是一个功能强大的容器监控工具,通过系统调用、cgroups 以及 /proc 和 /sys 文件系统,能够全面收集容器的资源使用和性能数据。其架构设计合理,组件之间协同工作,为容器监控提供了可靠的解决方案。
深入探索 cAdvisor:容器监控利器
11. 监控流程总结
cAdvisor 的容器监控流程可以用以下 mermaid 流程图表示:
graph LR
A[Manager 启动] --> B[注册容器工厂]
B --> C[创建容器监控器]
C --> D[创建根容器]
D --> E[检测子容器]
E --> F[启动容器监控]
F --> G[使用 inotify 监控文件系统]
G --> H[处理文件系统事件]
H --> I[收集 /sys 和 /proc 信息]
这个流程清晰地展示了 cAdvisor 从启动到最终实现容器监控和信息收集的整个过程。
12. 不同组件的交互
cAdvisor 各组件之间的交互关系对于理解其工作原理至关重要。以下是一个简要的交互说明:
- Manager 与插件 :Manager 使用不同的插件来与各种容器技术进行通信。例如,Docker 插件负责与 Docker 引擎交互,为 Manager 提供 Docker 容器的相关信息。
- Manager 与 Container Watcher :Manager 启动 Container Watcher 来监控容器活动。Container Watcher 会将监控到的事件通过 Events Channel 反馈给 Manager。
- Manager 与 InMemoryCache :Manager 将收集到的容器指标信息存储在 InMemoryCache 中,以便后续的查询和使用。
- Handlers 与 Manager :Handlers 负责处理 HTTP 请求,当用户通过网页界面或 API 请求容器指标数据时,Handlers 会从 Manager 中获取相应的数据并返回给用户。
13. 实际应用场景
cAdvisor 在实际应用中有多种场景,以下是一些常见的例子:
- 性能监控 :实时监控容器的 CPU、内存、磁盘和网络使用情况,帮助管理员及时发现性能瓶颈和异常。
- 资源管理 :根据容器的资源使用情况,合理分配系统资源,提高资源利用率。
- 故障排查 :当容器出现故障时,通过查看 cAdvisor 收集的详细信息,快速定位问题所在。
- 容量规划 :分析容器的资源使用趋势,为未来的系统扩容和升级提供依据。
14. 注意事项
在使用 cAdvisor 时,需要注意以下几点:
- 权限问题 :cAdvisor 需要 root 权限才能运行,因为它需要访问系统的敏感信息,如 /proc 和 /sys 文件系统。
- 端口冲突 :默认情况下,cAdvisor 使用 8080 端口。如果该端口已被其他应用占用,需要使用 -port 标志指定不同的端口。
- 日志管理 :cAdvisor 运行时会产生大量的日志信息,需要合理管理日志文件,避免占用过多的磁盘空间。
15. 总结
通过对 cAdvisor 的深入探索,我们了解到它是一个功能强大且灵活的容器监控工具。它利用系统调用、cgroups 以及 /proc 和 /sys 文件系统,能够全面收集容器的资源使用和性能数据。其架构设计合理,各个组件协同工作,为容器监控提供了可靠的解决方案。
以下是 cAdvisor 的主要特点总结:
| 特点 | 描述 |
| ---- | ---- |
| 开源项目 | 完整源代码可在 GitHub 上获取,方便开发者进行定制和扩展。 |
| 多容器支持 | 支持 Docker、Mesos、CRIO、Systemd 和 ContainerD 等多种容器技术。 |
| 实时监控 | 实时收集容器的资源使用和性能数据,帮助管理员及时发现问题。 |
| 网页界面 | 提供直观的网页界面,方便用户查看和分析数据。 |
| API 支持 | 暴露 API 接口,允许用户通过编程方式获取容器指标数据。 |
如果你正在寻找一个可靠的容器监控工具,cAdvisor 绝对是一个值得考虑的选择。它可以帮助你更好地管理和优化容器化应用程序,提高系统的稳定性和性能。
超级会员免费看
441

被折叠的 条评论
为什么被折叠?



