Docker 容器监控原理及 cAdvisor的安装与使用说明

生产环境中监控容器的运行状况十分重要,通过监控我们可以随时掌握容器的运行状态,做到线上隐患和问题早发现,早解决。

所以今天我就和你分享关于容器监控的知识(原理及工具 cAdvisor)。

虽然传统的物理机和虚拟机监控已经有了比较成熟的监控方案,但是容器的监控面临着更大的挑战,因为容器的行为和本质与传统的虚拟机是不一样的,总的来说,容器具有以下特性:

容器是短期存活的,并且可以动态调度

容器的本质是进程,而不是一个完整操作系统

由于容器非常轻量,容器的创建和销毁也会比传统虚拟机更加频繁

Docker 容器的监控方案有很多,除了 Docker 自带的docker stats命令,还有很多开源的解决方案,例如 sysdig、cAdvisor、Prometheus 等,都是非常优秀的监控工具。

下面我们首先来看下,不借助任何外部工具,如何用 Docker 自带的docker stats命令实现容器的监控。

使用 docker stats 命令

使用 Docker 自带的docker stats命令可以很方便地看到主机上所有容器的 CPU、内存、网络 IO、磁盘 IO、PID 等资源的使用情况。下面我们可以具体操作看看。

首先在主机上使用以下命令启动一个资源限制为 1 核 2G 的 nginx 容器:

$ docker run --cpus=1 -m=2g --name=nginx -d nginx

容器启动后,可以使用docker stats命令查看容器的资源使用状态:

$ docker stats nginx

通过docker stats命令可以看到容器的运行状态如下:

CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS

f742a467b6d8 0.00% 1.387 MiB / 2 GiB 0.07% 656 B / 656 B 0 B / 9.22 kB 2

从容器的运行状态可以看出,docker stats命令确实可以获取并显示 Docker 容器运行状态。但是它的缺点也很明显,因为它只能获取本机数据,无法查看历史监控数据,没有可视化展示面板。

因此,生产环境中我们通常使用另一种容器监控解决方案 cAdvisor。

cAdvisor

cAdvisor 是谷歌开源的一款通用的容器监控解决方案。cAdvisor 不仅可以采集机器上所有运行的容器信息,还提供了基础的查询界面和 HTTP 接口,更方便与外部系统结合。所以,cAdvisor很快成了容器指标监控最常用组件,并且 Kubernetes 也集成了 cAdvisor 作为容器监控指标的默认工具。

cAdvisor 的安装与使用

下面我们以 cAdvisor 0.37.0 版本为例,演示一下 cAdvisor 的安装与使用。

cAdvisor 官方提供了 Docker 镜像,我们只需要拉取镜像并且启动镜像即可。

由于 cAdvisor 镜像存放在谷歌的 gcr.io 镜像仓库中,国内无法访问到。这里我把打好的镜像放在了 Docker Hub。你可以使用 docker pull lagoudocker/cadvisor:v0.37.0 命令从 Docker Hub 拉取。

首先使用以下命令启动 cAdvisor:

$ docker run \
 --volume=/:/rootfs:ro \
 --volume=/var/run:/var/run:ro \
 --volume=/sys:/sys:ro \
 --volume=/var/lib/docker/:/var/lib/docker:ro \
 --volume=/dev/disk/:/dev/disk:ro \
 --publish=8080:8080 \
 --detach=true \
 --name=cadvisor \
 --privileged \
 --device=/dev/kmsg \
 lagoudocker/cadvisor:v0.37.0

此时,cAdvisor 已经成功启动,我们可以通过访问 http://localhost:8080 访问到 cAdvisor 的 Web 界面。

cAdvisor 不仅可以监控容器的资源使用情况,还可以监控主机的资源使用情况。下面我们就先看下它是如何查看主机资源使用情况的。

使用 cAdvisor 查看主机监控

访问 http://localhost:8080/containers/ 地址,在首页可以看到主机的资源使用情况,包含 CPU、内存、文件系统、网络等资源,如下图所示。

使用 cAdvisor 查看容器监控

如果你想要查看主机上运行的容器资源使用情况,可以访问 http://localhost:8080/docker/,这个页面会列出 Docker 的基本信息和运行的容器情况,如下图所示。

在上图中的 Subcontainers 下会列出当前主机上运行的所有容器,点击其中一个容器即可查看该容器的详细运行状态,如下图所示。

总体来说,使用 cAdvisor 监控容器具有以下特点:

可以同时采集物理机和容器的状态

可以展示监控历史数据

了解 Docker 的监控工具,你是否想问,这些监控数据是怎么来的呢?下面我就带你了解一下容器监控的原理。

监控原理

我们知道 Docker 是基于 Namespace、Cgroups 和联合文件系统实现的。其中 Cgroups 不仅可以用于容器资源的限制,还可以提供容器的资源使用率。无论何种监控方案的实现,底层数据都来源于 Cgroups。

Cgroups 的工作目录为/sys/fs/cgroup,/sys/fs/cgroup目录下包含了 Cgroups 的所有内容。Cgroups包含很多子系统,可以用来对不同的资源进行限制。例如对CPU、内存、PID、磁盘 IO等资源进行限制和监控。

为了更详细的了解 Cgroups 的子系统,我们通过 ls -l 命令查看/sys/fs/cgroup文件夹,可以看到很多目录:

$ sudo ls -l /sys/fs/cgroup/
total 0

dr-xr-xr-x 5 root root 0 Jul 9 19:32 blkio
lrwxrwxrwx 1 root root 11 Jul 9 19:32 cpu -> cpu,cpuacct
dr-xr-xr-x 5 root root 0 Jul 9 19:32 cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jul 9 19:32 cpuacct -> cpu,cpuacct
dr-xr-xr-x 3 root root 0 Jul 9 19:32 cpuset
dr-xr-xr-x 5 root root 0 Jul 9 19:32 devices
dr-xr-xr-x 3 root root 0 Jul 9 19:32 freezer
dr-xr-xr-x 3 root root 0 Jul 9 19:32 hugetlb
dr-xr-xr-x 5 root root 0 Jul 9 19:32 memory
lrwxrwxrwx 1 root root 16 Jul 9 19:32 net_cls -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Jul 9 19:32 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jul 9 19:32 net_prio -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Jul 9 19:32 perf_event
dr-xr-xr-x 5 root root 0 Jul 9 19:32 pids
dr-xr-xr-x 5 root root 0 Jul 9 19:32 systemd

这些目录代表了 Cgroups 的子系统,Docker 会在每一个 Cgroups 子系统下创建 docker 文件夹。这里如果你对 Cgroups 子系统不了解的话,不要着急,这里你只需要明白容器监控数据来源于 Cgroups 即可。

监控系统是如何获取容器的内存限制的?

下面我们以 memory 子系统(memory 子系统是Cgroups 众多子系统的一个,主要用来限制内存使用)为例,讲解一下监控组件是如何获取到容器的资源限制和使用状态的(即容器的内存限制)。

我们首先在主机上使用以下命令启动一个资源限制为 1 核 2G 的 nginx 容器:

$ docker run --name=nginx --cpus=1 -m=2g --name=nginx -d nginx

## 这里输出的是容器 ID

51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1

注意:如果你已经创建过名称为 nginx 的容器,请先使用 docker rm -f nginx 命令删除已经存在的 nginx 容器。

容器启动后,我们通过命令行的输出可以得到容器的 ID,同时 Docker 会在/sys/fs/cgroup/memory/docker目录下以容器 ID 为名称创建对应的文件夹。

下面我们查看一下/sys/fs/cgroup/memory/docker目录下的文件:

$ sudo ls -l /sys/fs/cgroup/memory/docker
total 0

drwxr-xr-x 2 root root 0 Sep 2 15:12 51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1
-rw-r--r-- 1 root root 0 Sep 2 14:57 cgroup.clone_children
--w--w--w- 1 root root 0 Sep 2 14:57 cgroup.event_control
-rw-r--r-- 1 root root 0 Sep 2 14:57 cgroup.procs
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.failcnt
--w------- 1 root root 0 Sep 2 14:57 memory.force_empty
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.numa_stat
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.oom_control
---------- 1 root root 0 Sep 2 14:57 memory.pressure_level
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.stat
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.swappiness
-r--r--r-- 1 root root 0 Sep 2 14:57 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 14:57 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Sep 2 14:57 notify_on_release
-rw-r--r-- 1 root root 0 Sep 2 14:57 tasks

可以看到 Docker 已经创建了以容器 ID 为名称的目录,我们再使用 ls 命令查看一下该目录的内容:

$ sudo ls -l /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1

total 0
-rw-r--r-- 1 root root 0 Sep 2 15:21 cgroup.clone_children
--w--w--w- 1 root root 0 Sep 2 15:13 cgroup.event_control
-rw-r--r-- 1 root root 0 Sep 2 15:12 cgroup.procs
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.failcnt
--w------- 1 root root 0 Sep 2 15:21 memory.force_empty
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 Sep 2 15:12 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.numa_stat
-rw-r--r-- 1 root root 0 Sep 2 15:13 memory.oom_control
---------- 1 root root 0 Sep 2 15:21 memory.pressure_level
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Sep 2 15:21 memory.stat
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.swappiness
-r--r--r-- 1 root root 0 Sep 2 15:12 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Sep 2 15:21 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Sep 2 15:21 notify_on_release
-rw-r--r-- 1 root root 0 Sep 2 15:21 tasks

由上可以看到,容器 ID 的目录下有很多文件,其中 memory.limit_in_bytes 文件代表该容器内存限制大小,单位为 byte,我们使用 cat 命令(cat 命令可以查看文件内容)查看一下文件内容:

$ sudo cat /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1/memory.limit_in_bytes

2147483648

这里可以看到memory.limit_in_bytes 的值为2147483648,转换单位后正好为 2G,符合我们启动容器时的内存限制 2G。

通过 memory 子系统的例子,我们可以知道监控组件通过读取 memory.limit_in_bytes 文件即可获取到容器内存的限制值。了解完容器的内存限制我们来了解一下容器的内存使用情况。

$ sudo /sys/fs/cgroup/memory/docker/51041a74070e9260e82876974762b8c61c5ed0a51832d74fba6711175f89ede1/memory.usage_in_bytes

4259840

可以看到当前内存的使用大小为 4259840 byte,约为 4 M。了解了内存的监控。

下面我们来了解下网络的监控数据来源

网络的监控数据来源是从 /proc/{PID}/net/dev 目录下读取的,其中 PID 为容器在主机上的进程 ID。下面我们首先使用 docker inspect 命令查看一下上面启动的 nginx 容器的 PID,命令如下:

$ docker inspect nginx |grep Pid

   "Pid": 27348,

   "PidMode": "",

   "PidsLimit": 0,

可以看到容器的 PID 为 27348,使用 cat 命令查看一下 /proc/27348/net/dev 的内容

$ sudo cat /proc/27348/net/dev
Inter-| Receive            | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed

 lo:  0  0 0 0 0  0   0   0  0  0 0 0 0  0  0   0

 eth0:  0  0 0 0 0  0   0   0  0  0 0 0 0  0  0   0

/proc/27348/net/dev 文件记录了该容器里每一个网卡的流量接收和发送情况,以及错误数、丢包数等信息。可见容器的网络监控数据都是定时从这里读取并展示的。

总结一下,容器的监控原理其实就是定时读取 Linux 主机上相关的文件并展示给用户。

结语

k8s后面使用metrics serve,cAdvisor 是提供底层数据的,metrics-server 底层数据来源是 cAdvisor

cAdvisor 是提供监控数据的,Prometheus 是负责采集的数据的,这两个作用是不一样的,生产集群中一般都是 cAdvisor 配合 Prometheus 一起使用。

以上这篇Docker 容器监控原理及 cAdvisor的安装与使用说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Docker 配置阿里云容器服务操作

    配置阿里云Docker容器服务 登录 阿里云镜像服务控制台 首先要有一个自己的阿里云账号 1.点击名称空间,建议用自己名字/公司名字 比如叫 aliyun-stg 创建完成名字空间 2.点击镜像仓库,创建镜像,填写细信息 仓库可以使用Redis mysql 等名字进行管理 创建仓库 3.观察创建好后的信息 registry.cn-beijing.aliyuncs.com/aliyun-stg/flask 阿里docker域名 registry.cn-beijing.aliyuncs.com 我自

  • 详解docker部署Jenkins新手使用教程

    本文通过docker部署Jenkins+Maven+SVN+Tomcat,在基础镜像Jenkins上安装Maven及自带的OpenJDK形成新的镜像,然后通过SVN将项目checkout下来,由Jenkins自带的插件或脚本将Maven生成的war包发送到指定的Tomcat的WebApps目录下,最终启动Tomcat完成自动化部署. 通过docker命令:sudo docker run –d -p 9898:8080 -p 50000:50000 -v /alidata/projects/jen

  • Docker数据卷容器创建及使用方法解析

    数据卷容器是一个专门用来挂载数据卷的容器,该容器主要是供其他容器引用和使用.所谓的数据卷容器,实际上就是一个普通的容器,举例如下: 创建数据卷容器 使用如下方式创建数据卷容器: docker run -itd -v /usr/share/nginx/html/ --name mydata ubuntu 命令执行效果如下图: 引用容器 使用如下命令引用数据卷容器: docker run -itd --volumes-from mydata -p 80:80 --name nginx1 nginx

  • Docker容器网络端口配置过程详解

    暴露网络端口 实际上,Docker中涉及暴露网络端口的参数有两个,分别是-p和-P.下面分别来介绍. -P 使用-P,Docker会在宿主机上随机为应用分配一个未被使用的端口,并将其映射到容器开放的端口,以Nginx 为例,如下: 可以看到,Docker为应用分配了一个随机端口32768,使用该端口即可访问容器中的 nginx(http://lcalhost:32768). -p -p参数则有几种不同的用法: hostPort:containerPort 这种用法是将宿主机端口和容器端口绑定起来

  • Docker 容器监控原理及 cAdvisor的安装与使用说明

    生产环境中监控容器的运行状况十分重要,通过监控我们可以随时掌握容器的运行状态,做到线上隐患和问题早发现,早解决. 所以今天我就和你分享关于容器监控的知识(原理及工具 cAdvisor). 虽然传统的物理机和虚拟机监控已经有了比较成熟的监控方案,但是容器的监控面临着更大的挑战,因为容器的行为和本质与传统的虚拟机是不一样的,总的来说,容器具有以下特性: 容器是短期存活的,并且可以动态调度 容器的本质是进程,而不是一个完整操作系统 由于容器非常轻量,容器的创建和销毁也会比传统虚拟机更加频繁 Docke

  • docker容器的原理分析

    01 容器的本质是什么? 今天的重点问题是讲述清楚什么是容器. 要理解容器的概念,首先我们需要知道什么是进程?当我们在Linux操作系统执行一个程序,这个程序可能是一个二进制文件,它被调用的时候,变成了计算机内存中的数据.寄存器中的值.堆栈中的指令.以及各种设备状态信息的一个集合.像这样的一个计算机执行环境的综合,我们称之为进程. 容器,就是为这个进程提供一个"边界",理解成白话,就是把这个进程"包"起来,它本质上是通过约束和修改进程的一些动态表现实现的这个&quo

  • Docker容器监控及日志管理实现过程解析

    当Docker部署规模变大后,需要对容器进行监控,一般Docker自带几个监控子命令ps.top和stats,然后是现在流行的开源监控工具Prometheus Docker自带的监控子命令ps docker ps ,列出容器,方便查看当前的运行的容器,以下是命令语法与参数 语法 docker ps [OPTIONS] OPTIONS说明: -a :显示所有的容器,包括未运行的. -f :根据条件过滤显示的内容. --format :指定返回值的模板文件. -l :显示最近创建的容器. -n :列

  • 使用Grafana 展示Docker容器的监控图表并设置邮件报警规则(图解)

    一.Docker 容器监控报警方式 接着上篇文章的记录,看到grafana的版本已经更新到4.2了,并且在4.0以后的版本中,加入了Alert Notifications 功能,这样在对容器 监控完,可以加入报警规则.根据官网介绍,报警方式也有很多种,常见的Email.Slack即时通讯.webhook等. 本篇记录的是邮件的报警设置.环境和上篇基本一致,都是在Docker 平台测试环境下,另外本篇使用的grafana容器的版本是用的 dockerhub上最新版本,该版本为grafana/gra

  • 在docker容器中安装vi命令的简单操作

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim,可是当你敲apt-get install vim命令时,提示: Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package vim 这时候需要敲: apt-get update 这

  • Docker容器修改配置文件的实现

    一.进入容器 docker run [option] 镜像名 [向启动容器中传入的命令] 常用可选参数说明: -i 表示以"交互模式"运行容器 -t 表示容器启动后会进入其命令行.加入这两个参数后,容器创建就能登录进去.即 分配一个伪终端. --name 为创建的容器命名 -v 表示目录映射关系(前者是宿主机目录,后者是映射到宿主机上的目录,即 宿主机目录:容器中目录),可以使 用多个-v 做多个目录或文件映射.注意:最好做目录映射,在宿主机上做修改,然后 共享到容器上. -d 在ru

  • 解决Docker容器下不能使用vim命令的问题

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,如图所示: 这时候就需要安装vim. 可是当你敲apt-get install vim命令时,提示: Reading package lists... Done        Building dependency tree               Reading state information... Done        E: Unable to locate pa

  • Docker 容器内存监控原理及应用

    Docker 容器内存监控 linux内存监控 要明白docker容器内存是如何计算的,首先要明白linux中内存的相关概念. 使用free命令可以查看当前内存使用情况. [root@localhost ~]$ free total used free shared buffers cached Mem: 264420684 213853512 50567172 71822688 2095364 175733516 -/+ buffers/cache: 36024632 228396052 Sw

  • 基于spring-boot和docker-java实现对docker容器的动态管理和监控功能[附完整源码下载]

    docker简介 Docker 是一个开源的应用容器引擎,和传统的虚拟机技术相比,Docker 容器性能开销极低,因此也广受开发者喜爱.随着基于docker的开发者越来越多,docker的镜像也原来越丰富,未来各种企业级的完整解决方案都可以直接通过下载镜像拿来即用.因此docker变得越来越重要. 本文目的 本文通过一个项目实例来介绍如果通过docker对外接口来实现对docker容器的管理和监控. 应用场景: 对服务器资源池通过docker进行统一管理,按需分配资源和创建容器,达到资源最大化利

  • golang实现对docker容器心跳监控功能

    自己写的go程序放到线上本来编译成二进制扔上去就行啦,但是怀着一颗docker的心,最终还是将它放到docker容器中运行起来了,运行起来也ok,一个最小容器64M,统一管理起来也方便,但是毕竟是个线上长驻内存的服务程序,万一跑挂了怎么办,如何才能监控它,直接上go代码,网上代码,略微做了下注释,但实测过,真实有效: package main import ( "encoding/json" "errors" "flag" "fmt&q

随机推荐