cAdvisor原理解析

简介

cAdvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行CAdvisor用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示。

cAdvisor可以对节点机器上的资源及容器进行实时监控和性能数据采集,包括CPU使用情况、内存使用情况、网络吞吐量及文件系统使用情况

实现原理

cAdvisor的数据采集分为两个部分machineInfo和containerInfo。


启动参数

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文件的格式参考定义。当前该配置仅用于原生容器驱动。 /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 插件注册和初始化流程:

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注册和初始化流程如下图所示:

指标采集

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初始化流程

manager启动流程

Container创建流程

容器指标生成流程

指标采集流程

kubelet与cAdvisor交互流程

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容