Просмотр исходного кода

Emit kube_pod_labels with all label names

In KSM v2, kube_pod_labels was restricted to only emit labels
if they are explicitly whitelisted. See
https://github.com/kubernetes/kube-state-metrics/issues/1270#issuecomment-712986441

We need labels so we can match pods with services, among other things.

This commit enables cost-model to emit kube_pod_labels as if it were
pre-KSM v2. This should not cause problems if KSM v1 is deployed because
we are just emitting the same data (which will have a different job label)
and it isn't used for things like sum/rate/etc. queries.
Michael Dresser 5 лет назад
Родитель
Сommit
13a60cf70a
2 измененных файлов с 147 добавлено и 0 удалено
  1. 139 0
      pkg/costmodel/metrics.go
  2. 8 0
      pkg/env/costmodelenv.go

+ 139 - 0
pkg/costmodel/metrics.go

@@ -1,6 +1,7 @@
 package costmodel
 
 import (
+	"fmt"
 	"math"
 	"strconv"
 	"strings"
@@ -711,6 +712,138 @@ func (nam KubeNodeStatusCapacityCPUCoresMetric) Write(m *dto.Metric) error {
 	return nil
 }
 
+//--------------------------------------------------------------------------
+//  KubePodLabelsCollector
+//--------------------------------------------------------------------------
+//
+// We use this to emit kube_pod_labels with all of a pod's labels, regardless
+// of the whitelist setting introduced in KSM v2. See
+// https://github.com/kubernetes/kube-state-metrics/issues/1270#issuecomment-712986441
+
+// KubePodLabelsCollector is a prometheus collector that generates
+// KubePodLabelsMetrics
+type KubePodLabelsCollector struct {
+	KubeClusterCache clustercache.ClusterCache
+}
+
+// Describe sends the super-set of all possible descriptors of metrics
+// collected by this Collector.
+func (nsac KubePodLabelsCollector) Describe(ch chan<- *prometheus.Desc) {
+	ch <- prometheus.NewDesc("kube_pod_labels", "all labels for each pod prefixed with label_", []string{}, nil)
+}
+
+// makeLabelNameValueArraysForPod takes a pod and returns two aligned arrays
+// the length of the number of labels on the pod. The first array contains
+// the name of each label prefixed with "label_" to match the kube-state-metrics
+// standard. The second array contains the value of the index-matched label name.
+func makeLabelNameValueArraysForPod(pod *v1.Pod) ([]string, []string) {
+	labelNames := []string{}
+	labelValues := []string{}
+
+	for labelName, labelValue := range pod.GetLabels() {
+		labelNames = append(labelNames, fmt.Sprintf("label_%s", labelName))
+		labelValues = append(labelValues, labelValue)
+	}
+
+	return labelNames, labelValues
+}
+
+// Collect is called by the Prometheus registry when collecting metrics.
+func (nsac KubePodLabelsCollector) Collect(ch chan<- prometheus.Metric) {
+	pods := nsac.KubeClusterCache.GetAllPods()
+	for _, pod := range pods {
+
+		labelNames, labelValues := makeLabelNameValueArraysForPod(pod)
+
+		m := newKubePodLabelsMetric(
+			pod.GetName(),
+			pod.GetNamespace(),
+			string(pod.GetUID()),
+			"kube_pod_labels",
+			labelNames,
+			labelValues,
+		)
+		ch <- m
+	}
+}
+
+//--------------------------------------------------------------------------
+//  KubePodLabelsMetric
+//--------------------------------------------------------------------------
+
+// KubePodLabelsMetric is a prometheus.Metric used to encode
+// a duplicate of the deprecated kube-state-metrics metric
+// kube_pod_labels
+type KubePodLabelsMetric struct {
+	fqName      string
+	help        string
+	labelNames  []string
+	labelValues []string
+	pod         string
+	namespace   string
+	uid         string
+}
+
+// Creates a new KubePodLabelsMetric, implementation of prometheus.Metric
+func newKubePodLabelsMetric(pod string, namespace string, uid string, fqname string, labelNames []string, labelValues []string) KubePodLabelsMetric {
+	return KubePodLabelsMetric{
+		fqName:      fqname,
+		labelNames:  labelNames,
+		labelValues: labelValues,
+		help:        "kube_pod_labels all labels for each pod prefixed with label_",
+		pod:         pod,
+		namespace:   namespace,
+		uid:         uid,
+	}
+}
+
+// Desc returns the descriptor for the Metric. This method idempotently
+// returns the same descriptor throughout the lifetime of the Metric.
+func (nam KubePodLabelsMetric) Desc() *prometheus.Desc {
+	l := prometheus.Labels{
+		"pod":       nam.pod,
+		"namespace": nam.namespace,
+		"uid":       nam.uid,
+	}
+	return prometheus.NewDesc(nam.fqName, nam.help, nam.labelNames, l)
+}
+
+// Write encodes the Metric into a "Metric" Protocol Buffer data
+// transmission object.
+func (nam KubePodLabelsMetric) Write(m *dto.Metric) error {
+	h := float64(1)
+	m.Gauge = &dto.Gauge{
+		Value: &h,
+	}
+
+	var labels []*dto.LabelPair
+	for i := range nam.labelNames {
+		labels = append(labels, &dto.LabelPair{
+			Name:  &nam.labelNames[i],
+			Value: &nam.labelValues[i],
+		})
+	}
+
+	podString := "pod"
+	namespaceString := "namespace"
+	uidString := "uid"
+	labels = append(labels,
+		&dto.LabelPair{
+			Name:  &podString,
+			Value: &nam.pod,
+		},
+		&dto.LabelPair{
+			Name:  &namespaceString,
+			Value: &nam.namespace,
+		}, &dto.LabelPair{
+			Name:  &uidString,
+			Value: &nam.uid,
+		},
+	)
+	m.Label = labels
+	return nil
+}
+
 // toStringPtr is used to create a new string pointer from iteration vars
 func toStringPtr(s string) *string {
 	return &s
@@ -869,6 +1002,12 @@ func initCostModelMetrics(clusterCache clustercache.ClusterCache, provider cloud
 				KubeClusterCache: clusterCache,
 			})
 		}
+
+		if env.IsEmitKubePodLabelsMetric() {
+			prometheus.MustRegister(KubePodLabelsCollector{
+				KubeClusterCache: clusterCache,
+			})
+		}
 	})
 }
 

+ 8 - 0
pkg/env/costmodelenv.go

@@ -39,6 +39,7 @@ const (
 	EmitNamespaceAnnotationsMetricEnvVar              = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
 	EmitKubeNodeStatusCapacityMemoryBytesMetricEnvVar = "EMIT_KUBE_NODE_STATUS_CAPACITY_MEMORY_BYTES_METRIC"
 	EmitKubeNodeStatusCapacityCPUCoresMetricEnvVar    = "EMIT_KUBE_NODE_STATUS_CAPACITY_CPU_CORES_METRIC"
+	EmitKubePodLabelsMetricEnvVar                     = "EMIT_KUBE_POD_LABELS_METRIC"
 
 	ThanosEnabledEnvVar      = "THANOS_ENABLED"
 	ThanosQueryUrlEnvVar     = "THANOS_QUERY_URL"
@@ -103,6 +104,13 @@ func IsEmitKubeNodeStatusCapacityCPUCoresMetric() bool {
 	return GetBool(EmitKubeNodeStatusCapacityCPUCoresMetricEnvVar, true)
 }
 
+// IsEmitKubePodLabelsMetric returns true if cost-model is configured
+// to emit the kube_pod_labels metric. It uses the old, pre KSM 2.0 logic
+// where all labels are emitted instead of requiring a whitelist.
+func IsEmitKubePodLabelsMetric() bool {
+	return GetBool(EmitKubePodLabelsMetricEnvVar, true)
+}
+
 // GetAWSAccessKeyID returns the environment variable value for AWSAccessKeyIDEnvVar which represents
 // the AWS access key for authentication
 func GetAWSAccessKeyID() string {