kubelet為cadvisor添加namespace/pod/container標簽示例詳解
kubelet內嵌了cadvisor
在kubernetes中,kubelet中內嵌了cadvisor,prometheus對cadvisor指標的拉取時,使用的是kubelet的endpoints,只是metric_path改為/metrics/cadvisor。
kubelet在集成cadvisor的同時,還其添加了namespace、pod、container標簽,用于定位它在kubernetes資源中的具體位置。
container_spec_cpu_period{
container="prometheus",
endpoint="https-metrics",
id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod304f6c86_d20b_45aa_95ad_db5edc2e8b43.slice/cri-containerd-cbde185ec5c5d6ff6928b10e9dc21de7548aec0e0bcbdff25a9ebf80a9fd3adf.scope",
image=“prometheus:latest",
instance=“192.168.0.1:10250",
job="kubelet",
metrics_path="/metrics/cadvisor",
name="cbde185ec5c5d6ff6928b10e9dc21de7548aec0e0bcbdff25a9ebf80a9fd3adf",
namespace="monitoring",
node=“node01",
pod="prometheus-k8s-0",
service="kubelet"} 100000那么kubelet是如何為cadvisor添加這些標簽的,cadvisor中有沒有采集這些信息呢?
一.cadvisor的指標標簽
為了驗證cadvisor自身的采集能力,將cadvisor單獨部署到kubernetes,配置其拉取的job=cadvisor,拉取到的指標如下:
container_cpu_usage_seconds_total{
container_env_HOSTNAME="prometheus-k8s-0”,
container_env_KUBERNETES_PORT="tcp://10.233.0.1:443”,
container_env_KUBERNETES_PORT_443_TCP="tcp://10.233.0.1:443”,
container_env_KUBERNETES_PORT_443_TCP_ADDR="10.233.0.1”,
container_env_KUBERNETES_PORT_443_TCP_PORT="443”,
container_env_KUBERNETES_PORT_443_TCP_PROTO="tcp”,
container_env_KUBERNETES_SERVICE_HOST="10.233.0.1”,
…
container_label_io_cri_containerd_kind="container”,
container_label_io_kubernetes_container_name="prometheus”, // 容器名稱
container_label_io_kubernetes_pod_name="prometheus-k8s-0”, // pod名稱
container_label_io_kubernetes_pod_namespace="monitoring”, // namespace
container_label_io_kubernetes_pod_uid="304f6c86-d20b-45aa-95ad-db5edc2e8b43”,
container_label_maintainer="The Prometheus Authors <prometheus-developers@googlegroups.com>”,
...
cpu="cpu00”,
endpoint="http”,
id="/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod304f6c86_d20b_45aa_95ad_db5edc2e8b43.slice/cri-containerd-cbde185ec5c5d6ff6928b10e9dc21de7548aec0e0bcbdff25a9ebf80a9fd3adf.scope”,
image=“prometheus:latest”,
instance="10.233.123.70:8080”,
job="cadvisor”,
name="cbde185ec5c5d6ff6928b10e9dc21de7548aec0e0bcbdff25a9ebf80a9fd3adf”,
service="cadvisor"} 709.899183253可以看到拉取的指標中的label:
container_env_*:
- cadvisor采集了容器內的環(huán)境變量信息,并將其添加到指標的label中;
container_label_io_*:
- cadvisor采集了容器的label信息,并將其添加到指標的label中;
- 這些label信息包含了容器的container名稱、所在的pod、所在的namespace信息;
也就是說,cadvisor可以采集到容器的container/pod/namespace信息。
那這些信息是從何而來的呢,看cadvisor的代碼:
- 對cadvisor采集的指標,使用containerLabelsFunc函數(shù)添加額外的標簽;
- containerLabelsFunc默認=DefaultContainerLabels;
// cadvisor/metrics/prometheus.go
func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc, includedMetrics container.MetricSet, now clock.Clock, opts v2.RequestOptions) *PrometheusCollector {
if f == nil {
f = DefaultContainerLabels // 默認的添加標簽的函數(shù)
}
c := &PrometheusCollector{
infoProvider: i,
containerLabelsFunc: f,
...
}
if includedMetrics.Has(container.CpuUsageMetrics) {
c.containerMetrics = append(c.containerMetrics, []containerMetric{
{
name: "container_cpu_user_seconds_total",
help: "Cumulative user cpu time consumed in seconds.",
valueType: prometheus.CounterValue,
getValues: func(s *info.ContainerStats) metricValues {
return metricValues{
{
value: float64(s.Cpu.Usage.User) / float64(time.Second),
timestamp: s.Timestamp,
},
}
},
},
...
}
return c
}看一下DefaultContainerLabels函數(shù)的實現(xiàn):
- 對container.spec中的label,添加了container_label_*前綴,這些label將被添加到最終的指標標簽中;
- 對container.spec中的env,添加了container_label_env_*前綴,這些label將被添加到最終的指標標簽中;
// cadvisor/metrics/prometheus.go
const (
// ContainerLabelPrefix is the prefix added to all container labels.
ContainerLabelPrefix = "container_label_"
// ContainerEnvPrefix is the prefix added to all env variable labels.
ContainerEnvPrefix = "container_env_"
// LabelID is the name of the id label.
LabelID = "id"
// LabelName is the name of the name label.
LabelName = "name"
// LabelImage is the name of the image label.
LabelImage = "image"
)
func DefaultContainerLabels(container *info.ContainerInfo) map[string]string {
set := map[string]string{LabelID: container.Name}
if len(container.Aliases) > 0 {
set[LabelName] = container.Aliases[0]
}
if image := container.Spec.Image; len(image) > 0 {
set[LabelImage] = image
}
for k, v := range container.Spec.Labels {
set[ContainerLabelPrefix+k] = v // container_label_*
}
for k, v := range container.Spec.Envs {
set[ContainerEnvPrefix+k] = v // container_env_*
}
return set
}最后,再看一下containerInfo的spec中的label和env是什么樣子:
"labels":{
"io.kubernetes.container.name":"node-exporter",
"io.kubernetes.pod.name":"node-exporter-gw4qg",
"io.kubernetes.pod.namespace":"monitoring",
"io.kubernetes.pod.uid":"2ac69f2e-cb3c-4e4f-b890-183e457ef891"
},"env": [ "HOSTNAME=node01", "KUBERNETES_SERVICE_PORT=443", "KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443", "KUBERNETES_SERVICE_HOST=10.233.0.1", "KUBERNETES_PORT_443_TCP_PORT=443", "KUBERNETES_SERVICE_PORT_HTTPS=443", "KUBERNETES_PORT=tcp://10.233.0.1:443", "KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1", ... ],
cadvisor對原始的label和env添加了前綴,返回給prometheus:
對label:
- 原始的label=“io.kubernetes.container.name”,加上前綴,變成:container_label_io_kubernetes_container_name;
對env:
- 原始的env=HOSTNAME,加上前綴,變成:container_env_HOSTNAME;
二. kubelet集成cadvisor的指標標簽
kubelet在集成cadvisor時,自定義了為指標額外添加標簽的邏輯containerLabelsFunc,沒有使用DefaultContainerLabels。
kubelet傳入的函數(shù)=containerPrometheusLabelsFunc:
// kubernetes/pkg/kubelet/server/server.go
r.RawMustRegister(metrics.NewPrometheusCollector(prometheusHostAdapter{s.host}, containerPrometheusLabelsFunc(s.host), includedMetrics, clock.RealClock{}, cadvisorOpts))containerPrometheusLabelsFunc函數(shù)的代碼實現(xiàn)如下:
- 從containerInfo.Spec.label中,提取io.kubernetes.pod.name的值,作為pod名稱的label-value;
- 從containerInfo.Spec.label中,提取io.kubernetes.pod.namespace的值,作為namespace名稱的label-value;
- 從containerInfo.Spec.label中,提取io.kubernetes.container.name的值,作為container名稱的label-value;
// kubernetes/pkg/kubelet/server/server.go
func containerPrometheusLabelsFunc(s stats.Provider) metrics.ContainerLabelsFunc {
// containerPrometheusLabels maps cAdvisor labels to prometheus labels.
return func(c *cadvisorapi.ContainerInfo) map[string]string {
// Prometheus requires that all metrics in the same family have the same labels,
// so we arrange to supply blank strings for missing labels
var name, image, podName, namespace, containerName string
if len(c.Aliases) > 0 {
name = c.Aliases[0]
}
image = c.Spec.Image
if v, ok := c.Spec.Labels[kubelettypes.KubernetesPodNameLabel]; ok { // io.kubernetes.pod.name
podName = v
}
if v, ok := c.Spec.Labels[kubelettypes.KubernetesPodNamespaceLabel]; ok { // io.kubernetes.pod.namespace
namespace = v
}
if v, ok := c.Spec.Labels[kubelettypes.KubernetesContainerNameLabel]; ok { // io.kubernetes.container.name
containerName = v
}
// Associate pod cgroup with pod so we have an accurate accounting of sandbox
if podName == "" && namespace == "" {
if pod, found := s.GetPodByCgroupfs(c.Name); found {
podName = pod.Name
namespace = pod.Namespace
}
}
set := map[string]string{
metrics.LabelID: c.Name,
metrics.LabelName: name,
metrics.LabelImage: image,
"pod": podName, // pod名稱
"namespace": namespace, // namespace
"container": containerName, // container名稱
}
return set
}
}三. 總結
cadvisor通過容器的接口,查詢到spec.labels的信息(包含container/pod/namespace)后,
對于普通的cadvisor:
- 使用默認的DefaultContainerLabels函數(shù)添加標簽,為label添加container_label_前綴;
對于kubelet集成的cadvisor:
- 使用自定義的containerPrometheusLablesFunc函數(shù)添加標簽,將原始的標簽變?yōu)閏ontainer=/pod=/namespace=;

以上就是kubelet為cadvisor添加namespace/pod/container標簽示例詳解的詳細內容,更多關于kubelet cadvisor標簽添加的資料請關注腳本之家其它相關文章!
相關文章
Podman開機自啟容器實現(xiàn)過程及與Docker對比
這篇文章主要為大家介紹了Podman開機自啟容器實現(xiàn)過程,通過示例代碼的形式進行演繹過程,有需要的朋友可以參考下,希望可以有所幫助2021-09-09
KVM虛擬化技術之virt-manager使用及KVM虛擬化平臺網(wǎng)絡模型介紹
這篇文章主要介紹了KVM虛擬化技術之virt-manager使用及KVM虛擬化平臺網(wǎng)絡模型介紹,需要的朋友可以參考下2016-10-10
Kubernetes?Ingress實現(xiàn)細粒度IP訪問控制
這篇文章主要為大家介紹了Kubernetes?Ingress實現(xiàn)細粒度IP訪問控制,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04

