乐趣区

promethues系列之追踪k8s容器指标的打tag的流程

k8s 中容器资源的监控

在 promethues 中如何配置采集容器指标

  • 采用 promethues 的 kubernetes_sd_configs 中 node 级别的 role
- job_name: kubernetes-nodes-cadvisor
  honor_timestamps: false
  scrape_interval: 30s
  scrape_timeout: 10s
  metrics_path: /metrics
  scheme: https
  kubernetes_sd_configs:
  - role: node
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  relabel_configs:
  - separator: ;
    regex: __meta_kubernetes_node_label_(.+)
    replacement: $1
    action: labelmap
  - separator: ;
    regex: (.*)
    target_label: __metrics_path__
    replacement: /metrics/cadvisor
    action: replace

cadvisor 架构图

cadvisor 中 POD

  • 在查看 cadvisor 代码时发现有一种 container_name==”POD” 的容器,查了下是 k8s 中的 pause pod

下面追踪下打 tag 的过程: 以 pod cpu 使用率为例

kubelet 最终 tag

  • 对应 cadvisor 指标为 container_cpu_usage_seconds_total, 可以看到最终查询出来的有如下 tag
  • 那我们会好奇标识 app 或 service 的 tag:pod,pod_name,container,container_name 是如何打上去的呢

访问集成在 kubelet 中的 cadvisor 的 tag

  • curl localhost:4194/metrics

  • 可以发现除了 cpu 是 container_cpu_usage_seconds_total 指标特有的 tag 之外, 还有 id,name,namespace,pod_name,container_name,image 这几个 tag
  • 上述 tag 作为 cadvisor 通用 tag 会附加在每一个 metric 上面
  • 其实在裸的 cadvisor 中只有 id,image,name 三个 tag 原始 cadvisor 打 tag
  • namespace,pod_name,container_name 等属性是 k8s 才有的,cadvisor 肯定无法感知 pod 信息, 说明是 k8s 注入的

kubelet 内置的 cadvisor 中使用了自定义的 PrometheusLabelsFunc

以 k8s 1.15 版本为例
代码在:E:go_pathsrcgithub.comkuberneteskubernetespkgkubeletserverserver.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 {podName = v}
        if v, ok := c.Spec.Labels[kubelettypes.KubernetesPodNamespaceLabel]; ok {namespace = v}
        if v, ok := c.Spec.Labels[kubelettypes.KubernetesContainerNameLabel]; ok {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_name":         podName,
            "pod":              podName,
            "namespace":        namespace,
            "container_name":   containerName,
            "container":        containerName,
        }
        return set
    }
}

k8s 1.15 1.16 版本对于 pod 和 pod_name 的变化

  • 经过观察发现 1.15 的 pod pod_name 都有,1.16 只有 pod
  • 这是因为 在 k8s 1.16 版本为了统一 cadvisor 和 kube-stats 指标 tag 做了变更[这个 pr] (https://github.com/kubernetes…

kubelet 启动时可以使用 –node-labels 注入 node 级别 tag

--node-labels=os.name=xxxx,os.version=xxxx,os.architecture=amd64,
  • 这些 tag 会转化为 promethues metric 命名方式 xxx_xxx
  • 最后追加为 os_version=xxx,os_architecture=amd64
退出移动版