从 Kubectl Top 说起, 谈谈 Kubernetes 是如何进行资源监控的?
一、前言
kubectl top 可以很方便地查看node、pod 的实时资源使用情况:如CPU、内存。这篇文章会介绍其数据链路和实现原理,同时借 kubectl top 阐述 k8s 中的监控体系,窥一斑而知全豹。最后会解释常见的一些问题:
kubectl top 为什么会报错?
kubectl top node 怎么计算,和节点上直接 top 有什么区别?
kubectl top pod 怎么计算,包含 pause 吗?
kubectl top pod 和exec 进入 pod 后看到的 top 不一样?
kubectl top pod 和 docker stats得到的值为什么不同?
以下命令的运行环境为:
k8s 1.8
k8s 1.13
二、使用
1.8以下:部署 heapter 1.8以上:部署 metric-server
kubectl top pod: 查看 pod 的使用情况
和 k8s中 的 request、limit 一致,CPU单位100m=0.1 内存单位1Mi=1024Ki pod 的内存值是其实际使用量,也是做 limit 限制时判断 oom 的依据。pod的使用量等于其所有业务容器的总和,不包括 pause 容器,值等于 cadvisr中的 container_memory_working_set_bytes
指标node 的值并不等于该 node 上所有 pod 值的总和,也不等于直接在机器上运行 top 或 free 看到的值
三、实现原理
3.1 数据链路
3.2 metric api
可以发现,heapster 使用的是 proxy 转发,而 metric-server 和普通 pod都是使用 api/xx 的资源接口,heapster采用的这种 proxy 方式是有问题的:
proxy 只是代理请求,一般用于问题排查,不够稳定,且版本不可控
heapster 的接口不能像 apiserver 一样有完整的鉴权以及 client 集成,两边都维护的话代价高,如 generic apiserver
pod 的监控数据是核心指标(HPA调度),应该和 pod 本身拥有同等地位,即 metric 应该作为一种资源存在,如 metrics.k8s.io 的形式,称之为 Metric Api
于是官方从 1.8 版本开始逐步废弃 heapster,并提出了上边 Metric api 的概念,而 metrics-server 就是这种概念下官方的一种实现,用于从 kubelet获取指标,替换掉之前的 heapster。
3.3 kube-aggregator
有了 metrics-server 组件,采集到了需要的数据,也暴露了接口,但走到这一步和 heapster 其实没有区别,最关键的一步就是如何将打到 apiserver的 /apis/metrics.k8s.io
请求转发给 metrics-server 组件?解决方案就是:kube-aggregator。kube-aggregator 是对 apiserver 的有力扩展,它允许 k8s 的开发人员编写一个自己的服务,并把这个服务注册到 k8s 的 api 里面,即扩展 API,metric-server 其实在 1.7版本就已经完成了,只是在等 kube-aggregator 的出现。kube-aggregator 是 apiserver 中的实现,有些 k8s 版本默认没开启,你可以加上这些配置来开启,他的核心功能是动态注册、发现汇总、安全代理。
如 metric-server 注册 pod 和 node 时:
3.4 监控体系
在提出 metric api 的概念时,官方也提出了新的监控体系,监控资源被分为了2种:
Core metrics(核心指标):从 Kubelet、cAdvisor 等获取度量数据,再由metrics-server 提供给 Dashboard、HPA 控制器等使用。
Custom Metrics(自定义指标):由 Prometheus Adapter 提供 API custom.metrics.k8s.io,由此可支持任意Prometheus采集到的指标。
3.5 kubelet
Kubelet Summary metrics: 127.0.0.1:10255/metrics,暴露 node、pod 汇总数据
Cadvisor metrics: 127.0.0.1:10255/metrics/cadvisor,暴露 container 维度数据
从k8s 1.6开始,kubernetes 将 cAdvisor 开始集成在kubelet中,不需要单独配置 从k8s 1.7开始,Kubelet metrics API 不再包含 cadvisor metrics,而是提供了一个独立的 API 接口来做汇总 从 k8s 1.12 开始,cadvisor 监听的端口在k8s中被删除,所有监控数据统一由 Kubelet 的 API 提供
3.6 cadvisor
3.7 cgroup
cgroup 文件中的值是监控数据的最终来源,如
mem usage 的值,来自于
/sys/fs/cgroup/memory/docker/[containerId]/memory.usage_in_bytes如果没限制内存,Limit=machine_mem,否则来自于
/sys/fs/cgroup/memory/docker/[id]/memory.limit_in_bytes内存使用率=memory.usage_in_bytes/memory.limit_in_bytes
一般情况下,cgroup文件夹下的内容包括CPU、内存、磁盘、网络等信息:
如 memory 下的几个常用的指标含义:
memory.stat 中的信息是最全的:
原理到这里结束,这里解释下最开始的 kubectl top 的几个问题:
四、问题
一般情况下 top 报错有以下几种,可以 kubectl top pod -v=10看到具体的调用日志:
没有部署 heapster 或者 metric-server,或者 pod 运行异常,可以排查对应 pod 日志 要看的 pod 刚刚建出来,还没来得及采集指标,报 not found 错误,默认 1 分钟 以上两种都不是,可以检查下 kubelet 的 10255 端口是否开放,默认情况下会使用这个只读端口获取指标,也可以在 heapster 或 metric-server 的配置中增加证书,换成 10250 认证端口
4.2 kubectl top pod 内存怎么计算,包含 pause容器吗
每次启动 pod,都会有一个 pause 容器,既然是容器就一定有资源消耗(一般在 2-3M 的内存),cgroup 文件中,业务容器和 pause 容器都在同一个 pod的文件夹下。
但 cadvisor 在查询 pod 的内存使用量时,是先获取了 pod 下的container列表,再逐个获取container的内存占用,不过这里的 container 列表并没有包含 pause,因此最终 top pod 的结果也不包含 pause 容器pod 的内存使用量计算kubectl top pod 得到的内存使用量,并不是 cadvisor 中的 container_memory_usage_bytes,而是 container_memory_working_set_bytes,计算方式为:
container_memory_usage_bytes = container_memory_rss + container_memory_cache + kernel memory
container_memory_working_set_bytes = container_memory_usage_bytes – total_inactive_file(未激活的匿名缓存页)
同理,node 的内存使用量也是 container_memory_working_set_bytes。
4.3 kubectl top node 怎么计算,和节点上直接 top 有什么区别
rss + cache = (in)active_anon + (in)active_file
4.4 kubectl top pod 和 exec 进入 pod 后看到的 top 不一样
进程的RSS为进程使用的所有物理内存(file_rss+anon_rss),即Anonymous pages+Mapped apges(包含共享内存) cgroup RSS为(anonymous and swap cache memory),不包含共享内存。两者都不包含file cache
4.5 kubectl top pod 和 docker stats得到的值为什么不同?
docker stats dockerID 可以看到容器当前的使用量:
docker stats = container_memory_usage_bytes - container_memory_cache
五、后记
虽然 kubectl top help 中显示支持 Storage,但直到 1.16 版本仍然不支持 1.13 之前需要 heapster,1.13 以后需要 metric-server,这部分 kubectl top help 的输出 有误,里面只提到了heapster k8s dashboard 中的监控图默认使用的是 heapster,切换为 metric-server后数据会异常,需要多部署一个metric-server-scraper 的 pod 来做接口转换,具体参考 pr:https://github.com/kubernetes/dashboard/pull/3504
扫码更精彩 ⏬
近期好文: