16

Container及其内部进程监控剖析-wx5c2da66615f74的博客

 4 years ago
source link: https://blog.51cto.com/14159827/2431963
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Container及其内部进程监控剖析

目前市场上的虚拟化技术种类很多,例如moby(docker)、LXC、RKT等等。在带来方便应用部署和资源充分利用的好处的同时,如何监控相应Container及其内部应用进程成为运维人员不可避免遇到的新情况。UAV.Container从虚拟化技术的基础原理和Linux操作系统的内核特性出发,得到Container容器和内部进程的各维度监控数据,使无论是虚拟机或物理机运维人员,还是业务运维人员角度,都能得到合适的监控维度。

虚拟化技术从基础原理上主要是cgroups、namespace和file system的应用,而操作系统作为cgroup和namespace根节点,无论在container里启动何种应用,从内核角度上来说,肯定在操作系统有其一定的特征和表现形式。我们需要做的就是对这些特征做加工处理,以得到相应的监控数据。

下面我们以docker技术举例,其他虚拟化技术类似。

一、Container ID

Container ID是一个Container的唯一标识。从容器监控的角度我们需要能得到该进程在哪个Container里运行。在操作系统层面,进程的cgroup的挂载情况就能有所体现。如图所示,我们在一个ID为3411554ff684的Container内部跑一个Tomcat进程。

Container及其内部进程监控剖析

由于Container的pid namespace是操作系统的pid namespace的子namespace,那么该进程在操作系统级也应该有相应的pid,用docker top命令验证一下:

Container及其内部进程监控剖析

该容器内进程在宿主机上的进程号为1848。接下来进入/proc/1848/cgroup下看看该进程的cgroup挂载情况

Container及其内部进程监控剖析

从cgroup文件里清楚的显示了实现了该容器的虚拟化技术、Container ID和此container的资源挂载路径,对比一下这里面显示的Container ID,和创建Container时的ID完全相同。这也验证了通过扫描宿主机进程的cgroup信息可以获得Container ID。这样就将pid和Container ID做了关联。

二、CPU

虽然cgroup管控了该cgroup下所有进程的CPU使用情况,但从操作系统的角度上,不论进程是否隶属于某个子cgroup下,仍然是共用宿主机的CPU。所以监控宿主机上该进程的CPU就能得到进程的CPU监控指标。

Linux上常用的CPU监控命令是top。top对CPU监控的原理是在time1时刻获取CPU从启动时的累计总时间countAll1和busy总时间countBusy1,再到time2时刻获取CPU总时间countAll2和busy总时间countBusy2,最后用busy的时间差值减去总时间的差值得到了在time1到time2这个时间段内机器CPU的占用情况。也就是:

CPU占用率(%) = (countBusy2 - countBusy1)/(countAll2 - countAll1) * 100

进程同理,在两个时刻分别得到每个进程的busy总时间countProcBusy1和countProcBusy2,则得到进程CPU占用率:

进程CPU占用率(%) = (countProcBusy2 - countProcBusy1)/(countProcAll2 - countProcAll1)*100

宿主机从启动开始的CPU总时间片可以从/proc/stat下获取:

Container及其内部进程监控剖析

第一行是总的CPU使用情况,具体参数的意思:

所以,选择当前为time1,3秒后为time2,countAll = user + nice + system + idle + iowait + irq + softirq + stealstolean + guest + guest_nice。countBusy为countAll减去idle的值,这样上面第一个公式的所有需要的值就齐了,可以直接计算。

第二行、第三行是每个逻辑CPU的使用情况,这里记下有两个逻辑CPU,CPU的逻辑核数与CPU显示模式irix和solaris有关。

接下来是countProcBusy的计算,进程的CPU时间片位于/proc/$pid/stat下,如图所示:

Container及其内部进程监控剖析

这个文件里面体现了很多进程的相关信息。其中第14、15、16、17个参数与CPU有关。

所以,countProcBusy = utime + stime + cutime + cstime,该值包括其所有线程的cpu时间。而countProcAll2-countProcAll1=3s,通过两个时刻的countProcBusy和countProcAll,进程CPU的占用率就能得到了。

其中需要注意的问题有两点:

1) jiffies实际上指的是内核时钟使用的节拍总数,所以这里的jiffies需要换算成秒才能应用上面的除法公式。

2) 刚刚我们谈到CPU显示模式irix和solaris,简单来说irix模式就是机器有N个逻辑CPU,CPU显示上限就是N*100%,solaris模式就是不管机器有多少逻辑CPU,CPU显示上限就是100%,而/proc/$pid/stat显示的是计算了所有逻辑CPU时间的,所以两种显示方式意味着计算方法稍有差异,solaris模式的结果需要在上面进程CPU占用率公式基础之上除以逻辑核数。

进程内存的监控有两个维度的数据:一是物理占用内存大小,二是进程内存占用百分比的大小。

进程内存占用率(%) = 进程物理内存占用大小 / 宿主机总内存大小 * 100

与CPU类似,/proc/$pid/status文件记录了进程物理内存使用情况,其中VmRSS即为该进程目前所占实际物理内存的大小。

Container及其内部进程监控剖析

/proc/meminfo文件下记录了机器内存占用情况,这个文件很长,截取其中的一部分展示一下,MemTotal就是宿主机总内存大小:

Container及其内部进程监控剖析

这样,这个进程的物理内存占用和机器总内存就都得到了,相应的进程内存的占用率也就得到了。

四、磁盘IO

磁盘IO获取也很简单,/proc/$pid/io已经帮我们把这个进程的io情况记录下来了,但是与CPU类似,io文件里存的也是该进程从启动到现在的io总量,那么:

磁盘I/O(bytes/秒) = (time2时刻I/O – time1时刻I/O) / (time2 – time1)

Container及其内部进程监控剖析

其中的read_bytes和write_bytes分别为该进程从启动到目前为止的读取字节数和写入字节数,分别取2个时刻的值,根据上面的公式,就得到了该进程的磁盘IO。

五、端口号和连接数

由于Network Namespace对网络做了隔离,所以如果进程在Container内部运行,该进程的端口信息也应该是进程本身监听的端口号,而不是真正实际对外的端口,而Container内外端口的映射机制是由应用的虚拟化技术本身控制的,这就避免不了与实现容器的虚拟化技术打交道了,那么问题就转化成获取容器内进程本身监听的端口了。

/proc/$pid/net/tcp(tcp6,udp,udp6)就对端口号和连接数做了相应的历史记录。这些文件格式都类似,以tcp6举例

Container及其内部进程监控剖析

解释几个关键的key:

因为st = 0A代表listen,所以从其中挑选出st = 0A的数据,取出对应的inode号,这里这个inode号是socket号,则问题转换为了这个进程是否还存在这个socket号代表的socket。在/proc/$pid/fd下有该进程所有的fd(file descriptor),截取一段举个例子。

Container及其内部进程监控剖析

每个文件描述符后面的软链实际上就是打开的文件,以socket开头的就是这个进程打开的socket,在中括号中间的部分就是socket号。拿着这个socket号和上面tcp6里获得的inode号做一个匹配,如果对应上,那么tcp6里的st = 0A的端口就是这个进程监听的。至于容器内外端口的映射,这就需要根据应用的虚拟化技术的映射方法来获取了。连接数计算与端口扫描是同理的,区别只在于需要对st = 01(establish)进行扫描计数累加。

  • 上面的方法将容器内所有进程的CPU、内存、磁盘IO、端口号和连接数都拿到了。根据Container ID就可以对不同的Container的对应数据做加和,就获得了Container级的监控数据。
  • 在容器内的进程是通过在操作系统级别反映出的pid和Container ID的对应关系来关联的。这样就可以通过读取/proc下的文件来获取监控数据。

参考文档:

http://elixir.free-electrons.com/linux/v3.10/ident

作者:周新宇


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK