通过cAdvisor收集容器指标
Google的cAdvisor项目最初是一个独立项目,用于从节点上收集运行的容器的资源和性能指标。在Kubernetes中,cAdvisor嵌入到kubelet中。kubelet控制着集群中每个节点上的所有容器。这就很方便了,因为不需要在每个节点中都运行另一个进程来收集容器指标。
kubelet以Prometheus指标格式在/metrics端点上公开了所有运行时指标和所有cAdvisor指标。
从cAdvisor提供的“容器”度量标准最终是底层Linux cgroup提供报告的度量标准。就像节点指标一样,它们众多且详细。但是,我们关注基础节点提供的资源的容器使用。具体来说,我们对CPU,内存,网络和磁盘感兴趣。同样,在处理资源时,最好在选择这些指标的报告时使用USE方法。
容器指标概述
由于这些度量标准的来源从节点(node_exporter)更改为容器(cAdvisor),因此度量标准的名称也将更改。此外,每个指标都是集群中所有容器的报告。要获得应用程序的整体视图,必须在Prometheus中使用sum
方法。
在开始讨论各个资源指标之前,我们需要讨论Kubernetes中的一项功能,该功能将使饱和度的计算更加容易。此功能是资源“requests”和“limits”。
Requests 和 Limits
Kubernetes系统的核心是一个调度程序,它将容器调度在节点上。就像用不同大小的物品包装一堆不同大小的盒子一样,调度程序需要知道节点的容量以及放在这些节点上的容器的大小。在不知道容器的“大小”的情况下,您可以轻松地对群集中的节点进行过度配置,从而由于拥挤而导致性能问题。
请求和限制将作为部署的一部分应用于容器规范。从Kubernetes 1.10开始,可以设置两种资源类型的请求和限制; CPU和内存。将CPU指定为core数,并以字节为单位指定内存。
请求是对容器将需要的最少资源量。请求并没有说明您将使用多少资源,而是需要多少资源。您正在告诉调度程序容器需要多少资源来完成其工作。请求由Kubernetes调度程序用于调度。对于CPU请求,它们还用于配置Linux内核如何调度容器。
限制是您的容器将要使用的最大资源量。限制必须大于或等于请求。如果仅设置限制,则请求将与限制相同。
限制允许容器有一定的余量来超过资源请求。限制为您提供了一个旋钮,可以过度使用节点上的资源,因为Kubernetes调度程序不考虑限制。话虽如此,如果您的容器超出了限制,则操作取决于资源;如果您超过CPU限制,将受到限制;如果超过内存限制,将被杀死。
CPU Utilization, Saturation, 和 Errors
对于CPU利用率,Kubernetes仅为我们提供了每个容器的三个指标:
-
container_cpu_user_seconds_total
--“user”时间总数(即,不在内核中花费的时间) -
container_cpu_system_seconds_total
--“system”时间的总数(即在内核中花费的时间) -
container_cpu_usage_seconds_total
--以上的总和。在Kubernetes 1.9之前的版本中,将为所有节点中的每个CPU报告此错误。在1.10中发生了变化。
所有这些指标都是计数器,需要对其应用rate。该查询将为我们提供每个容器正在使用的核心数。对于整个系统中该名称的所有容器:
sum(
rate(container_cpu_usage_seconds_total[5m]))
by (container_name)
当使用CPU限制运行时,由于定义了CPU使用上限,饱和度的计算变得容易得多。当容器超出其CPU限制时,Linux运行时将“限制”该容器并在container_cpu_cfs_throttled_seconds_total系列中记录其被限制的时间。再次按容器跟踪每个容器,因此采用一个比率:
sum(
rate(container_cpu_cfs_throttled_seconds_total[5m]))
by (container_name)
这是跟踪具有CPU限制的运行时间的重要指标。
就像node_exporter一样,cAdvisor不会暴露CPU错误。
内存 Utilization, Saturation 和Errors
cAdvisor中跟踪的内存指标是从node_exporter公开的43个内存指标的子集。以下是容器内存指标:
container_memory_cache -- Number of bytes of page cache memory.
container_memory_rss -- Size of RSS in bytes.
container_memory_swap -- Container swap usage in bytes.
container_memory_usage_bytes -- Current memory usage in bytes,
including all memory regardless of
when it was accessed.
container_memory_max_usage_bytes -- Maximum memory usage recorded
in bytes.
container_memory_working_set_bytes -- Current working set in bytes.
container_memory_failcnt -- Number of memory usage hits limits.
container_memory_failures_total -- Cumulative count of memory
allocation failures.
您可能认为可以通过container_memory_usage_bytes轻松跟踪内存利用率,但是,该指标还包括可以在内存压力下驱逐的缓存(认为是文件系统缓存)项。更好的指标是container_memory_working_set_bytes,因为这是OOM杀手正在关注的对象。
要计算容器的内存利用率,我们使用:
sum(container_memory_working_set_bytes{name!~"POD"})
by (name)
在上述查询中,我们需要排除名称中包含“POD”的容器。这是此容器的父级cgroup,将跟踪pod中所有容器的统计信息。
在有内存限制的情况下运行时,容器的内存饱和度会变得更容易。我们将从饱和度定义饱和度为可用内存量:
sum(container_memory_working_set_bytes) by (container_name) / sum(label_join(kube_pod_container_resource_limits_memory_bytes,
"container_name", "", "container")) by (container_name)
在这里,我们必须加入两个系列,一个来自cAdvisor,一个来自kube-state-metrics。不幸的是,容器名称标签没有对齐,但是PromQL在这里可以使用label_join
帮助。
kubelet不会暴露内存错误。
磁盘 Utilization, Saturation, 和Errors
在处理磁盘I / O时,我们首先通过查找以及读取和写入跟踪所有磁盘利用率。 cAdvisor具有针对container_fs_io_time_seconds_total和container_fs_io_time_weighted_seconds_total的系列。这些应该在节点级别跟踪相似的指标,但是在我的安装中,它们始终为零。
最基本的磁盘I/O利用率是读/写的字节数:
sum(rate(container_fs_writes_bytes_total[5m])) by (container_name,device)
sum(rate(container_fs_reads_bytes_total[5m])) by (container_name,device)
对这些求和求和,以获得每个容器的总体磁盘I/O利用率。
Kubelet没有公开足够的细节,无法对容器磁盘饱和或错误进行有意义的查询。
网络 Utilization, Saturation 和Errors
您可以在容器级别的网络利用率之间进行选择,以字节或数据包为单位进行发送和接收。该查询有些不同,因为所有网络记帐都在Pod级别上进行,而不是在容器上进行!
此查询将按Pod名称显示每个Pod的网络利用率:
sum(rate(container_network_receive_bytes_total[5m])) by (name)
sum(rate(container_network_transmit_bytes_total[5m])) by (name)
同样,在不知道最大网络带宽是多少的情况下,网络的饱和度定义不明确。您也许可以使用丢弃的数据包作为代理。 cAdvisor会同时提供container_network_receive_packets_dropped_total和container_network_transmit_packets_dropped_total。
cAdvisor还将显示系列container_network_receive_errors_total和container_network_transmit_errors_total的错误数量。