cadvisor详解
一. cadvisor和k8s的耦合
cadvisor是一个谷歌开发的容器监控工具,它被内嵌到k8s中作为k8s的监控组件。现在将k8s中的cadvisor实现分析一下。
k8s中和cadvisor的代码主要在./pkg/kubelet/cadvisor目录下。在当前k8s版本(v1.13)中,kubelet主要调用的cadvisor方法如下:
MachineInfo
RootFsInfo
VersionInfo
GetDirFsInfo
GetFsInfo
---------------------------------------
ContainerInfoV2
SubcontainerInfo
ContainerInfo
WatchEvents
分割线之上的方法和cadvisor本身耦合较松,分割线之下的方法则和cadvisor耦合紧密。怎么样理解这里的耦合度呢?举例来说,对于分割线
之上的方法,例如MachineInfo,它的操作只是简单的读取本地文件以获取主机的信息。比如通过读取/proc/cpuinfo文件读取本地主机的cpu信息。
对于这种方法,我们可以非常轻松的移植他们。
而分割线之下的方法则很难从cadvisor中单独剥离出来,它们的实现是依赖于整个cadvisor的体系。下面分析一下cadvisor具体的实现
二. 事件监听层
cadvisor的架构简单来说就是一个event机制。它基本上可以分为两层,事件监听层和事件处理层。事件监听层负责监听linux系统发生的事件,而事件处理层
负责对这些事件进行处理。
首先说说事件监听层。事件监听层主要包含两个监听者,ContainerAdd事件和OOM事件。其对应的函数是watchForNewContainers, watchForNewOoms。
watchForNewContainers完成的事情是启动每一个watcher。代码如下,可以看到和watcher交互的是eventsChannel。目前cadvisor中包含两种wathcer, 一个是rawWatcher,另一个是rktWatcher。
for _, watcher := range self.containerWatchers {
err := watcher.Start(self.eventsChannel)
if err != nil {
return err
}
}
rawWatcher直接监控系统的cgroup根目录,而rktWatcher似乎是与rkt的client进行交互,由于rkt不是主流的技术,因此我们目前主要研究rawWatcher。这个watcher的代码在./manager/watcher/raw目录下。
稍作分析就可以看出这个watcher是调用了github.com/sigma/go-inotify库,这个库简单来说就是利用linux的inotify机制对cgroup根目录进行监听,如果根目录创建了新的目录,那么它就会触发一个ContainerAdd的事件。
然后将事件发送到上面代码中的self.eventsChannel中。注意linux的inotify机制会监听目录的增删改。而这里rawWatcher只对目录的增删感兴趣。也就是说它只对容器的创建和删除感兴趣,对容器本身状态的变化不感兴趣。
对函数rawContainerWatcher.watchDirectory的代码稍作分析不难发现,它是一个递归调用的结构。如果用户请求对任何目录进行监听,它会一并监听这个目录下的所有子目录。
watchForNewOoms是为了监控OOM事件,它的执行流程与container watcher类似,只不过调用的库是github.com/euank/go-kmsg-parser/,这个库的原理是读取linux系统的/dev/kmsg字符串设备。这个字符串设备的大概
意思是将系统的事件报告出来。其核心代码如下。
outStream := make(chan *oomparser.OomInstance, )
oomLog, err := oomparser.New()
if err != nil {
return err
}
go oomLog.StreamOoms(outStream) go func() {
for oomInstance := range outStream {
// Surface OOM and OOM kill events.
newEvent := &info.Event{
ContainerName: oomInstance.ContainerName,
Timestamp: oomInstance.TimeOfDeath,
EventType: info.EventOom,
}
err := self.eventHandler.AddEvent(newEvent)
if err != nil {
klog.Errorf("failed to add OOM event for %q: %v", oomInstance.ContainerName, err)
}
三 事件处理层
事件监听层将event发送到self.eventsChannel上,这些event包含了,ContainerAdd, ContainerDelete,EventOomKill三种。这三种事件分两类进行处理,对于ContainerAdd和ContainerDelete, Manager分别
调用CreateContainer和ContainerDestroy方法,然后调用self.eventHandler.AddEvent(event)方法。而EventOomkill事件则只调用self.eventHandler.AddEvent(event)方法,没有其他特殊的处理。
那么这个eventHandler是干啥的呢。这个东西实际上就是一个缓冲区,我们看一下这个evnetHandler的数据结构。它的核心数据结构就是events.watchers,它维护了一组watch,每一个watch存储了一个channel和一个
request。这个request其所在的watch想要监听的事件特性。evnetsHandler每当接收到新的事件的时候,它会根据这个事件的类型分发给各个watch。
// events provides an implementation for the EventManager interface.
type events struct {
// eventStore holds the events by event type.
eventStore map[info.EventType]*utils.TimedStore
// map of registered watchers keyed by watch id.
watchers map[int]*watch
// lock guarding the eventStore.
eventsLock sync.RWMutex
// lock guarding watchers.
watcherLock sync.RWMutex
// last allocated watch id.
lastId int
// Event storage policy.
storagePolicy StoragePolicy
} // initialized by a call to WatchEvents(), a watch struct will then be added
// to the events slice of *watch objects. When AddEvent() finds an event that
// satisfies the request parameter of a watch object in events.watchers,
// it will send that event out over the watch object's channel. The caller that
// called WatchEvents will receive the event over the channel provided to
// WatchEvents
type watch struct {
// request parameters passed in by the caller of WatchEvents()
request *Request
// a channel used to send event back to the caller.
eventChannel *EventChannel
} // Request holds a set of parameters by which Event objects may be screened.
// The caller may want events that occurred within a specific timeframe
// or of a certain type, which may be specified in the *Request object
// they pass to an EventManager function
type Request struct {
// events falling before StartTime do not satisfy the request. StartTime
// must be left blank in calls to WatchEvents
StartTime time.Time
// events falling after EndTime do not satisfy the request. EndTime
// must be left blank in calls to WatchEvents
EndTime time.Time
// EventType is a map that specifies the type(s) of events wanted
EventType map[info.EventType]bool
// allows the caller to put a limit on how many
// events to receive. If there are more events than MaxEventsReturned
// then the most chronologically recent events in the time period
// specified are returned. Must be >= 1
MaxEventsReturned int
// the absolute container name for which the event occurred
ContainerName string
// if IncludeSubcontainers is false, only events occurring in the specific
// container, and not the subcontainers, will be returned
IncludeSubcontainers bool
}
剩下的事就很简单了,对于任何ContainerAdd事件,manager维护了一组工厂类,每一个类对应一种container类型。这些工厂类定义在./container中。manager分析ContainerAdd事件中的相关信息,将它传递
给对应的工厂类,工厂类为container生成一个对应的handler并且存储起来,handler执行具体的监控任务。具体来说就是定期读取container对应的cgroup文件。从中获取信息。handler将读取到的数据存储到自己的缓存memoryCache中。
handler的包装类型是containerData
四. k8s中用到的几个关键函数
GetContainerV2(),直接获取它想要的container对应的handler,然后读取其中memoryCache的状态数据
WatchEvents(),这个函数主要是OOMWatcher在调用,它暴露出一个channel给OOMWatcher用以监听系统的OOMWatcher事件
cadvisor详解的更多相关文章
- 详解k8s一个完整的监控方案(Heapster+Grafana+InfluxDB) - kubernetes
1.浅析整个监控流程 heapster以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.网络流量等,然后将这些数据输出到外部存储,如Inf ...
- 详解k8s原生的集群监控方案(Heapster+InfluxDB+Grafana) - kubernetes
1.浅析监控方案 heapster是一个监控计算.存储.网络等集群资源的工具,以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.netwo ...
- Kubernetes学习之路(二十)之K8S组件运行原理详解总结
目录 一.看图说K8S 二.K8S的概念和术语 三.K8S集群组件 1.Master组件 2.Node组件 3.核心附件 四.K8S的网络模型 五.Kubernetes的核心对象详解 1.Pod资源对 ...
- Kubernetes Pod 驱逐详解
原文链接:Kubernetes Pod 驱逐详解 在 Kubernetes 中,Pod 使用的资源最重要的是 CPU.内存和磁盘 IO,这些资源可以被分为可压缩资源(CPU)和不可压缩资源(内存,磁盘 ...
- kubelet 参数详解
kubelet 参数详解 基本参数 --allow-privileged=true #允许容器请求特权模式 --anonymous-auth=false #不允许匿名请求到 kubelet 服务(默认 ...
- Kubernetes K8S之存储Volume详解
K8S之存储Volume概述与说明,并详解常用Volume示例 主机配置规划 服务器名称(hostname) 系统版本 配置 内网IP 外网IP(模拟) k8s-master CentOS7.7 2C ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
随机推荐
- 【C语言】一次内存泄露的分析的记录
今天运行一个程序,程序刚启动时占用内存很小,在运行过程中发现占用的内存会一直增大. 用cat /proc/pid/statm的方式查看发现也确实在一直增大. 而且这个程序移植到另外一个平台后,会直接无 ...
- 最简单的windows平台Git服务器---Gitstack 【转】
转自:http://www.360doc.com/content/12/0503/11/1016783_208316518.shtml 目前在windows平台上的git服务器大多数采用CopSSH+ ...
- HTML5 拖拽事件
dragstart:拖拽开始 drag: 拖拽中,会不停的触发 dragend:拖拽结束 ondraglevea:有元素离开了本元素 ondragenter:有元素进入了本元素 ondragover: ...
- 关于C++编译的程序无法在新一台电脑上运行总结
最近在调用一个SDK调试一个主板的DPIO. 可是编译好的程序在开发电脑上运行没问题,到了新主板建立的电脑系统上就出问题. 总结了下要注意一下几方面. 1:程序本身要没有问题.至少在开发电脑系统环境下 ...
- Pycharm上python和unittest两种姿势傻傻分不清楚【转载】
前言 经常有人在群里反馈,明明代码一样的啊,为什么别人的能出报告,我的出不了报告:为什么别人运行结果跟我的不一样啊... 这种问题先检查代码,确定是一样的,那就是运行姿势不对了,一旦导入unittes ...
- python的上下文管理(context)(1)
本文转载自:http://blog.csdn.net/G_66_hero/article/details/53048540 什么是Python中的上下文管理器 怎么使用上下文管理器 如何创建自己的上下 ...
- WebDriver框架之自动运行失败的case
大家在运行自动化case的时候都会碰到失败的情况,有的时候可能是被测程序有bug,还有就是网络的问题,如果想采取失败的case再运行一次的机制,那么有bug的情况,即使再运行N次还是失败,那么如果是网 ...
- mysql table status
SHOW TABLE STATUS 能获得表的信息 可以SHOW TABLE STATUS where name='表名'
- (24)python 无线破解
import pywifi import time wifi = pywifi.PyWiFi() # iface = wifi.interfaces()[0]#获取第一块网卡 #print(iface ...
- 洛谷 P1598 垂直柱状图【字符串】
题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数.严格地按照输出样例来安排你的输出格式. 输入输出格式 输入格式 ...