公众号关注 「奇妙的 Linux 世界」
设为「星标」,每天带你玩转 Linux !
简介
cAdvisor 是 Google 开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行 CAdvisor 用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示。
cAdvisor 可以对节点机器上的资源及容器进行实时监控和性能数据采集,包括 CPU 使用情况、内存使用情况、网络吞吐量及文件系统使用情况
。
实现原理
cAdvisor 的数据采集分为两个部分 machineInfo 和 containerInfo。
![9c46ef991fb7acaf68edd4af2be8fac7.png](https://i-blog.csdnimg.cn/blog_migrate/96d057db328a7fd96f431b4930ed5c3f.png)
启动参数
cAdvisor 服务相关
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
listen_ip | string | 要监听的 IP,默认监听所有 IP | |
port | int | 要监听的端口 | 8080 |
max_procs | int | 可同时使用的 CPU 的最大数量。默认值小于 1(核心数)。 | 0 |
version | bool | 打印 cAdvisor 版本然后退出 | false |
http_auth_file | string | web UI 的 HTTP 身份验证文件 | |
http_auth_realm | string | web UI 的 HTTP 身份验证领域 | localhost |
http_digest_file | string | web UI 的 HTTP 摘要文件 | |
http_digest_realm | string | web UI 的 HTTP 摘要文件 | localhost |
指标采集相关
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
prometheus_endpoint | string | 暴露给 Prometheus 的指标采集站点 | /metrics |
housekeeping_interval | Duration | 容器 housekeeping 的间隔 | 1s |
max_housekeeping_interval | Duration | 容器 housekeeping 的最大间隔 | 60s |
allow_dynamic_housekeeping | bool | 是否允许动态 housekeeping 间隔。动态管理 housekeeping 间隔可以让 cAdvisor 根据容器的活动性调整它收集统计信息的频率。关闭此选项可提供可预测的采集周期间隔,但会增加 cAdvisor 的资源使用。 | true |
global_housekeeping_interval | Duration | cAdvisor 有两个 housekeeping 间隔设定:全局的和每容器的。全局 housekeeping 间隔是 cAdvisor 进行的一次单独的采集操作,通常在检测到新的容器时执行一次。当前,cAdvisor 通过内核事件发现新的容器,因此这种全局 housekeeping 间隔主要用于处理有任何事件遗漏的情况。 | 1min |
update_machine_info_interval | Duration | 机器信息更新间隔 | 5min |
enable_load_reader | bool | 是否启用 cpu load reader | false |
log_cadvisor_usage | bool | 是否打印 cAdvisor 容器的资源使用情况 | false |
event_storage_age_limit | string | 各类事件的最大保存时间。Value 是一个逗号分隔的键值列表,其中键是事件类型(例如:creation、oom)或“default”,值是持续时间。默认值应用于所有未指定的事件类型 | default=24h |
event_storage_event_limit | string | 各类事件的最大保存事件个数。Value 是一个逗号分隔的键值列表,其中键是事件类型(例如:creation、oom)或“default”,值是持续时间。默认值应用于所有未指定的事件类型 | default=100000 |
application_metrics_count_limit | int | 要存储的应用程序指标的最大数量(每个容器) | 100 |
profiling | bool | 开启 web 界面分析。host:port/debug/pprof/ | |
collector_cert | string | 指标采集器证书,向站点公开以进行基于证书的身份验证。 | |
collector_key | string | 指标采集器证书密钥 | |
store_container_labels | bool | 将容器标签和环境变量转换为每个容器的 prometheus 指标的标签。如果标志设置为 false,则仅导出容器名称、第一别名和镜像名称 | true |
whitelisted_container_labels | string | 以逗号分隔的容器标签列表,用于将每个容器转换为 prometheus 指标的标签。storecontainer_labels 必须设置为 false 才能生效。 | |
url_base_prefix | string | URL 前缀路径,将附加到所有路径以支持某些反向代理 | |
raw_cgroup_prefix_whitelist | string | 即使指定了-docker_only,也需要收集的 cgroup 路径前缀列表(用逗号分隔) | |
perf_events_config | string | 包含要测量的 perf 事件配置的 JSON 文件的路径。空值表示禁用 perf 事件测量。 | |
disable_metrics | []string | 逗号分隔的要禁用的指标集合 | |
v | int | 日志详细程度 | 2 |
docker_only | bool | 除了 root cgroup 统计信息外,仅报告 docker 容器 | false |
disable_root_cgroup_stats | bool | 禁用 root cgroup 状态采集 | false |
container_hints | string | 通过一个 JSON 文件向 cAdvisor 传递额外的容器配置信息,JSON 文件的格式参考定义[1]。当前该配置仅用于原生容器驱动。 | /etc/cadvisor/container_hints.json |
machine_id_file | string | 以逗号分隔的文件列表,用于检查机器 ID。使用第一个存在的文件。 | /etc/machine-id,/var/lib/dbus/machine-id |
boot_id_file | string | 以逗号分隔的文件列表,用于检查 boot-id。使用第一个存在的文件。 | /proc/sys/kernel/random/boot_id |
CRI 相关
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
docker | string | docker endpoint | unix:///var/run/docker.sock |
docker-tls | bool | 使用 TLS 来访问 Docker | false |
docker-tls-cert | string | 客户端证书路径 | cert.pem |
docker-tls-key | string | 私钥路径 | key.pem |
docker-tls-ca | string | 可信任 CA 路径 | ca.pem |
docker_env_metadata_whitelist | string | 要为 docker 容器收集的环境变量键列表(以逗号分隔,前缀匹配) | |
docker_root | string | 已弃用: Docker 根目录,用于获取 Docker 信息(默认 : /var/lib/docker) | /var/lib/docker |
containerd | string | containerd endpoint | /run/containerd/containerd.sock |
containerd-namespace | string | containerd namespace | k8s.io |
containerd_env_metadata_whitelist | string | 要为 containerd 容器收集的环境变量键列表(以逗号分隔,前缀匹配) | |
mesos_agent | string | Mesos 代理地址 | 127.0.0.1:5051 |
mesos_agent_timeout | Duration | Mesos 代理超时时间 | 10s |
存储相关
|storage_driver|string| 要使用的存储“驱动程序”。数据总是很快缓存在内存中,该参数控制了数据被推送到本地缓存之外的位置。空表示没有,多个用逗号隔开。可选值为:
BigQuery
ElasticSearch
InfluxDB
Kafka
Redis
Statsd
stdout
参数 | 类型 | 说明 | 默认值 |
---|---|---|---|
storage_duration | Duration | 数据在内存中保存多长时间(默认:2 分钟) | 2min |
storage_driver_user | string | 数据库用户名 | root |
storage_driver_password | string | 数据库密码 | root |
storage_driver_host | string | 数据库地址 | localhost:8086 |
storage_driver_db | string | 数据库名称 | cadvisor |
storage_driver_table | string | 数据库表名 | stats |
storage_driver_secure | bool | 是否使用安全连接数据库 | false |
storage_driver_buffer_duration | Duration | 存储驱动程序中的写入将在此期间进行缓存,并作为单个事务提交给非内存后端 | 60s |
bq_id | string | BigQuery 客户端 ID | |
bq_secret | string | BigQuery 客户端秘钥 | notasecret |
bq_project_id | string | BigQuery 客户端 project ID | |
bq_account | string | BigQuery 客户端服务账户邮箱 | |
bq_credentials_file | string | BigQuery 客户端证书 | |
storage_driver_es_host | string | ElasticSearch 地址 host:por | http://localhost:9200 |
storage_driver_es_index | string | ElasticSearch 索引名称 | cadvisor |
storage_driver_es_type | string | ElasticSearch 类型名称 | stats |
storage_driver_es_enable_sniffer | bool | 默认情况下,ElasticSearch 使用嗅探进程自动查找集群的所有节点 | false |
storage_driver_kafka_broker_list | string | kafka broker(s) csv | localhost:9092 |
storage_driver_kafka_topic | string | kafka topic | stats |
storage_driver_kafka_ssl_cert | string | 用于 TLS 客户端身份验证的证书文件(可选) | |
storage_driver_kafka_ssl_key | string | 用于 TLS 客户端身份验证的密钥文件(可选) | |
storage_driver_kafka_ssl_ca | string | 用于 TLS 客户端身份验证的证书颁发机构文件(可选) | |
storage_driver_kafka_ssl_verify | bool | 是否验证 ssl 证书 | true |
storage_driver_influxdb_retention_policy | string | 保留策略 |
指标
Go 运行时指标
指标 | 含义 |
---|---|
go_gc_duration_seconds | 持续时间秒 |
go_gc_duration_seconds_sum | gc-持续时间-秒数-总和 |
go_memstats_alloc_bytes | Go 内存统计分配字节 |
go_memstats_alloc_bytes_total | Go 内存统计分配字节总数 |
go_memstats_buck_hash_sys_bytes | 用于剖析桶散列表的堆空间字节 |
go_memstats_frees_total | 内存释放统计 |
go_memstats_gc_cpu_fraction | 垃圾回收占用服务 CPU 工作的时间总和 |
go_memstats_gc_sys_bytes | 圾回收标记元信息使用的内存字节 |
go_memstats_heap_alloc_bytes | 服务分配的堆内存字节数 |
go_memstats_heap_idle_bytes | 申请但是未分配的堆内存或者回收了的堆内存(空闲)字节数 |
go_memstats_heap_inuse_bytes | 正在使用的堆内存字节数 |
go_memstats_heap_objects | 堆内存块申请的量 |
go_memstats_heap_released_bytes | 返回给 OS 的堆内存 |
go_memstats_heap_sys_bytes | 系统分配的作为运行栈的内存 |
go_memstats_last_gc_time_seconds | 持续时间秒 |
go_memstats_mspan_sys_bytes | 系统为测试用的结构体分配的字节数 |
go_gc_duration_seconds | 垃圾回收器最后一次执行时间 |
go_memstats_lookups_total | 被 runtime 监视的指针数 |
go_memstats_mallocs_total | 服务 malloc 的次数 |
go_memstats_mcache_inuse_bytes | mcache 结构体申请的字节数 (不会被视为垃圾回收) |
go_memstats_mcache_inuse_bytes | mcache 结构体申请的字节数 (不会被视为垃圾回收) |
go_memstats_mcache_sys_bytes | 操作系统申请的堆空间用于 mcache 的字节数 |
go_memstats_mspan_inuse_bytes | 用于测试用的结构体使用的字节数 |
go_memstats_next_gc_bytes | 垃圾回收器检视的内存大小 |
go_memstats_other_sys_bytes | golang 系统架构占用的额外空间 |
go_memstats_stack_inuse_bytes | 正在使用的栈字节数 |
go_memstats_stack_sys_bytes | 系统分配的作为运行栈的内存 |
go_memstats_sys_bytes | 服务现在系统使用的内 |
go_threads | 线程 |
go_goroutines | 协程数量 |
go_info | go 编译器版本 |
进程指标
指标 | 含义 |
---|---|
process_cpu_seconds_total | 进程用户和系统 CPU 总时间(以秒为单位)。 |
process_max_fds | 进程打开文件描述符的最大数量。 |
process_open_fds | 进程打开文件描述符的数量。 |
process_resident_memory_bytes | 进程驻留内存大小(以字节为单位)。 |
process_start_time_seconds | 进程的开始时间,以秒为单位(时间戳)。 |
process_virtual_memory_bytes | 进程以字节为单位的虚拟内存大小。 |
process_virtual_memory_max_bytes | 可用的最大虚拟内存量(以字节为单位)。 |
机器指标
指标 | 类型 | 含义 |
---|---|---|
machine_cpu_physical_cores | Gauge | 物理 CPU 核数 |
machine_cpu_cores | Gauge | 逻辑 CPU 核数 |
machine_cpu_sockets | Gauge | CPU 插槽数 |
machine_memory_bytes | Gauge | 机器上安装的内存字节数 |
machine_dimm_count | Gauge | 由 dimm 类型标记的 RAM DIMM(所有类型的内存模块)值,信息从内核 3.6 中引入的 sysfs edac per-DIMM API (/sys/devices/system/edac/mc/) 检索 |
machine_dimm_capacity_bytes | Gauge | 由 dimm 类型标记的总 RAM DIMM 容量(所有类型的内存模块)值,信息从内核 3.6 中引入的 sysfs edac per-DIMM API (/sys/devices/system/edac/mc/) 检索 |
machine_nvm_capacity | Gauge | NVM 模式标记的 NVM 容量值(内存模式或应用程序直接模式) |
machine_nvm_avg_power_budget_watts | Gauge | NVM 功率预算 |
machine_cpu_cache_capacity_bytes | Gauge | 分配给 NUMA 节点和 CPU 内核的缓存大小(以字节为单位) |
machine_thread_siblings_count | Gauge | 同级 CPU 线程数 |
machine_node_memory_capacity_bytes | Gauge | 分配给 NUMA 节点的内存量 |
machine_node_hugepages_count | Gauge | 分配给 NUMA 节点的大页数 |
容器指标
容器指标分类
指标 | 默认禁用 |
---|---|
sched | 是 |
memory_numa | 是 |
tcp | 是 |
advtcp | 是 |
udp | 是 |
app | 是 |
process | 是 |
hugetlb | 是 |
referenced_memory | 是 |
cpu_topology | 是 |
resctrl | 是 |
cpuset | 是 |
accelerator | 否 |
percpu | 否 |
network | 否 |
cpuLoad | 否 |
diskIO | 否 |
disk | 否 |
perf_event | 否 |
cpu | 否 |
memory | 否 |
oom_event | 否 |
指标详情
详细指标请参考:https://support.huaweicloud.com/devg-cci/cci_05_1003.html#cci_05_1003__table20182130676
核心对象
主流程管理
Manager
负责 cAdvisor 主流程控制。
type Manager interface {
// 启动 cAdvisor Container Manager
Start() error
// 停止 cAdvisor Container Manager
Stop() error
// 获取指定容器的信息
GetContainerInfo(containerName string, query *info.ContainerInfoRequest) (*info.ContainerInfo, error)
// 获取容器的V2信息。
// 该方法会尽量递归子容器,在部分失败的情况下,可能会返回部分结果和错误。
GetContainerInfoV2(containerName string, options v2.RequestOptions) (map[string]v2.ContainerInfo, error)
// 获取指定容器的所有子容器的信息(包含其自身信息)
SubcontainersInfo(containerName string, query *info.ContainerInfoRequest) ([]*info.ContainerInfo, error)
// 获取所有的 Docker 容器信息,该方法会返回一个以container name为 key 的 map 集合
AllDockerContainers(query *info.ContainerInfoRequest) (map[string]info.ContainerInfo, error)
// 获取指定的 Docker 容器信息。指定的名称位于Docker命名空间中。
DockerContainer(dockerName string, query *info.ContainerInfoRequest) (info.ContainerInfo, error)
// 获取指定容器的 spec 信息
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)
// 判断容器是否存在,如果存在则返回true
Exists(containerName string) bool
// 获取宿主机信息
GetMachineInfo() (*info.MachineInfo, error)
// 获取我们依赖的不同组件的版本信息。
GetVersionInfo() (*info.VersionInfo, error)
// 返回具有指定文件系统uuid的设备的信息。如果不存在具有UUID的此类设备,则此函数将返回fs.ErrNoSuchDevice错误。
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)
// 获取通过passedChannel传输的符合请求的事件。
WatchForEvents(request *events.Request) (*events.EventChannel, error)
// 获取已检测到且符合请求的过去事件。
GetPastEvents(request *events.Request) ([]*info.Event, error)
// 关闭 Event Channel
CloseEventChannel(watch_id int)
// 获取 docker info 信息
DockerInfo() (info.DockerStatus, error)
// 获取docker镜像列表
DockerImages() ([]info.DockerImage, error)
// 返回调试信息。并按列表分类。
DebugInfo() map[string][]string
}
manager
manager 是 Manager 接口的实现类,其中包含 cAdvisor 运行所需的各种信息。
type manager struct {
// 当前受到监控的容器存在一个map中 containerData结构中包括了对容器的各种具体操作方式和相关信息
containers map[namespacedContainerName]*containerData
// 对map中数据存取时采用的Lock
containersLock sync.RWMutex
// 缓存在内存中的数据,主要是容器的相关信息
memoryCache *memory.InMemoryCache
// 宿主机上的实际文件系统的相关信息
fsInfo fs.FsInfo
// 用于获取宿主机信息
sysFs sysfs.SysFs
machineMu sync.RWMutex // protects machineInfo
// 宿主机的相关信息 cpu memory network system信息等等
machineInfo info.MachineInfo
// 用于存放退出信号的channel manager关闭的时候会给其中的channel发送退出信号
quitChannels []chan error
// cadvisor本身所运行的那个容器(如果cadvisor运行在容器中)
cadvisorContainer string
//是否在host的namespace中
inHostNamespace bool
// 对event相关操作进行的封装
eventHandler events.EventManager
//manager启动时间
startupTime time.Time
// 在内存中保留数据的时间 也就是下次开始搜集容器相关信息并且更新内存信息的时间
maxHousekeepingInterval time.Duration
// 是否允许动态设置dynamic housekeeping
allowDynamicHousekeeping bool
// 要采集的指标信息
includedMetrics container.MetricSet
// ContainerWatcher 列表
containerWatchers []watcher.ContainerWatcher
// 注册一个通道以监听影响子容器的事件(递归)。
eventsChannel chan watcher.ContainerEvent
collectorHttpClient *http.Client
nvidiaManager stats.Manager
perfManager stats.Manager
resctrlManager stats.Manager
// raw 容器cgroup路径前缀白名单列表。
rawContainerCgroupPathPrefixWhiteList []string
}
宿主机管理
MachineInfo
MachineInfo 用于记录宿主机的各项信息。
type MachineInfo struct {
// 当前信息的采集事件点
Timestamp time.Time `json:"timestamp"`
// 机器上CPU逻辑核心数
NumCores int `json:"num_cores"`
// 机器上CPU物理核心数
NumPhysicalCores int `json:"num_physical_cores"`
// CPU插槽数
NumSockets int `json:"num_sockets"`
// 最大CPU时钟频率(KHz)
CpuFrequency uint64 `json:"cpu_frequency_khz"`
// 内存容量(字节)
MemoryCapacity uint64 `json:"memory_capacity"`
// 按内存类型划分的内存容量和 DIMM 数量
MemoryByType map[string]*MemoryInfo `json:"memory_by_type"`
// 非易失性内存模块的信息
NVMInfo NVMInfo `json:"nvm"`
// 大页信息
HugePages []HugePagesInfo `json:"hugepages"`
// 机器ID
MachineID string `json:"machine_id"`
// 系统UUID
SystemUUID string `json:"system_uuid"`
// boot id
BootID string `json:"boot_id"`
// 本机文件系统信息
Filesystems []FsInfo `json:"filesystems"`
// 本机磁盘信息
DiskMap map[string]DiskInfo `json:"disk_map"`
// 网络设备信息
NetworkDevices []NetInfo `json:"network_devices"`
// 机器拓扑,描述 cpu/内存布局和层次结构
Topology []Node `json:"topology"`
// 本机的云供应商
CloudProvider CloudProvider `json:"cloud_provider"`
// 机器的云实例类型(例如 GCE 标准)。
InstanceType InstanceType `json:"instance_type"`
// 云提供商提供给它的云实例 ID(例如 instance-1)。
InstanceID InstanceID `json:"instance_id"`
}
SysFs
SysFs 定义了一系列方法用于获取操作系统底层的一些信息,其接口定义如下:
type SysFs interface {
// 获取所有可用的块设备的目录信息,访问的是 /sys/block 目录
GetBlockDevices() ([]os.FileInfo, error)
// 获取指定块设备的大小,访问的是 /sys/block/${device-name}/dev 文件
GetBlockDeviceSize(string) (string, error)
// 获取指定块设备的调度器类型,访问的是 /sys/block/${device-name}/queue/scheduler 文件
GetBlockDeviceScheduler(string) (string, error)
// 获取块设备的 major:minor 数字字符串,访问的是 /sys/block/${device-name}/size 文件
GetBlockDeviceNumbers(string) (string, error)
// 获取所有的网络设备信息,访问的是 /sys/class/net 目录
GetNetworkDevices() ([]os.FileInfo, error)
// 获取指定网络设备的 MAC 地址信息,访问的是 /sys/class/net/${device-name}/address 文件
GetNetworkAddress(string) (string, error)
// 获取指定网络设备的 MTU(最大传输单元(MTU)指通过联网设备可以接收的最大数据包的值),访问的是 /sys/class/net/${device-name}/mtu 文件
GetNetworkMtu(string) (string, error)
// 获取网络设备的网速信息,访问的是 /sys/class/net/${device-name}/speed 文件
GetNetworkSpeed(string) (string, error)
// 获取网络设备的统计信息,访问的是/sys/class/net/${device-name}/statistics 文件
GetNetworkStatValue(dev string, stat string) (uint64, error)
// 获取指定 cpu 的高速缓存目录信息,访问的是 /sys/devices/system/cpu/cpu${cpu-id}/cache 目录
GetCaches(id int) ([]os.FileInfo, error)
// 获取指定 cpu 的高速缓存信息,包括size、level、type、cpu 数量
// 访问的是 /sys/devices/system/cpu/cpu${cpu-id}/cache/${cache} 文件
GetCacheInfo(cpu int, cache string) (CacheInfo, error)
// 获取系统的 UUID
GetSystemUUID() (string, error)
}
realSysFs
SysFs 接口的实现类是 realSysFs,位于 github.com/google/cadvisor/utils/sysfs/sysfs.go。
容器管理
containerData
containerData 中封装了操作该容器所需的全部信息和 handler。
type containerData struct {
// 该容器handler,用于与底层 CRI 进行交互,获取容器详细信息
handler container.ContainerHandler
// 该容器的基本信息,包括容器及其子容器的引用、和容器的 info.ContainerSpec 信息
info containerInfo
// 用于缓存该容器的指标信息
memoryCache *memory.InMemoryCache
lock sync.Mutex
// 用于获取容器 load 信息
loadReader cpuload.CpuLoadReader
// 用于获取某个cgroups下面容器的某段时间的摘要信息,目前主要追踪的是cpu以及memory的信息。
summaryReader *summary.StatsSummary
// 迄今为止的平滑负载平均值
loadAvg float64
housekeepingInterval time.Duration
maxHousekeepingInterval time.Duration
allowDynamicHousekeeping bool
// 最后一次容器信息更新时间
infoLastUpdatedTime time.Time
// 最后一次容器指标更新时间
statsLastUpdatedTime time.Time
// 最后一次报错时间
lastErrorTime time.Time
// 用于跟踪时间
clock clock.Clock
// 用于负载平均平滑的衰减值。间隔长度为10秒。
loadDecay float64
// 更新此容器时是否记录其使用情况
logUsage bool
// 告知容器停止 housekeeping
stop chan bool
// 告诉容器立即收集统计信息
onDemandChan chan chan struct{}
// 运行自定义指标收集器
collectorManager collector.CollectorManager
// nvidiaCollector 更新连接到容器的Nvidia GPU的统计信息
nvidiaCollector accelerators.AcceleratorCollector
}
ContainerHandler
ContainerHandler 用于与 CRI 交互,并完成对关联 containerData 的各种操作(每个 containerData 对象都会有一个专属的 ContainerHandler)。当有容器新增时,ContainerHandlerFactory 会为该容器创建并设置 ContainerHandler。
type ContainerHandler interface {
// 获取 ContainerReference 对象
ContainerReference() (info.ContainerReference, error)
// 获取 ContainerSpec 对象
GetSpec() (info.ContainerSpec, error)
// 获取子容器的状态
GetStats() (*info.ContainerStats, error)
// 获取子容器的 ContainerReference 对象列表
ListContainers(listType ListType) ([]info.ContainerReference, error)
// 返回容器内进程pid列表
ListProcesses(listType ListType) ([]int, error)
// 获取容器指定资源的 cgroup 绝对路径
GetCgroupPath(resource string) (string, error)
// 获取容器的标签map
GetContainerLabels() map[string]string
// 获取容器的 ip 地址
GetContainerIPAddress() string
// 判断当前的容器是否还存在,存在返回true,否则返回false
Exists() bool
// 释放 ContainerHandler 所使用的资源,如 fds、go routines等
Cleanup()
// 启动所有必须的后端goroutines——必须在 Cleanup() 方法中释放
Start()
// 关联的容器的类型
Type() ContainerType
}
ContainerHandlerFactory
ContainerHandlerFactory 是 ContainerHandler 的工厂类。其功能是为指定的容器创建关联的 ContainerHandler 对象
type ContainerHandlerFactory interface {
// 通过该方法为指定的 container 创建一个 ContainerHandler,用于处理对该 container 的操作。CanHandleAndAccept() 必须返回 true
// name:容器名称
// inHostNamespace:cAdvisor 是否运行在容器中
NewContainerHandler(name string, inHostNamespace bool) (c ContainerHandler, err error)
// 判断当期的 factory 能否接收并处理指定的容器
CanHandleAndAccept(name string) (handle bool, accept bool, err error)
// factory 名称
String() string
// 返回调试信息。Map of lines per category.
DebugInfo() map[string][]string
}
ContainerHandlerFactory 的种类有:
类型 | 处理范围 |
---|---|
mesos | 只处理 mesos 关联容器 |
containerd | 只处理 containerd 关联容器 |
docker | /docker 下处于 Running 状态的容器 |
cri-o | /crio 下的容器 |
systemd | 处理包含 .mount 后缀的容器 |
raw | 名字为“/”,或 raw_cgroup_prefix_whitelist 中指定前缀的容器 |
ContainerHandlerFactory 插件注册和初始化流程:
![161d609a2477c065e6fd62b4cb2c9210.png](https://i-blog.csdnimg.cn/blog_migrate/b0315618614f19bcfed86bd2217c3f44.png)
ContainerWatcher
ContainerWatcher 用于监听主机上容器的新增或删除事件。
type ContainerWatcher interface {
// 监听所有子容器的新增或删除事件,并将事件写入到 ContainerEvent 通道中
Start(events chan ContainerEvent) error
// 停止监听
Stop() error
}
rawContainerWatcher
ContainerWatcher 接口的实现类是 rawContainerWatcher。一方面,rawContainerWatcher 在 manager 启动时,通过递归遍历 cgroup 子系统目录,完成机器上容器列表的初始化。另一方面,rawContainerWatcher 通过递归遍历 cgroup 子系统目录,并设置 InotifyWatcher,从而监听所有 cgroup 子目录的变化情况,并抛出相关事件,然后将这些事件放入 eventsChannel 中交由消费者去处理。在一方面,rawContainerWatcher 还会定期(通过--global_housekeeping_interval 参数设置)全量扫描容器列表,避免事件遗漏,从而保证内存中容器列表与机器上保持一致。
文件系统管理
FsHandler
FsHandler 负责定期收集容器各文件系统的使用情况。在新增容器并创建 ContainerHandler 时,会为容器创建关联的 FsHandler 实例。
type FsHandler interface {
// 定期收集容器各文件系统使用情况
Start()
// 获取容器文件系统使用情况
Usage() FsUsage
// 停止容器文件系统指标采集
Stop()
}
FsHandler 有两个实现类:
realFsHandler:用于定期收集并更新容器 rootfs 和 extraDir(/opt/lib/docker/containers/${容器 ID} 目录)文件系统使用情况。
dockerFsHandler:专为 Docker 设计的复合 FsHandler ,可用于收集 devicemapper、zfs 等文件系统的使用情况。
realFsHandler
realFsHandler 是一个通用 FsHandler,用于定期收集并更新容器 rootfs 和 extraDir(/opt/lib/docker/containers/${容器 ID} 目录)的文件系统使用情况。
dockerFsHandler
dockerFsHandler 是一个专为 Docker 设计的复合 FsHandler 实现,它包含 realFsHandler、devicemapper ThinPoolWatcher 和 zfsWatcher
type dockerFsHandler struct {
fsHandler common.FsHandler
// thinPoolWatcher is the devicemapper thin pool watcher
thinPoolWatcher *devicemapper.ThinPoolWatcher
// deviceID is the id of the container's fs device
deviceID string
// zfsWatcher is the zfs filesystem watcher
zfsWatcher *zfs.ZfsWatcher
// zfsFilesystem is the docker zfs filesystem
zfsFilesystem string
}
FsInfo
FsInfo 用于获取主机文件系统信息,及相关的设备、挂载点等信息。
type FsInfo interface {
// 返回主机上所有ext2、ext3和ext4文件系统的容量和可用空间(以字节为单位)。
GetGlobalFsInfo() ([]Fs, error)
// 返回传递的挂载点集合的容量和可用空间(以字节为单位)。
GetFsInfoForPath(mountSet map[string]struct{}) ([]Fs, error)
// 返回指定目录的使用情况
GetDirUsage(dir string) (UsageInfo, error)
// 返回指定文件系统uuid关联的设备的信息。如果不存在此类设备,则此函数将返回ErrNoSuchDevice错误。
GetDeviceInfoByFsUUID(uuid string) (*DeviceInfo, error)
// 返回“dir”所在文件系统的块设备信息。
GetDirFsDevice(dir string) (*DeviceInfo, error)
// 返回与特定标签关联的设备名称。
GetDeviceForLabel(label string) (string, error)
// 返回与特定设备名称关联的所有标签。
GetLabelsForDevice(device string) ([]string, error)
// 返回与特定设备关联的挂载点。
GetMountpointForDevice(device string) (string, error)
}
RealFsInfo
RealFsInfo 是对 FsInfo 接口的实现
type RealFsInfo struct {
// 从块设备路径映射到分区信息。
partitions map[string]partition
// 从标签映射到块设备路径。
// 标签是自动检测到的特定于意图的标签。
labels map[string]string
// 从挂载点映射到挂载信息。
mounts map[string]mount.Info
// devicemapper 客户端
dmsetup devicemapper.DmsetupClient
// fsUUIDToDeviceName 是从文件系统UUID到其设备名称的映射。
fsUUIDToDeviceName map[string]string
}
事件管理
EventManager
EventManager 用于管理容器生命周期中一些重要的事件,调用方可以通过调用 WatchEvents() 方法监听自己关心的事件,或调用 AddEvent() 方法新增事件到 EventManager。用户可以通过调用 HTTP 接口设置要监听的事件,并获取这些事件。 目前已定义的事件包括:
oom:通过监听 /dev/kmsg 内核日志,获取容器 OOM 事件。
oomKill:同上。
containerCreation:容器新增事件。
containerDeletion:容器销毁事件。
type EventManager interface {
// 当 WatchEvents() 方法被调用时,就会生成一个新的 watch 对象,并注册到 EventManager 中
// 该方法会返回一个 EventChannel 通道,监听到的满足条件的事件会被放入该通道中,调用方从该通道中读取事件
WatchEvents(request *Request) (*EventChannel, error)
// 从 eventStore 中查询满足指定条件的事件列表
GetEvents(request *Request) ([]*info.Event, error)
// 允许调用方添加一个事件到事件队列中,该方法的执行流程为:
// 1\. 将 event 添加到 eventStore 中
// 2\. 遍历所有的 watch,判断是否满足 watch 条件,如果满足,则放入 watch 的 eventChannel 中,这样对应的调用方就能收到该事件
AddEvent(e *info.Event) error
// 取消对 watch_id 所要求的事件的监听,从 watchers 中移除 watch 对象,并关闭其 eventChannel
StopWatch(watch_id int)
}
events
events 类是 EventManager 接口的默认实现类。
type events struct {
// 按类型存储各种事件
eventStore map[info.EventType]*utils.TimedStore
// 已注册的 watch 列表,以 watch id 为key
watchers map[int]*watch
// lock guarding the eventStore.
eventsLock sync.RWMutex
// lock guarding watchers.
watcherLock sync.RWMutex
// 上一个已分配的 watch id,每个 watch 对象都有一个唯一的id。每次有新的 watch 生成时,该值加1
lastId int
// 事件存储策略
storagePolicy StoragePolicy
}
EventChannel
事件通道,用于缓存近期生成的事件。
type EventChannel struct {
// Watch ID. Can be used by the caller to request cancellation of watch events.
watchId int
// Channel on which the caller can receive watch events.
channel chan *info.Event
}
StoragePolicy
StoragePolicy 定义了事件在内存中存储的策略,包括事件存储最大时长(默认 24 小时)、最大可保存事件数量(默认 10w 条)、各类型事件事件存储最大时长和最大可保存事件数量。
type StoragePolicy struct {
// 各类事件默认保留的最大时长
DefaultMaxAge time.Duration
// 各类事件默认保留的最大条数
DefaultMaxNumEvents int
// 各类事件保留的最大时长
PerTypeMaxAge map[info.EventType]time.Duration
// 各类事件保留的最大条数
PerTypeMaxNumEvents map[info.EventType]int
}
指标存储
StorageDriver
StorageDriver 用于将数据转存到外部存储,它的特点是容量较大,但存取速度较慢。
type StorageDriver interface {
// 添加指标数据
AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error
// 将清除存储驱动程序的状态。存储在底层存储器中的元素可以被删除,
// 也可以不被删除,这取决于存储驱动程序的实现。
Close() error
}
cAdvisor 支持的 StorageDriver 类型有:
BigQuery
ElasticSearch
InfluxDB
Kafka
Redis
Statsd
stdout
InMemoryCache
InMemoryCache 用于将数据保存在内存中,它的特点是存取速度快,但容量有限。
// 添加指标数据
func (c *InMemoryCache) AddStats(cInfo *info.ContainerInfo, stats *info.ContainerStats) error
// 获取最近一个时间区间的指标数据
func (c *InMemoryCache) RecentStats(name string, start, end time.Time, maxStats int) ([]*info.ContainerStats, error)
// 关闭缓存
func (c *InMemoryCache) Close() error
// 删除指定 Container 关联的指标
func (c *InMemoryCache) RemoveContainer(containerName string) error
StorageDriver 注册和初始化流程如下图所示:
![7835aff77754b119235e5f0aa44ec747.png](https://i-blog.csdnimg.cn/blog_migrate/3d352bd2da44812fbea25e7761ed3a53.png)
指标采集
Collector
type Collector interface {
// 从当前 collector 中采集指标
// 返回该 collector 下次需要采集的时间。该接口每次都会返回 collector 下次需要采集的时间,即便发生了错误
// 如果无需继续采集,该接口返回的时间为0
Collect(map[string][]v1.MetricVal) (time.Time, map[string][]v1.MetricVal, error)
// 返回该 collector 关联的所有指标的spec信息
GetSpec() []v1.MetricSpec
// collector的名称
Name() string
}
cAdvisor 中 Collector 接口的实现类有两个:
PrometheusCollector:Prometheus 指标采集器
GenericCollector:通用指标采集器
CollectorManager
CollectorManager 用于管理和运行 Collectors。
type CollectorManager interface {
// 注册一个 collector
RegisterCollector(collector Collector) error
// 从所有已经准备就绪的 collector 采集指标,并返回 collector 下次可以被采集的时间。
// 该接口每次都会返回 collector 下次需要采集的时间,即便发生了错误
// 如果无需继续采集,该接口返回的时间为0
Collect() (time.Time, map[string][]v1.MetricVal, error)
// 获取所有已注册的 collector 关联的指标的spec信息
GetSpec() ([]v1.MetricSpec, error)
}
GenericCollectorManager
GenericCollectorManager 是 CollectorManager 接口的实现类,用于管理和运行 Collectors。
type GenericCollectorManager struct {
// 已注册的 Collector 列表
Collectors []*collectorData
// 下次指标采集时间
NextCollectionTime time.Time
}
核心流程
cAdvisor 初始化流程
![d047896d04584f024c74ac24287182fc.png](https://i-blog.csdnimg.cn/blog_migrate/c1b2ca65d368621116418e0795ea6ab7.png)
manager 启动流程
![2d9f0c1d69b3b78738628c4c1cd75e5e.png](https://i-blog.csdnimg.cn/blog_migrate/05cd7e3946660b31e0357688505f6fc4.png)
Container 创建流程
![21fc9df1fa8e08bf924b291c94ce75b2.png](https://i-blog.csdnimg.cn/blog_migrate/195e5dd6b87c9720c579a649e10f1ff7.png)
容器指标生成流程
![c7c8ef152ed10e440840e1db7fffb8d7.png](https://i-blog.csdnimg.cn/blog_migrate/0c2caa8e80a5d3431ce6e85b77451e76.png)
指标采集流程
![8e3b09b2adf1c2ddc939cc1bfc827aa4.png](https://i-blog.csdnimg.cn/blog_migrate/5da9cf8e2a13f8e579b31dc1f81c98e8.png)
kubelet 与 cAdvisor 交互流程
![e5ca0b37378a313a731579550ff4c1f2.png](https://i-blog.csdnimg.cn/blog_migrate/32d3a4b221724495fc02da11fb474219.png)
引用链接
[1]
定义: https://github.com/google/cadvisor/blob/master/container/common/test_resources/container_hints.json
本文转载自:「简书」,原文:https://url.hi-linux.com/t7jPl,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。
最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。
你可能还喜欢
点击下方图片即可阅读
全网最详保姆级 Kubernetes 应用调试中文指南
点击上方图片,『美团|饿了么』外卖红包天天免费领
更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!