Container内部进程监控

Stella981
• 阅读 216

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

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

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

  1. 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做了关联。

  1. 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使用情况,具体参数的意思:

参数(单位:jiffies)

意义

user(13194198)

用户态运行时间,不包括nice值为负的

nice(167)

nice值为负的进程所占用时间

system(17492544)

内核态占用时间

idle(160819392)

闲置时间

iowait(17224)

IO等待时间

irq(0)

硬中断时间

softirq(52326)

软中断时间

stealstolean(0)

虚拟环境下其他操作系统运行时间

guest(0)

running a normal  guest

guest_nice(0)

running a niced  guest

所以,选择当前为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有关。

参数(单位:jiffies)

意义

utime (52361)

该任务在用户态的运行时间

stime(32298)

该任务在内核态的运行时间

cutime(0)

该任务已死的线程在用户态的运行时间

cstime(0)

该任务已死的线程在内核态的运行时间

所以,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占用率公式基础之上除以逻辑核数。

  1. 内存

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

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

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

Container内部进程监控

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

Container内部进程监控

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

  1. 磁盘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。

  1. 端口号和连接数

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

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

Container内部进程监控

解释几个关键的key:

key

意义

local_address

本地地址,ip(网络字节序):端口(十六进制)

remote_address

远端地址

st

连接状态(十六进制),包括listen、establish、time_wait等等

inode

inode号

因为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)进行扫描计数累加。

总结:

  1. 上面的方法将容器内所有进程的CPU、内存、磁盘IO、端口号和连接数都拿到了。根据Container ID就可以对不同的Container的对应数据做加和,就获得了Container级的监控数据。

  2. 在容器内的进程是通过在操作系统级别反映出的pid和Container ID的对应关系来关联的。这样就可以通过读取/proc下的文件来获取监控数据。

参考文档:

http://man7.org/linux/man-pages/man5/proc.5.html

http://man7.org/linux/man-pages/dir\_section\_1.html

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

◆ ◆ ◆  ◆ ◆

发现文章有错误、对内容有疑问,都可以通过关注宜信技术学院微信公众号(CE_TECH),在后台留言给我们。我们每周会挑选出一位热心小伙伴,送上一份精美的小礼品。快来扫码关注我们吧!

Container内部进程监控

本文分享自微信公众号 - 宜信技术学院(CE_TECH)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
刚刚好 刚刚好
2个月前
css问题
1、 在IOS中图片不显示(给图片加了圆角或者img没有父级) <div<img src""/</div div {width: 20px; height: 20px; borderradius: 20px; overflow: h
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录 问题 用navicat导入数据时,报错: 原因这是因为当前的MySQL不支持datetime为0的情况。 解决修改sql\mode: sql\mode:SQL Mode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。 全局s
晴空闲云 晴空闲云
2个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。 盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
1个月前
快速入门|使用MemFire Cloud构建React Native应用程序
> MemFire Cloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Stella981 Stella981
1年前
MAC docker启动参数修改
启动 docker,漏加 16020 端口,怎么修改呢? 1\. Docker ps 看一下id CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
Stella981 Stella981
1年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置 1、virsh edit centos7 找到“memory”和“vcpu”标签,将 <name>centos7</name> <uuid>2220a6d1-a36a-4fbb-8523-e078b3dfe795</uuid>
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序 select * from table_name order id desc; 2.按照指定(多个)字段排序 select * from table_name order id desc,status desc; 3.按照指定字段和规则排序 selec
Stella981 Stella981
1年前
Container及其内部进程监控剖析
目前市场上的虚拟化技术种类很多,例如moby(docker)、LXC、RKT等等。在带来方便应用部署和资源充分利用的好处的同时,如何监控相应Container及其内部应用进程成为运维人员不可避免遇到的新情况。UAV.Container从虚拟化技术的基础原理和Linux操作系统的内核特性出发,得到Container容器和内部进程的各维度监控数据,使无论是虚拟机
helloworld_28799839 helloworld_28799839
2个月前
常用知识整理
# Javascript ## 判断对象是否为空 ```js Object.keys(myObject).length === 0 ``` ## 经常使用的三元运算 > 我们经常遇到处理表格列状态字段如 `status` 的时候可以用到 ``` vue
helloworld_34035044 helloworld_34035044
4个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。 uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid() 或 uuid(sep)参数说明:sep 布尔值,生成的uuid中是否包含分隔符'',缺省为