互联网架构应用文章精选系统运维专家

解惑|你是否为容器监控操碎了心?

2017-07-11  本文已影响125人  优云数智

导读:容器对于物理机和虚拟机,单从监控上看就不是一个数量级的,但监控又是至关重要的,没有监控如同闭眼开车。

本次分享邀请数人云运维总监庞铮,本文将从以下几个方面聊聊容器监控的相关思考:

  1. 容器监控面临问题-容器设计及运营复杂性的挑战;
  2. 容器的三种监控收集指标;
  3. 容器性能监控能力把控及报警调查。

容器监控的问题

为什么要使用Docker

简介

容器对于物理机和虚拟机,单从监控上看就不是一个数量级的。但是监控又是至关重要的,如果没有监控,如同闭着眼开车。先看下传统监控解决的问题:

Markdown

而使用容器则在于资源层和应用层之间,应用监控和基础设施监控无法起作用,造成了监控系统的盲点。

容器的设计

容器最开始设计就是为了提供运行时的安全隔离,且没有虚拟化的资源开销。容器提供了一种孤立运行软件的方法,既不是进程也不是主机,而存在于两者之间。

Markdown

现在使用容器主要有两个重要原因:

如果软件是微服务架构,在 Kubernetes\Mesos 等容器平台上进行无停机的扩缩和升级等系统操作。

容器挑战:运营的巨大复杂性

可以将每个容器看成一个迷你的主机,但它与主机的操作并不是很相同。

Markdown

上图显示了15年的系统演进过程。

Markdown Markdown Markdown Markdown

Markdown

Markdown Markdown

监控的爆炸性增长

在没有容器以前,监控数量如:


Markdown

使用容器后公式:假设每个容器收集 50 个度量,再加上应用收集 50 个度量。

系统监控   (容器数量*(容器监控 应用监控))= 每个主机监控数量100         (4 *(50 50))= 500/主机监控项
Markdown

以主机为中心的监控体系

容器作为主机,以主机为中心将有两个问题无法解决:

简化监控体系

Markdown

如图采用分层监控架构,更符合现有监控体系。主机层和应用层保持不变使用传统的 Apm 和主机层监控,而容器层使用新的监控模式。

Markdown

如何监控容器

容器类似主机

它有一个迷你主机该有的一切,包含常驻程序、CPU、MEM、IO 和网络资源。但容器不能报告和主机完全相同的 Cgroup 指标。

容器监控资源

cpu

容器 CPU 会给出以下数据而不会有和主机一样的全数据,如 Idle\Iowait\Irq。

Markdown

内存

Markdown

使用内存区别

属于进程的数据,如 Stacks、Heaps 等。可以被进一步分解为

必要时,非活动内存可以被交换到磁盘

缓存存储器存储当前保存在内存中的磁盘数据。可以进一步分解为

必要时,首先回收非活动内存

io

Markdown

容器对于每个块设别汇报4个指标,这种情况下,在主机监控层面跟踪主机队列和服务时间是个好办法,如果同块的队列和服务时间增长,那么因同块 IO 是共享的,所以容器 IO 也受到影响。

网络

和普通主机一样,分为接收和发送的多个度量数据。

Markdown

如何收集容器指标

容器有三种指标收集方法,但标准并不一样:

Sysfs 中的 Pseudo-files

收集位置

CONTAINER_ID=$(docker run [OPTIONS] IMAGE [COMMAND] [ARG...] )

CPU 获取方法

cd /sys/fs/cgroupu/docker/&& ll

-rw-r--r-- 1 root root 0 5月  31 10:17 cgroup.clone_children
  --w--w--w- 1 root root 0 5月  31 10:17 cgroup.event_control
  -rw-r--r-- 1 root root 0 5月  31 10:17 cgroup.procs
  -r--r--r-- 1 root root 0 5月  31 10:17 cpuacct.stat
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpuacct.usage
  -r--r--r-- 1 root root 0 5月  31 10:17 cpuacct.usage_percpu
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpu.cfs_period_us
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpu.cfs_quota_us
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpu.rt_period_us
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpu.rt_runtime_us
  -rw-r--r-- 1 root root 0 5月  31 10:17 cpu.shares
  -r--r--r-- 1 root root 0 5月  31 10:17 cpu.stat
  -rw-r--r-- 1 root root 0 5月  31 10:17 notify_on_release
  -rw-r--r-- 1 root root 0 5月  31 10:17 tasks
# cat $CONTAINER_ID/cpuacct.stat     user 46409 #进程占用  464.09s     system 22162 #系统调用占用 221.62s

CPU 每核使用量

# cat $CONTAINER_ID/cpuacct.usage_percpu         362316789800  #自启动以来占用,单位纳秒         360108180815
# cat $CONTAINER_ID/cpuacct.usage
    722473378982
$ cat /sys/fs/cgroup/cpu/docker/$CONTAINER_ID/cpu.stat
    nr_periods 565 # 已经执行间隔数
    nr_throttled 559 # 被组抑制的次数
    throttled_time 12119585961 # 总使用时间,单位纳秒(12.12s)

内存获取方法

ll /sys/fs/cgroup/memory/docker/$CONTAINER_ID/
  
  # 没有 total 标签,不包含于子cgroup组
  cache 2015232
  rss 15654912
  rss_huge 0
  mapped_file 131072
  swap 0
  pgpgin 22623
  pgpgout 18309
  pgfault 27855
  pgmajfault 7
  inactive_anon 12148736
  active_anon 3506176
  inactive_file 2011136
  active_file 4096
  unevictable 0
  hierarchical_memory_limit 9223372036854775807
  hierarchical_memsw_limit 9223372036854775807
  
  # 有 total 标签,包含于子cgroup组
  total_cache 2015232
  total_rss 15654912
  total_rss_huge 0
  total_mapped_file 131072
  total_swap 0
  total_pgpgin 22623
  total_pgpgout 18309
  total_pgfault 27855
  total_pgmajfault 7
  total_inactive_anon 12148736
  total_active_anon 3506176
  total_inactive_file 2011136
  total_active_file 4096
  total_unevictable 0

可以通过特定命令直接获取一些指标:

# 总物理内存占用 cached + rss ,单位为字节 
  $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.usage_in_bytes

  # 总物理内存+swap 占用 ,单位为字节 
  $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.memsw.usage_in_bytes

  # 内存使用次数限制
  $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.failcnt

  # cgroup 内存限制,单位为字节 
  $ cat /sys/fs/cgroup/memory/docker/$CONTAINER_ID/memory.limit_in_bytes
  注意如果最终返回的是一个很长的数值代表容器实例并没有限制,如果想增加限制
  $ docker run -m 500M IMAGE [COMMAND] [ARG...]

IO

ll /sys/fs/cgroup/blkio/docker/$CONTAINER_ID
  
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_merged
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_merged_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_queued
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_queued_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_service_bytes
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_service_bytes_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_serviced
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_serviced_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_service_time
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_service_time_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_wait_time
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.io_wait_time_recursive
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.leaf_weight
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.leaf_weight_device
  --w------- 1 root root 0 5月  31 10:17 blkio.reset_stats
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.sectors
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.sectors_recursive
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.io_service_bytes
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.io_serviced
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.read_bps_device
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.read_iops_device
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.write_bps_device
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.throttle.write_iops_device
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.time
  -r--r--r-- 1 root root 0 5月  31 10:17 blkio.time_recursive
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.weight
  -rw-r--r-- 1 root root 0 5月  31 10:17 blkio.weight_device
  -rw-r--r-- 1 root root 0 5月  31 10:17 cgroup.clone_children
  --w--w--w- 1 root root 0 5月  31 10:17 cgroup.event_control
  -rw-r--r-- 1 root root 0 5月  31 10:17 cgroup.procs
  -rw-r--r-- 1 root root 0 5月  31 10:17 notify_on_release
  -rw-r--r-- 1 root root 0 5月  31 10:17 tasks

根据系统不同可能会有更多的指标文件,然而大部分的文件返回值是零。这种情况下通常还有两个可以工作的文件。

8:0 Read 2080768
  8:0 Write 0
  8:0 Sync 0
  8:0 Async 2080768
  8:0 Total 2080768
  253:0 Read 2080768
  253:0 Write 0
  253:0 Sync 0
  253:0 Async 2080768
  253:0 Total 2080768
  Total 4161536
   8:0 Read 226
  8:0 Write 0
  8:0 Sync 0
  8:0 Async 226
  8:0 Total 226
  253:0 Read 226
  253:0 Write 0
  253:0 Sync 0
  253:0 Async 226
  253:0 Total 226
  Total 452

想查看设备之间的关系可以使用:

# lsblk
  NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
  sda               8:0    0   50G  0 disk
  ├─sda1            8:1    0  500M  0 part /boot
  ├─sda2            8:2    0 29.5G  0 part
  │ ├─centos-root 253:0    0 46.5G  0 lvm  /
  │ └─centos-swap 253:1    0    3G  0 lvm  [SWAP]
  └─sda3            8:3    0   20G  0 part
     └─centos-root 253:0    0 46.5G  0 lvm  /

网络

网络从 1.6.1版本以后才支持,和以上的路径有所不同,获取使用容器Pid获取,注意Host模式获取的是主机网络数据,所以 host 模式无法从容器数据统计网络数据。

$ CONTAINER_PID=`docker inspect -f '{{ .State.Pid }}' $CONTAINER_ID`
  $ cat /proc/$CONTAINER_PID/net/dev 
  
  Inter-|   Receive                                                |  Transmit
  face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  eth0:    9655      90    0    0    0     0          0         0    31435      78    0    0    0     0       0          0
  lo:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

使用 docker stats 会不断的接收监控指标,1.9.0 以后指标包含磁盘io

cpu 占用百分比,多个实例占用cpu会根据分配进行占用峰值,如果设定强制规约,那么cpu只能占设定的数值,比如20%

如果没有明确内存限制,则限制为主机内存限制。如果主机上还有其他使用内存进程,那么会在到达限制前耗尽内存。

1.9.0 版本后支持,显示总读写字节

显示总进/出流量字节

和 docker stats 命令一样,但是提供更多的细节。守护进程监听 unix:///var/run/docker.sock,只允许本地连接。使用 nc 调用方法:

echo "" | nc -U /var/run/docker.sock 例子 echo -ne "GET /containers/$CONTAINER_ID/stats HTTP/1.1\r\n\r\n" | sudo nc -U /var/run/docker.sock
Markdown

如何监控Docker的性能

监控都需要有什么能力

Markdown Markdown

报警和调查

内部网络流量变化作为最重要的指标来触发报警而不会引起报警洪水。因此聚合和分解服务级别流量可见性是至关重要的。此外,即使在测量交叉异常阀值前,报警系统也可以提醒网络流量变化。而其余的资源指标是用来调查排错的。

数人云容器监控实践

Markdown Markdown Markdown

参考

The Docker monitoring problem

datadog

Runtime metrics

QA

Q:有对Docker本身做什么监控么?

A:可以认为 Docker 监控是类主机监控,只不过是缩小版,基本上分为4部分:CPU、内存、磁盘、网络。

Q:使用的整套监控工具是哪些?容器CPU内存网络 如何监控?容器事件比如起停如何监控。

A:整套工具数人云使用的是Cadvisor + Prometheus + Grafana ,当然中间的组件是可以替换的,但基本上围绕着采集、存储计算、展现来做。采集也可以使用自己的,比如文章说的自己写代理去拿。容器的监控数据当然靠采集程序了。起停这个一般通过监控Docker的事件来实现,采集工具也能收。

Q:分享的监控图片,有数据的,是使用什么监控工具达成的?

A:这个分两种,一种是靠底层的绘图引擎,将数据从存储里读出来自己绘制,一种就是用类Grafana的程序。

Q:如果用Zabbix监控,是否需要定义容器的的历史数据保留时间和趋势数据存储周期,我设定的时历史数据保留7天,趋势数据14天,这样是否合理?

A:我认为Zabbix 是上一代监控体系,或者以主机为中心的监控体系,如果是容器监控,建议还是考虑时序类的监控体系,比如Influxdb\Prometheus等,Zabbix还可以沿用作为主机的,只是Docker单独分离出来,这样基础建设可以复用。

Q:建不建议通过Pod中放一个监控容器来监控应用容器,比如Zabbix客户端的监控容器在Pod中,如果这么做 优缺点哪些?

A:Pod应该是Kubernetes的概念,和容器其实关系不大,这个Kubernetes自己应该会提供数据,具体不是很清楚。但是Abbix还是建议保留在主机层面使用,除非大改,否则即使靠拆分数据库什么的解决,未来维护和性能也是运维大坑。

Q:Cadvisor Heapster 和 Prometheus 哪种好用一些,各自优缺点有哪些。

A: Heapster不熟悉, Prometheus很好,Google个人的开源项目,都是Google套路,唯独存储是个问题,这块还需要看他们未来如何处理,现在单机存储虽然性能上还可以,但是扩展能力比较差。

Q:监控工具推荐哪个?对于容器生命周期短,有何策略应对?如何实现快速监控策略?

A:监控工具推荐刚才已经说了,可以参考数人云的方案然后自己摸索出适合自己的。至于容器生命周期短的问题,这个不就是容器设计嘛,很正常,多起几个相同的服务顶上。

Q:容器的一大特点是IP或者ID信息变化频繁,这就会导致时间序列数据库存储的监控数据量增长和vm相比大上不少,这块有什么应对方案吗?尝试过固定ID的,但是效果不佳。

A:这块确实没有什么好办法,不过可以换个角度,可以将底层的实例抽象一个维度,比如起了1个服务10个容器,把容器编号0-9,对应挂掉的容器,新启动继承这个编号。从时序上用这个作为标记,就能看比较直观的显示了。此功能数人云Swan (欢迎Star&Fork)实现了,可以考虑。

Q:容器的安全如何做监控?

A:这个问题问的好,现在比较通用的监控基本上走的是两条路,一个是监控性能,一个是监控业务,安全层面监控,到现在我觉得还是要靠网络层来监控比较靠谱。

Q:Docker启动Kafka集群的问题,有没有控制内存方面的经验呢?

A:Kafka集群,性能监控的话,可以沿用原来的Kafka集群监控软件,当然如果想做数据汇聚,也可以使用开源软件将数据汇聚到一个数据存储,然后在汇聚出来。关于Docker内存的超出被杀问题,这个主要是看自身对于容器内存设置的容忍度问题,这里可以把容器当成一个机器,看到底给这个机器插多少内存合适。

Q:Promethues有没有做高可用?

A:如果存储高可用的话,可以考虑使用两台Prometheus同时抓,这样数据完全一样,也没啥压力。

分享人庞铮,数人云运维总监。15 年以上运维工作经验。就职过宏碁戏谷、第三波、SQUARE ENIX CO, LTD 等。2015年加入数人云,从事数人云平台运维管理,在容器技术及SRE实践方面有深入研究。

上一篇下一篇

猜你喜欢

热点阅读