过去的一年中,关于 Docker 的话题从未断过,而如今,从尝试 Docker 到最终决定使用 Docker 的转化率依然在逐步升高,关于 Docker 的讨论更是有增无减。另一方面,大家的注意力也渐渐从 “Docker 是什么”转移到“实践 Docker”与“监控 Docker”上。
本文转自刘斌博文「如何选择 Docker 监控方案 」,文中刘斌从技术的角度深入解释了 Docker 监控的数据采集原理,介绍了现有开源的监控方案,以及能够对 Docker 进行监控功能的主流 SaaS 服务工具。
斌哥是谁?
刘斌,拥有 10 多年编程经验,曾参与翻译过「第一本 Docker 书」、「GitHub 入门与实践」、「Web 应用安全权威指南」等多本技术书籍,主讲过「Docker入门与实践 」课程的 Cloud Insight 后台工程师。
为什么监控,监控什么内容?
作为一名工程师,我们要对自己系统的运行状态了如指掌,有问题及时发现,而不是让用户先发现系统不能使用,打电话找客服,再反映到开发。这个过程很长,而且对工程师来说,是一件比较没面子的事情。
当领导问我们这个月的 MySQL 并发什么情况?slowsql 处于什么水平,平均响应时间超过 200ms 的占比有百分之多少的时候,回答不出来这个问题很尴尬。尽管你工作很辛苦,但是却没有拿得出来的成果。不能因为暂时没出问题就掉以轻心,换位想想,站在领导的角度,领导什么都不干,你提案,他签字,出了谁背锅?
监控目的
- 减少宕机时间
- 扩展和性能管理
- 资源计划
- 识别异常事件
- 故障排除、分析
为什么需要监控我们的服务?其中有一些显而易见的原因,比如需要监控工具来提醒服务故障,比如通过监控服务的负载来决定扩容或缩容。如果机器普遍负载不高,则可以考虑缩减一下机器规模,如果数据库连接经常维持在一个高位水平,则可以考虑一下是否可以进行拆库处理,优化一下架构。
Docker监控面临的挑战
-
Docker特点
- 像host但不是host
- 量大
- 生命周期短 监控盲点(断层)
- 微服务 集群
- 全方位
* Host(VM) + Services + Containers + Apps
容器为我们的开发和运维带来了更多的方向和可能性,我们也需要一种现代的监控方案来应对这种变化。
随着不可变基础设施概念的普及,云原生应用的兴起,云计算组件已经越来越像搭建玩具的积木块。很多基础设施生命周期变短,不光容器如此,云主机、VM也是。
在云计算出现之前,一台机器可能使用3、5年甚至更长都不需要重装,主机名也不会变,而现在,可能升级一个版本,就要重建一个云主机或重新启动一个容器。监控对象动态变化,而且非常频繁。即使全部实现自动化,也会在负载和复杂度方面带来不利影响。
监控还有助于进行内部统制,尤其是对安全比较敏感的行业,比如证券、银行等。比如服务器受到攻击时,我们需要分析事件,找到根本原因,识别类似攻击,发现未知的被攻击系统,甚至完成取证等工作。
集群的出现,使应用的拓扑结构也变得复杂,不同应用的指标和日志格式也不统一,再加上要考虑应对多租户的问题,这些都给监控带来了新挑战。
传统的监控内包括对主机、网络和应用的监控,但是Docker出现之后,容器这一层很容易被忽略,成为三不管地区,即监控的盲点。
有人说,容器不就是个普通的OS么?装个Zabbix的探针不就行了么?Docker host和Docker 容器都要装 Zabbix探针……其实问题很多。
除了容器内部看到的cpu内存情况不准之外,而且容器生命周期短,重启之后host名,ip地址都会变,所以最好在Docker host上安装Zabbix agent。
如果每个容器都像OS那样监控,则metric数量将会非常巨大,而且这些数据很可能几分钟之后就无效率了(容器已经停止)。容器生命周期短暂,一旦容器结束运行,之前收集的数据将不再有任何意义。
主要的解决方式就是以App或者Service为单位进行监控(通过Tag等方式)。
Docker 监控技术基础
- docker stats
- Remote API
- 伪文件系统
我们可以通过 docker stats 命令或者Remote API以及Linux的伪文件系统来获取容器的性能指标。
使用API的话需要注意一下,那就是不要给Docker daemon带来性能负担。如果你一台主机有200个容器,如果非常频繁的采集系统性能可能会大量占据CPU时间。
最好的方式应该就是使用伪文件系统。如果你只是想通过shell来采集性能数据,则 docker stats 可能是最简单的方式了。
docker stats 命令
该命令默认以流式方式输出,如果想打印出最新的数据并立即退出,可以使用 no-stream=true 参数。
- 伪文件系统
- CPU、内存、磁盘
- 网络
文件位置大概在(跟系统有关,这是 Systemd 的例子):
Docker各个版本对这三种方式的支持程度不同,取得metric的方式和详细程度也不同,其中网络metric是在1.6.1之后才能从伪文件系统得到。
Memory
内存的很多性能指标都来自于 memory.stat 文件:
前面的不带total的指标,表示的是该cgroup中的process所使用的、不包括子cgroup在内的内存量,而total开头的指标则包含了这些进程使用的包括子cgroup数据。这里我们看到的数据都是一样的,由于这里并没有子cgroup。
两个比较重要的指标:
- RSS: resident set size
进程的所有数据堆、栈和memory map等。rss可以进一步分类为active和inactive(activeanon and inactiveanon)。在内存不够需要swap一部分到磁盘的时候,会选择inactive 的rss进行swap 。
- cache memory
缓存到内存中的硬盘文件的大小。比如你读写文件的时候,或者使用mapped file的时候,这个内存都会增加。这类内存也可以再细分为active和inactive的cache,即activefile和inactivefile。如果系统需要更多内存,则inactive的cache会被优先重用。
CPU
- cpuacct.stat文件
- docker.cpu.system
- docker.cpu.user
但是比较遗憾,Docker 不会报告nice,idle和iowait等事件。
System也叫kernel时间,主要是系统调用所耗费的部分,而user则指自己程序的耗费CPU,如果User时间高,则需要好好检查下自己的程序是否有问题,可能需要进行优化。
Blkio
优先从CFQ(Completely Fair Queuing 完全公平的排队)拿数据,拿不到从这两个文件拿: · blkio.throttle.ioservicebytes,读写字节数 · blkio.throttle.io_serviced,读写次数
Throttle这个单纯可能有误导,实际这些都不是限制值,而是实际值。每个文件的第一个字段是 major:minor 这样格式的device ID。
网络数据
- iptables
- 伪文件系统
- 网络设备接口
- Virtual Ethernet
针网络的监控要精确到接口级别,即网卡级别。每个容器在host上都有一个对应的virtual Ethernet,我们可以从这个设备获得tx和rx信息。
不过找到容器在主机上对应的虚拟网卡比较麻烦。这时候可以在宿主机上通过 ip netns 命令从容器内部取得网络数据。
为了在容器所在网络命名空间中执行 ip netns 命令,我们首先需要找到这个容器进程的PID。
或者:
实际上Docker的实现也是从伪文件系统中读取网络metric的:
以上,是不是意犹未尽呢? 下一部分,斌哥将为大家介绍: 《Docker 监控方案的实现》
超好用的监控软件 Cloud Insight 不仅能监控 Docker,还能对 Nagios 进行更好的可视化哦~
阅读更多技术文章,请访问 OneAPM 官方博客。
本文转自 OneAPM 官方博客