DockOne微信分享(一三七):Kubernetes主机和容器的监控方案


【编者的话】随着Docker容器云的广泛应用,大量的业务软件运行在容器中,这使得对Docker容器的监控越来越重要。传统的监控系统大多数是针对物理机或者虚拟机设计的,而容器的特点不同与传统的物理机或者虚拟机,如果还是采用传统的监控系统,则会增加监控复杂程度,那么如何对容器进行监控呢?

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。

今天很高兴能和大家一起交流和分享在工作中的一些经验和总结。都知道监控在运维体系乃至产品的整个生命中期都是重要的一个环节,针对不同的应用场景,监控方案也会有很大的不同。本次就和大家分享一下我在开发我们公司新产品ufleet的监控模块时的一些技术总结,如果有错误的地方,欢迎大家指出。

一个完整的监控体系包括:采集数据、分析存储数据、展示数据、告警以及自动化处理、监控工具自身的安全机制,接下来会对数据的采集和监控原理深入讲解,其他部分会在一些架构中穿插讲解。

数据的采集方式

命令行方式

比如在Linux系统上使用top,vmstat,netstat写一些shell脚本进行数据的采集,再把数据存储在文本文件中进行处理。

嵌入式

通过在进程中运行Agent的方式获取应用的状态。如目前的APM产品都是通过将监控工具嵌入到应用内部进行数据采集。

主动输出

提前在应用中埋点,应用主动上报。比如一些应用系统的业务状态,可以通过在日志中主动输出状态用于采集。

旁路式

通过外部获取的方式采集数据。比如对网站url的探测,模拟业务的报文 ,对服务器的ping,流量的监控。可以通过在交换机上将流量进行端口复制,将源始流量复制到另一个端口后再进行处理,这样这业务系统是完全没有侵入。

远程接入

通过对应用进程接口调用获取应用的状态。比如使用JMX的方式连接到Java进程中,对进程的状态进行采集。

入侵式

不同于嵌入式,入侵式的agent是独立运行的进程,而不是运行在进程中。这个目前监控工具比较常用的方式,比如Zabbix,在主机上运行一个进程进行相关数据的采集。

监控原理

具体监控指标总结如下:

首先是容器本身资源使用情况:CPU,内存,网络,磁盘

物理机的资源使用情况:CPU,内存,网络,磁盘

物理机上容器镜像情况:名字,大小,版本。

主机的监控

1、CPU数据

使用top命令可以查看当前CPU使用情况,源文件来自/proc/stat
采样两个足够短的时间间隔的CPU快照,分别记作t1、t2,其中t1、t2的结构均为:(user、nice、system、idle、iowait、irq、softirq、stealstolen、guest)的9元组;

a)计算总的CPU时间片totalCpuTime

把第一次的所有CPU使用情况求和,得到s1;
把第二次的所有CPU使用情况求和,得到s2;
s2 - s1得到这个时间间隔内的所有时间片,即totalCpuTime = j2 - j1;

b)计算空闲时间idle

idle对应第四列的数据,用第二次的第四列 - 第一次的第四列即可

idle = 第二次的第四列 - 第一次的第四列

c)计算CPU使用率

PCPU = 100* (total-idle)/total

Linux内存监控

使用free命令可以查看当前内存使用情况,其数据来源是来自/proc/meminfo文件。

常用的计算公式:

real_used = used_mem - buffer - cache
real_free = free_mem + buffer + cache
total_mem = used_mem + free_mem

Network数据

/proc/net/dev保存着有关网络的数据,如计算一段时间sec秒内的网络平均流量:

infirst = $(awk'/'$eth'/{print $1 }' /proc/net/dev |sed 's/'$eth'://')
outfirst = $(awk'/'$eth'/{print $10 }' /proc/net/dev)
sumfirst = $(($infirst+$outfirst))
sleep$sec"s"
inend = $(awk'/'$eth'/{print $1 }' /proc/net/dev |sed 's/'$eth'://')
outend = $(awk'/'$eth'/{print $10 }' /proc/net/dev)
sumend = $(($inend+$outend))
sum = $(($sumend-$sumfirst))
aver = $(($sum/$sec))

Docker的监控

Docker自身提供了一种内存监控的方式,即可以通过docker stats对容器内存进行监控。

该方式实际是通过对cgroup中相关数据进行取值从而计算得到。其数据来源是/sys/fs/cgroup。

DockerClient相关代码入口可参考:/docker/docker/api/client/stats.go#141

DockerDaemon相关代码入口可参考:/docker/docker/daemon/daemon.go#1474

CPU数据

DockerDaemon会记录这次读取/sys/fs/cgroup/cpuacct/docker/ [containerId]/cpuacct.usage的值,作为cpu_total_usage;并记录了上一次读取的该值为pre_cpu_total_usage;读取/proc/stat中cpu field value,并进行累加,得到system_usage;并 记录上一次的值为pre_system_usage;读取/sys/fs/cgroup/cpuacct/docker/ [containerId]/cpuacct.usage_percpu中的记录,组成数组per_cpu_usage_array;

DockerStats计算CPU Percent的算法:

cpu_delta = cpu_total_usage - pre_cpu_total_usage;
system_delta = system_usage - pre_system_usage;
CPU% = ((cpu_delta / system_delta) * length(per_cpu_usage_array) ) * 100.0。

Memory数据

读取/sys/fs/cgroup/memory/docker/[containerId]/memory.usage_in_bytes的值,作为 mem_usage;如果容器限制了内存,则读取/sys/fs/cgroup/memory/docker/ [id]/memory.limit_in_bytes作为mem_limit,否则mem_limit = machine_mem;docker stats计算 Memory数据的算法:

MEMUSAGE = mem_usage
MEMLIMIT = mem_limit
MEM% = (mem_usage / mem_limit) * 100.0

Network Stats数据

获取属于该容器networknamespace veth pairs在主机中对应的veth*虚拟网卡EthInterface数组,然后循环数组中每个网卡设备,读取/sys/class/net/[device]/statistics/rx_bytes得到rx_bytes, 读取/sys/class/net/[device]/statistics/tx_bytes得到对应的tx_bytes。

将所有这些虚拟网卡对应的rx_bytes累加得到该容器的rx_bytes。

将所有这些虚拟网卡对应的tx_bytes累加得到该容器的tx_bytes。

DockerStats计算Network IO数据的算法:

NETI = rx_bytes
NETO = tx_bytes

容器的监控方案

单台主机容器监控

1、 Docker Stats

单台主机上容器的监控实现最简单的方法就是使用命令Docker Stats,就可以显示所有容器的资源使用情况。
1(26).png

这样就可以查看每个容器的CPU利用率、内存的使用量以及可用内存总量。请注意,如果你没有限制容器内存,那么该命令将显示您的主机的内存总量。但它并不意味着你的每个容器都能访问那么多的内存。另外,还可以看到容器通过网络发送和接收的数据总量

虽然可以很直观地看到每个容器的资源使用情况,但是显示的只是一个当前值,并不能看到变化趋势。

2、Google的cAdvisor是另一个知名的开源容器监控工具:
2(20).png

只需在宿主机上部署cAdvisor容器,用户就可通过Web界面或REST服务访问当前节点和容器的性能数据(CPU、内存、网络、磁盘、文件系统等等),非常详细。

它的运行方式也有多种:

a、直接下载命令运行

下载地址:https://github.com/google/cadvisor/releases/latest

格式: nohup /root/cadvisor -port=10000&>>/var/log/kubernetes/cadvisor.log &

访问: http://ip:10000/
3(22).png

b、以容器方式运行
docker pullindex.alauda.cn/googlelib/cadvisor

运行:
docker run -d --volume=/:/rootfs:ro--volume=/var/run:/var/run:rw –volume=/sys:/sys:ro       --volume=/var/lib/docker/:/var/lib/docker:ro--publish=8080:8080  --name=cadvisor                      index.alauda.cn/googlelib/cadvisor:latest

c、kubelet选项

在启动kubelete时候,启动cAdvisor,cAdvisor当前都是只支持http接口方式,被监控的容器应用必须提供http接口,所以能力较弱。在Kubernetes的新版本中已经集成了cAdvisor,所以在Kubernetes架构下,不需要单独再去安装cAdvisor,可以直接使用节点的IP加默认端口4194就可以直接访问cAdvisor的监控面板。UI界面如下:
4(16).png

因为cAdvisor默认是将数据缓存在内存中,在显示界面上只能显示1分钟左右的趋势,所以历史的数据还是不能看到,但它也提供不同的持久化存储后端,比如InfluxDB等,同时也可以根据业务的需求,只利用cAdvisor提供的API接口,定时去获取数据存储到数据库中,然后定制自己的界面。

如需要通过cAdvisor查看某台主机上某个容器的性能数据只需要调用:
http://<host_ip>:4194/v1.3/subcontainers/docker/<container_id>

cAdvisor的API接口返回的数据结构如下:
微信图片_20170817152955.png

可以根据这些数据分别计算出CPU、内存、网络等资源的使用或者占用情况。

Kubernetes上的监控

容器的监控

在Kubernetes监控生态中,一般是如下的搭配使用:
6(13).png

1、cAdvisor + InfluxDB + Grafana:

Cadvisor:将数据,写入InfluxDB

InfluxDB :时序数据库,提供数据的存储,存储在指定的目录下

Grafana :提供了WEB控制台,自定义查询指标,从InfluxDB查询数据,并展示。
7(10).png

cAdivsor虽然能采集到监控数据,也有很好的界面展示,但是并不能显示跨主机的监控数据,当主机多的情况,需要有一种集中式的管理方法将数据进行汇总展示,最经典的方案就是cAdvisor + InfluxDB + Grafana,可以在每台主机上运行一个cAdvisor容器负责数据采集,再将采集后的数据都存到时序型数据库InfluxDB中,再通过图形展示工具Grafana定制展示面板。

在上面的安装步骤中,先是启动InfluxDB容器,然后进行到容器内部配置一个数据库给cAdvisor专用,然后再启动cAdvisor容器,容器启动的时候指定把数据存储到InfluxDB中,最后启动Grafana容器,在展示页面里配置Grafana的数据源为InfluxDB,再定制要展示的数据,一个简单的跨多主机的监控系统就构建成功了。

2、Kubernetes——Heapster + InfluxDB + Grafana:

Heapster:在Kubernetes集群中获取Metrics和事件数据,写入InfluxDB,Heapster收集的数据比cAdvisor多,却全,而且存储在InfluxDB的也少。

InfluxDB:时序数据库,提供数据的存储,存储在指定的目录下。

Grafana:提供了WEB控制台,自定义查询指标,从InfluxDB查询数据,并展示。
8(7).png

Heapster是一个收集者,将每个Node上的cAdvisor的数据进行汇总,然后导到InfluxDB。Heapster的前提是使用cAdvisor采集每个Node上主机和容器资源的使用情况,再将所有Node上的数据进行聚合,这样不仅可以看到Kubernetes集群的资源情况,还可以分别查看每个node/namespace及每个node/namespace下Pod的资源情况。这样就可以从Cluster、Node、Pod的各个层面提供详细的资源使用情况。

Kubernetes中主机监控方案

Prometheus

Prometheus是个集DB、Graph、Statistics、Alert 于一体的监控工具,安装也非常简单,下载包后做些参数的配置,比如监控的对象就可以运行了,默认通过9090端口访问。

1、部署node-exporter容器

node-exporter要在集群的每台主机上部署,使用主机网络,端口是9100 如果有多个Kubernetes集群,则要在多个集群上部署,部署node-exporter的命令如下:
#kubectl create -f node-exporter-deamonset.yaml

9(6).png

获取Metrics数据http://ip:9100/metrics
9(6).png

返回的数据结构不是Json格式,如果要使用该接口返回的数据,可以通过正则匹配,匹配出需要的数据,然后在保存到数据库中。

2、部署Prometheus和Grafana

Prometheus通过配置文件发现新的节点,文件路径是/sd/*.json,可以通过修改已有的配置文件,添加新的节点纳入监控,命令如下:
#kubectl create -f prometheus-file-sd.yaml


3、查看Prometheus监控的节点

Prometheus的访问地址是:http://192.168.xxx.xxx:31330,通过网页查看监控的节点Status --> Targets
10(6).png

11(4).png

4、 另外可以配置Grafana展示Prometheus输出的监控数据,配置仪表盘等。

Grafana访问地址是:http://192.168.xxx.xxx:31331,账号:admin 密码:admin。

:系统预置了几个常用监控仪表盘配置,更多的配置可以到官方网站下载。

监控工具的对比

以上从几个典型的架构上介绍了一些监控,但都不是最优实践。需要根据生产环境的特点结合每个监控产品的优势来达到监控的目的。比如Grafana的图表展示能力强,但是没有告警的功能,那么可以结合Prometheus在数据处理能力改善数据分析的展示。下面列了一些监控产品,但并不是严格按表格进行分类,比如Prometheus和Zabbix都有采集,展示,告警的功能。都可以了解一下,各取所长。
12(5).png

今天分享的内容主要就是这些,有不懂的地方或者有讲错的地方欢迎大家提出,谢谢大家。

Q&A

Q:容器监控和主机监控为何不能用同一套方案,比如Prometheus?

A:可以,主要考虑到Prometheus的组件比较多,它将DB、Graph、Statistic、Alert都集于一体,但是它的扩展性不好,内存占用率大,在SSD盘下IO占用比较高,同时可能会有大量数据堆积内存,维护成本比较大,但是也可以避免,其实还是要看具体的业务场景和需求,如果是针对大规模的主机和容器监控,并且对DB、Graph、Statistic、Alert的要求都比较高,那么Prometheus肯定是比较好的选择,另外还可以使用cAdvisor + Prometheus + Grafana的组合方案,将这几个工具的有点结合起来使用。
Q:有没有能集成邮件或短信告警工具的呢?

A:比如Prometheus和Zabbix都有采集,展示,告警的功能。
Q:Prometheus的数据存储在哪儿,用的文件系统是什么?

A:Prometheus本身是用的LevelDB数据库,数据存储分两部分:内存和本地磁盘中。
Q:kubelet和cAdvisor 整合后,监控如果出问题岂不是会影响服务稳定性?这个如何解决?

A:在Kubernetes的新版本中已经集成了cAdvisor,cAdvisor作为一个daemon跑在Kubernetes上面,即使cAdvisor出现问题,对Kubernetes并没有影响,而且Kubernetes本身也有一套管理机制。
Q:想问一下对于Pod的生命周期的监控有没有好的解决方案,想监控一些pod不明原因频繁删除和新建?
A:cAdvisor可以对Pod进行监控,如果想查原因,可以对日志进行监控和分析。

Q6:Grafana 4.0以上也支持告警了,请问Kubernetes告警方案有哪些推荐?

A:可以使用Prometheus、Icinga、Zabbix的告警功能。
Q:cAdvisor的采集粒度是多长时间?当需要采集秒级的性能数据时cAdvisor是否能满足要求?

A:cAdvisor采集了最近接近两分钟内的8组数据, 可以满足,这里主要是要考虑下存储问题,因为到采集到秒级别后,数据会很大。
Q:容器中使用像JVM这种都会怎么来进行监控呢?

A:ELK stack应该适合这种场景,另外Datadog也是SaaS监测工具,Datadog比较灵活,需要植入自己的代码,可能没有前者用起来简单。
Q:对于群集环境,能不能简单比较一下各数据采集软件的好坏?或者分享一下用过的工具和坑。

A:这几个采集工具不好说哪个好那个坏,还是要看具体应用场景和需求,适合自己的才是最好的(嘿嘿)。例如:功能全的工具可能会很臃肿,占用资源也多,而且并不一定使用所有场景,功能少的扩展性可能很好。
Q:容器监控应该是为了容器能更好的运行。那么当容器出现一些异常情况,比如IO占用过高,带宽占用很多时,该怎么处理呢。

A:这是监控系统中自动化处理的那部分,针对容器出现的异常到底是要采取什么自动化操作还是要看具体情况,一般如果容器异常挂掉,可能会选择自动拉起,但如果像IO占用过高这中问题,因为导致的原因太多了,可能是主机的问题,也可能是程序本身的问题,所以还是需要人为去排查才行。
Q:cAdvisor 是定时采集数据,但是有时候时间点采集不到数据,是为什么?

A:可以看下cAdvisor有没有异常重启过,然后可以手动区主机的文件下查看数据,然后跟cAdvisor取到的数据进行比较,有可能是是在采集数据的时候有问题。
Q:数据采集中,您提到主动输出到文件,那么涉及到日志文件的读取采集,那这块怎么做呢?

A:如果是传统的日志汇总收集有开源的软件ELK和Facebook开源的Scribe,容器的日志管理可以参考Fluentd。
Q:这些监控方案中从资源占用数据准确性角度来看,哪个更好用?

A:准确性都不会差,他们采集的源数据都是一样的,在资源占用这块,cAdvisor是占用资源最少的,Prometheus占用资源比较多。
Q16:有一处我不是很确定是否讲错了,我实践发现即便为容器设置了MEM、CPU限制,所监控到的依然是主机的总MEM和CPU。

A:我测试了,在启动容器的时候设置MEM和CPU限制后,通过docker stats命令监控的是设置的值。
问答1.png
Q:如果要监控某个容器内正在跑的进程,你们现在的方案是如何的,能介绍下吗?

A:可以参考Kubernetes中Pod健康部分:https://kubernetes.io/docs/tas ... obes/,利用探针的方式监控进程。
以上内容根据2017年07月27日晚微信群分享内容整理。分享人李强,有容云后端开发工程师。有着多年的服务器、网络、容器、虚拟化等云计算技术相关工作经验,现主要负责Kubernetes安装、集群、监控等相关的后台研发工作。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

0 个评论

要回复文章请先登录注册