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

Emit kube_node_status_capacity_TYPE metrics

kube-state-metrics has removed kube_node_status_capacity_memory_bytes
and kube_node_status_capacity_cpu_cores as of v2.0. Our users have
persisted metrics that go back to pre-2.0 and we have not had the proper
replacement metric kube_node_status_capacity whitelisted until recently.
To maintain functionality, we are choosing to emit the removed metrics
ourselves. At some later date we can likely remove this code and
translate our Prometheus queries to use kube_node_status_capacity.

These metrics are critically important for Assets data via ClusterNodes
which is then used by ComputeAssets.

This commit adds the ability for cost-model to emit
- kube_node_status_capacity_cpu_cores
- kube_node_status_capacity_memory_bytes

When the respective env vars are true:
- EMIT_KUBE_NODE_STATUS_CAPACITY_MEMORY_BYTES_METRIC
- EMIT_KUBE_NODE_STATUS_CAPACITY_CPU_CORES_METRIC

Tested on a cluster that still had KSM v1.9.x installed to confirm that
Kubecost still behaved as expected. Validation tests with KSM v2.0 will
occur later alongside a helm chart change.
Michael Dresser 5 лет назад
Родитель
Сommit
aac94075cc
2 измененных файлов с 210 добавлено и 2 удалено
  1. 194 0
      pkg/costmodel/metrics.go
  2. 16 2
      pkg/env/costmodelenv.go

+ 194 - 0
pkg/costmodel/metrics.go

@@ -529,6 +529,188 @@ func (cim ClusterInfoMetric) Write(m *dto.Metric) error {
 	return nil
 }
 
+//--------------------------------------------------------------------------
+//  KubeNodeStatusCapacityMemoryBytesCollector
+//--------------------------------------------------------------------------
+
+// KubeNodeStatusCapacityMemoryBytesCollector is a prometheus collector that generates
+// KubeNodeStatusCapacityMemoryBytesMetrics
+type KubeNodeStatusCapacityMemoryBytesCollector struct {
+	KubeClusterCache clustercache.ClusterCache
+}
+
+// Describe sends the super-set of all possible descriptors of metrics
+// collected by this Collector.
+func (nsac KubeNodeStatusCapacityMemoryBytesCollector) Describe(ch chan<- *prometheus.Desc) {
+	ch <- prometheus.NewDesc("kube_node_status_capacity_memory_bytes", "node capacity memory bytes", []string{}, nil)
+}
+
+// Collect is called by the Prometheus registry when collecting metrics.
+func (nsac KubeNodeStatusCapacityMemoryBytesCollector) Collect(ch chan<- prometheus.Metric) {
+	nodes := nsac.KubeClusterCache.GetAllNodes()
+	for _, node := range nodes {
+		// k8s.io/apimachinery/pkg/api/resource/amount.go and
+		// k8s.io/apimachinery/pkg/api/resource/quantity.go for
+		// details on the "amount" API. See
+		// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-types
+		// for the units of memory and CPU.
+		memoryBytes := node.Status.Capacity.Memory().Value()
+
+		m := newKubeNodeStatusCapacityMemoryBytesMetric(node.GetName(), memoryBytes, "kube_node_status_capacity_memory_bytes", nil, nil)
+		ch <- m
+	}
+}
+
+//--------------------------------------------------------------------------
+//  KubeNodeStatusCapacityMemoryBytesMetric
+//--------------------------------------------------------------------------
+
+// KubeNodeStatusCapacityMemoryBytesMetric is a prometheus.Metric used to encode
+// a duplicate of the deprecated kube-state-metrics metric
+// kube_node_status_capacity_memory_bytes
+type KubeNodeStatusCapacityMemoryBytesMetric struct {
+	fqName      string
+	help        string
+	labelNames  []string
+	labelValues []string
+	bytes       int64
+	node        string
+}
+
+// Creates a new KubeNodeStatusCapacityMemoryBytesMetric, implementation of prometheus.Metric
+func newKubeNodeStatusCapacityMemoryBytesMetric(node string, bytes int64, fqname string, labelNames []string, labelValues []string) KubeNodeStatusCapacityMemoryBytesMetric {
+	return KubeNodeStatusCapacityMemoryBytesMetric{
+		fqName:      fqname,
+		labelNames:  labelNames,
+		labelValues: labelValues,
+		help:        "kube_node_status_capacity_memory_bytes Node Capacity Memory Bytes",
+		bytes:       bytes,
+		node:        node,
+	}
+}
+
+// Desc returns the descriptor for the Metric. This method idempotently
+// returns the same descriptor throughout the lifetime of the Metric.
+func (nam KubeNodeStatusCapacityMemoryBytesMetric) Desc() *prometheus.Desc {
+	l := prometheus.Labels{"node": nam.node}
+	return prometheus.NewDesc(nam.fqName, nam.help, nam.labelNames, l)
+}
+
+// Write encodes the Metric into a "Metric" Protocol Buffer data
+// transmission object.
+func (nam KubeNodeStatusCapacityMemoryBytesMetric) Write(m *dto.Metric) error {
+	h := float64(nam.bytes)
+	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],
+		})
+	}
+	n := "node"
+	labels = append(labels, &dto.LabelPair{
+		Name:  &n,
+		Value: &nam.node,
+	})
+	m.Label = labels
+	return nil
+}
+
+//--------------------------------------------------------------------------
+//  KubeNodeStatusCapacityCPUCoresCollector
+//--------------------------------------------------------------------------
+
+// KubeNodeStatusCapacityCPUCoresCollector is a prometheus collector that generates
+// KubeNodeStatusCapacityCPUCoresMetrics
+type KubeNodeStatusCapacityCPUCoresCollector struct {
+	KubeClusterCache clustercache.ClusterCache
+}
+
+// Describe sends the super-set of all possible descriptors of metrics
+// collected by this Collector.
+func (nsac KubeNodeStatusCapacityCPUCoresCollector) Describe(ch chan<- *prometheus.Desc) {
+	ch <- prometheus.NewDesc("kube_node_status_capacity_cpu_cores", "node capacity cpu cores", []string{}, nil)
+}
+
+// Collect is called by the Prometheus registry when collecting metrics.
+func (nsac KubeNodeStatusCapacityCPUCoresCollector) Collect(ch chan<- prometheus.Metric) {
+	nodes := nsac.KubeClusterCache.GetAllNodes()
+	for _, node := range nodes {
+		// k8s.io/apimachinery/pkg/api/resource/amount.go and
+		// k8s.io/apimachinery/pkg/api/resource/quantity.go for
+		// details on the "amount" API. See
+		// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-types
+		// for the units of memory and CPU.
+		cpuCores := float64(node.Status.Capacity.Cpu().MilliValue()) / 1000
+
+		m := newKubeNodeStatusCapacityCPUCoresMetric(node.GetName(), cpuCores, "kube_node_status_capacity_cpu_cores", nil, nil)
+		ch <- m
+	}
+}
+
+//--------------------------------------------------------------------------
+//  KubeNodeStatusCapacityCPUCoresMetric
+//--------------------------------------------------------------------------
+
+// KubeNodeStatusCapacityCPUCoresMetric is a prometheus.Metric used to encode
+// a duplicate of the deprecated kube-state-metrics metric
+// kube_node_status_capacity_memory_bytes
+type KubeNodeStatusCapacityCPUCoresMetric struct {
+	fqName      string
+	help        string
+	labelNames  []string
+	labelValues []string
+	cores       float64
+	node        string
+}
+
+// Creates a new KubeNodeStatusCapacityCPUCoresMetric, implementation of prometheus.Metric
+func newKubeNodeStatusCapacityCPUCoresMetric(node string, cores float64, fqname string, labelNames []string, labelValues []string) KubeNodeStatusCapacityCPUCoresMetric {
+	return KubeNodeStatusCapacityCPUCoresMetric{
+		fqName:      fqname,
+		labelNames:  labelNames,
+		labelValues: labelValues,
+		help:        "kube_node_status_capacity_cpu_cores Node Capacity CPU Cores",
+		cores:       cores,
+		node:        node,
+	}
+}
+
+// Desc returns the descriptor for the Metric. This method idempotently
+// returns the same descriptor throughout the lifetime of the Metric.
+func (nam KubeNodeStatusCapacityCPUCoresMetric) Desc() *prometheus.Desc {
+	l := prometheus.Labels{"node": nam.node}
+	return prometheus.NewDesc(nam.fqName, nam.help, nam.labelNames, l)
+}
+
+// Write encodes the Metric into a "Metric" Protocol Buffer data
+// transmission object.
+func (nam KubeNodeStatusCapacityCPUCoresMetric) Write(m *dto.Metric) error {
+	h := nam.cores
+	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],
+		})
+	}
+	n := "node"
+	labels = append(labels, &dto.LabelPair{
+		Name:  &n,
+		Value: &nam.node,
+	})
+	m.Label = labels
+	return nil
+}
+
 // toStringPtr is used to create a new string pointer from iteration vars
 func toStringPtr(s string) *string {
 	return &s
@@ -675,6 +857,18 @@ func initCostModelMetrics(clusterCache clustercache.ClusterCache, provider cloud
 				KubeClusterCache: clusterCache,
 			})
 		}
+
+		if env.IsEmitKubeNodeStatusCapacityMemoryBytesMetric() {
+			prometheus.MustRegister(KubeNodeStatusCapacityMemoryBytesCollector{
+				KubeClusterCache: clusterCache,
+			})
+		}
+
+		if env.IsEmitKubeNodeStatusCapacityCPUCoresMetric() {
+			prometheus.MustRegister(KubeNodeStatusCapacityCPUCoresCollector{
+				KubeClusterCache: clusterCache,
+			})
+		}
 	})
 }
 

+ 16 - 2
pkg/env/costmodelenv.go

@@ -35,8 +35,10 @@ const (
 	ConfigPathEnvVar               = "CONFIG_PATH"
 	CloudProviderAPIKeyEnvVar      = "CLOUD_PROVIDER_API_KEY"
 
-	EmitPodAnnotationsMetricEnvVar       = "EMIT_POD_ANNOTATIONS_METRIC"
-	EmitNamespaceAnnotationsMetricEnvVar = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
+	EmitPodAnnotationsMetricEnvVar                    = "EMIT_POD_ANNOTATIONS_METRIC"
+	EmitNamespaceAnnotationsMetricEnvVar              = "EMIT_NAMESPACE_ANNOTATIONS_METRIC"
+	EmitKubeNodeStatusCapacityMemoryBytesMetricEnvVar = "EMIT_KUBE_NODE_STATUS_CAPACITY_MEMORY_BYTES_METRIC"
+	EmitKubeNodeStatusCapacityCPUCoresMetricEnvVar    = "EMIT_KUBE_NODE_STATUS_CAPACITY_CPU_CORES_METRIC"
 
 	ThanosEnabledEnvVar      = "THANOS_ENABLED"
 	ThanosQueryUrlEnvVar     = "THANOS_QUERY_URL"
@@ -89,6 +91,18 @@ func IsEmitPodAnnotationsMetric() bool {
 	return GetBool(EmitPodAnnotationsMetricEnvVar, false)
 }
 
+// IsEmitKubeNodeStatusCapacityMemoryBytesMetric returns true if cost-model is configured
+// to emit the kube_node_status_capacity_memory_bytes metric.
+func IsEmitKubeNodeStatusCapacityMemoryBytesMetric() bool {
+	return GetBool(EmitKubeNodeStatusCapacityMemoryBytesMetricEnvVar, false)
+}
+
+// IsEmitKubeNodeStatusCapacityCPUCoresMetric returns true if cost-model is configured
+// to emit the kube_node_status_capacity_cpu_cores metric.
+func IsEmitKubeNodeStatusCapacityCPUCoresMetric() bool {
+	return GetBool(EmitKubeNodeStatusCapacityCPUCoresMetricEnvVar, false)
+}
+
 // GetAWSAccessKeyID returns the environment variable value for AWSAccessKeyIDEnvVar which represents
 // the AWS access key for authentication
 func GetAWSAccessKeyID() string {