From 145ee24e09cdfb8760775a60c65d28f55c08d17b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johannes=20W=C3=BCrbach?= <johannes.wuerbach@googlemail.com>
Date: Tue, 7 Apr 2020 22:00:29 +0200
Subject: [PATCH] Convert custom-metrics into an addon

---
 README.md                                     |   1 +
 ...prometheus-rules-and-grafana-dashboards.md |   1 +
 example.jsonnet                               |   1 +
 experimental/custom-metrics-api/.gitignore    |   7 -
 experimental/custom-metrics-api/README.md     |  21 --
 ...-resource-reader-cluster-role-binding.yaml |  12 --
 .../custom-metrics-apiservice.yaml            |  13 --
 .../custom-metrics-cluster-role.yaml          |   9 -
 .../custom-metrics-configmap.yaml             |  98 ----------
 experimental/custom-metrics-api/deploy.sh     |   7 -
 ...a-custom-metrics-cluster-role-binding.yaml |  12 --
 .../custom-metrics-api/sample-app.yaml        |  67 -------
 experimental/custom-metrics-api/teardown.sh   |   7 -
 .../kube-prometheus-custom-metrics.libsonnet  | 179 ++++++++++++++++++
 14 files changed, 182 insertions(+), 253 deletions(-)
 delete mode 100644 experimental/custom-metrics-api/.gitignore
 delete mode 100644 experimental/custom-metrics-api/README.md
 delete mode 100644 experimental/custom-metrics-api/custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
 delete mode 100644 experimental/custom-metrics-api/custom-metrics-apiservice.yaml
 delete mode 100644 experimental/custom-metrics-api/custom-metrics-cluster-role.yaml
 delete mode 100644 experimental/custom-metrics-api/custom-metrics-configmap.yaml
 delete mode 100644 experimental/custom-metrics-api/deploy.sh
 delete mode 100644 experimental/custom-metrics-api/hpa-custom-metrics-cluster-role-binding.yaml
 delete mode 100644 experimental/custom-metrics-api/sample-app.yaml
 delete mode 100644 experimental/custom-metrics-api/teardown.sh
 create mode 100644 jsonnet/kube-prometheus/kube-prometheus-custom-metrics.libsonnet

diff --git a/README.md b/README.md
index 4172e516..c8a99484 100644
--- a/README.md
+++ b/README.md
@@ -198,6 +198,7 @@ local kp =
   // (import 'kube-prometheus/kube-prometheus-node-ports.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-static-etcd.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-thanos-sidecar.libsonnet') +
+  // (import 'kube-prometheus/kube-prometheus-custom-metrics.libsonnet') +
   {
     _config+:: {
       namespace: 'monitoring',
diff --git a/docs/developing-prometheus-rules-and-grafana-dashboards.md b/docs/developing-prometheus-rules-and-grafana-dashboards.md
index 974c3cc4..91f430f8 100644
--- a/docs/developing-prometheus-rules-and-grafana-dashboards.md
+++ b/docs/developing-prometheus-rules-and-grafana-dashboards.md
@@ -18,6 +18,7 @@ local kp =
   // (import 'kube-prometheus/kube-prometheus-node-ports.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-static-etcd.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-thanos-sidecar.libsonnet') +
+  // (import 'kube-prometheus/kube-prometheus-custom-metrics.libsonnet') +
   {
     _config+:: {
       namespace: 'monitoring',
diff --git a/example.jsonnet b/example.jsonnet
index 77864e09..54de1e35 100644
--- a/example.jsonnet
+++ b/example.jsonnet
@@ -6,6 +6,7 @@ local kp =
   // (import 'kube-prometheus/kube-prometheus-node-ports.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-static-etcd.libsonnet') +
   // (import 'kube-prometheus/kube-prometheus-thanos-sidecar.libsonnet') +
+  // (import 'kube-prometheus/kube-prometheus-custom-metrics.libsonnet') +
   {
     _config+:: {
       namespace: 'monitoring',
diff --git a/experimental/custom-metrics-api/.gitignore b/experimental/custom-metrics-api/.gitignore
deleted file mode 100644
index 794c008c..00000000
--- a/experimental/custom-metrics-api/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-apiserver-key.pem
-apiserver.csr
-apiserver.pem
-metrics-ca-config.json
-metrics-ca.crt
-metrics-ca.key
-cm-adapter-serving-certs.yaml
diff --git a/experimental/custom-metrics-api/README.md b/experimental/custom-metrics-api/README.md
deleted file mode 100644
index e93d809f..00000000
--- a/experimental/custom-metrics-api/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Custom Metrics API
-
-The custom metrics API allows the HPA v2 to scale based on arbirary metrics.
-
-This directory contains an example deployment which extends the Prometheus Adapter, deployed with kube-prometheus, serve the [Custom Metrics API](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/custom-metrics-api.md) by talking to Prometheus running inside the cluster.
-
-Make sure you have the Prometheus Adapter up and running in the `monitoring` namespace.
-
-You can deploy everything in the `monitoring` namespace using `./deploy.sh`.
-
-When you're done, you can teardown using the `./teardown.sh` script.
-
-### Sample App
-
-Additionally, this directory contains a sample app that uses the [Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) to scale the Deployment's replicas of Pods up and down as needed.  
-Deploy this app by running `kubectl apply -f sample-app.yaml`. 
-Make the app accessible on your system, for example by using `kubectl port-forward svc/sample-app 8080`. Next you need to put some load on its http endpoints. 
-
-A tool like [hey](https://github.com/rakyll/hey) is helpful for doing so: `hey -c 20 -n 100000000 http://localhost:8080/metrics`
-
-There is an even more detailed information on this sample app at [luxas/kubeadm-workshop](https://github.com/luxas/kubeadm-workshop#deploying-the-prometheus-operator-for-monitoring-services-in-the-cluster).
diff --git a/experimental/custom-metrics-api/custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml b/experimental/custom-metrics-api/custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
deleted file mode 100644
index e2b1ca43..00000000
--- a/experimental/custom-metrics-api/custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: custom-metrics-server-resources
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: custom-metrics-server-resources
-subjects:
-- kind: ServiceAccount
-  name: prometheus-adapter
-  namespace: monitoring
diff --git a/experimental/custom-metrics-api/custom-metrics-apiservice.yaml b/experimental/custom-metrics-api/custom-metrics-apiservice.yaml
deleted file mode 100644
index 98f87495..00000000
--- a/experimental/custom-metrics-api/custom-metrics-apiservice.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-apiVersion: apiregistration.k8s.io/v1beta1
-kind: APIService
-metadata:
-  name: v1beta1.custom.metrics.k8s.io
-spec:
-  service:
-    name: prometheus-adapter
-    namespace: monitoring
-  group: custom.metrics.k8s.io
-  version: v1beta1
-  insecureSkipTLSVerify: true
-  groupPriorityMinimum: 100
-  versionPriority: 100
diff --git a/experimental/custom-metrics-api/custom-metrics-cluster-role.yaml b/experimental/custom-metrics-api/custom-metrics-cluster-role.yaml
deleted file mode 100644
index 003f0bf1..00000000
--- a/experimental/custom-metrics-api/custom-metrics-cluster-role.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRole
-metadata:
-  name: custom-metrics-server-resources
-rules:
-- apiGroups:
-  - custom.metrics.k8s.io
-  resources: ["*"]
-  verbs: ["*"]
diff --git a/experimental/custom-metrics-api/custom-metrics-configmap.yaml b/experimental/custom-metrics-api/custom-metrics-configmap.yaml
deleted file mode 100644
index 36908acd..00000000
--- a/experimental/custom-metrics-api/custom-metrics-configmap.yaml
+++ /dev/null
@@ -1,98 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: adapter-config
-  namespace: monitoring
-data:
-  config.yaml: |
-    rules:
-    - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}'
-      seriesFilters: []
-      resources:
-        overrides:
-          namespace:
-            resource: namespace
-          pod:
-            resource: pod
-      name:
-        matches: ^container_(.*)_seconds_total$
-        as: ""
-      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>)
-    - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}'
-      seriesFilters:
-      - isNot: ^container_.*_seconds_total$
-      resources:
-        overrides:
-          namespace:
-            resource: namespace
-          pod:
-            resource: pod
-      name:
-        matches: ^container_(.*)_total$
-        as: ""
-      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>)
-    - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}'
-      seriesFilters:
-      - isNot: ^container_.*_total$
-      resources:
-        overrides:
-          namespace:
-            resource: namespace
-          pod:
-            resource: pod
-      name:
-        matches: ^container_(.*)$
-        as: ""
-      metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>)
-    - seriesQuery: '{namespace!="",__name__!~"^container_.*"}'
-      seriesFilters:
-      - isNot: .*_total$
-      resources:
-        template: <<.Resource>>
-      name:
-        matches: ""
-        as: ""
-      metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)
-    - seriesQuery: '{namespace!="",__name__!~"^container_.*"}'
-      seriesFilters:
-      - isNot: .*_seconds_total
-      resources:
-        template: <<.Resource>>
-      name:
-        matches: ^(.*)_total$
-        as: ""
-      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)
-    - seriesQuery: '{namespace!="",__name__!~"^container_.*"}'
-      seriesFilters: []
-      resources:
-        template: <<.Resource>>
-      name:
-        matches: ^(.*)_seconds_total$
-        as: ""
-      metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)
-    resourceRules:
-      cpu:
-        containerQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)
-        nodeQuery: sum(rate(container_cpu_usage_seconds_total{<<.LabelMatchers>>, id='/'}[1m])) by (<<.GroupBy>>)
-        resources:
-          overrides:
-            node:
-              resource: node
-            namespace:
-              resource: namespace
-            pod:
-              resource: pod
-        containerLabel: container
-      memory:
-        containerQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>}) by (<<.GroupBy>>)
-        nodeQuery: sum(container_memory_working_set_bytes{<<.LabelMatchers>>,id='/'}) by (<<.GroupBy>>)
-        resources:
-          overrides:
-            node:
-              resource: node
-            namespace:
-              resource: namespace
-            pod:
-              resource: pod
-        containerLabel: container
-      window: 1m
diff --git a/experimental/custom-metrics-api/deploy.sh b/experimental/custom-metrics-api/deploy.sh
deleted file mode 100644
index d276afc0..00000000
--- a/experimental/custom-metrics-api/deploy.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-kubectl apply -n monitoring -f custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
-kubectl apply -n monitoring -f custom-metrics-apiservice.yaml
-kubectl apply -n monitoring -f custom-metrics-cluster-role.yaml
-kubectl apply -n monitoring -f custom-metrics-configmap.yaml
-kubectl apply -n monitoring -f hpa-custom-metrics-cluster-role-binding.yaml
diff --git a/experimental/custom-metrics-api/hpa-custom-metrics-cluster-role-binding.yaml b/experimental/custom-metrics-api/hpa-custom-metrics-cluster-role-binding.yaml
deleted file mode 100644
index 530ebea5..00000000
--- a/experimental/custom-metrics-api/hpa-custom-metrics-cluster-role-binding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1beta1
-kind: ClusterRoleBinding
-metadata:
-  name: hpa-controller-custom-metrics
-roleRef:
-  apiGroup: rbac.authorization.k8s.io
-  kind: ClusterRole
-  name: custom-metrics-server-resources
-subjects:
-- kind: ServiceAccount
-  name: horizontal-pod-autoscaler
-  namespace: kube-system
diff --git a/experimental/custom-metrics-api/sample-app.yaml b/experimental/custom-metrics-api/sample-app.yaml
deleted file mode 100644
index 470887c6..00000000
--- a/experimental/custom-metrics-api/sample-app.yaml
+++ /dev/null
@@ -1,67 +0,0 @@
-kind: ServiceMonitor
-apiVersion: monitoring.coreos.com/v1
-metadata:
-  name: sample-app
-  labels:
-    app: sample-app
-spec:
-  selector:
-    matchLabels:
-      app: sample-app
-  endpoints: 
-  - port: http
-    interval: 5s
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: sample-app
-  labels:
-    app: sample-app
-spec:
-  ports:
-  - name: http
-    port: 8080
-    targetPort: 8080
-  selector:
-    app: sample-app
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: sample-app
-  labels:
-    app: sample-app
-spec:
-  replicas: 1
-  selector:
-    matchLabels:
-      app: sample-app
-  template:
-    metadata:
-      labels:
-        app: sample-app
-    spec:
-      containers:
-      - image: luxas/autoscale-demo:v0.1.2
-        name: metrics-provider
-        ports:
-        - name: http
-          containerPort: 8080
----
-kind: HorizontalPodAutoscaler
-apiVersion: autoscaling/v2beta1
-metadata:
-  name: sample-app
-spec:
-  scaleTargetRef:
-    apiVersion: apps/v1
-    kind: Deployment
-    name: sample-app
-  minReplicas: 1
-  maxReplicas: 10
-  metrics:
-  - type: Pods
-    pods:
-      metricName: http_requests
-      targetAverageValue: 500m
diff --git a/experimental/custom-metrics-api/teardown.sh b/experimental/custom-metrics-api/teardown.sh
deleted file mode 100644
index b3a455f5..00000000
--- a/experimental/custom-metrics-api/teardown.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env bash
-
-kubectl delete -n monitoring -f custom-metrics-apiserver-resource-reader-cluster-role-binding.yaml
-kubectl delete -n monitoring -f custom-metrics-apiservice.yaml
-kubectl delete -n monitoring -f custom-metrics-cluster-role.yaml
-kubectl delete -n monitoring -f custom-metrics-configmap.yaml
-kubectl delete -n monitoring -f hpa-custom-metrics-cluster-role-binding.yaml
diff --git a/jsonnet/kube-prometheus/kube-prometheus-custom-metrics.libsonnet b/jsonnet/kube-prometheus/kube-prometheus-custom-metrics.libsonnet
new file mode 100644
index 00000000..479a7ee5
--- /dev/null
+++ b/jsonnet/kube-prometheus/kube-prometheus-custom-metrics.libsonnet
@@ -0,0 +1,179 @@
+local k = import 'ksonnet/ksonnet.beta.4/k.libsonnet';
+
+// Custom metrics API allows the HPA v2 to scale based on arbirary metrics.
+// For more details on usage visit https://github.com/DirectXMan12/k8s-prometheus-adapter#quick-links
+
+{
+  _config+:: {
+    prometheusAdapter+:: {
+      // Rules for custom-metrics
+      config+:: {
+        rules+: [
+          {
+            seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}',
+            seriesFilters: [],
+            resources: {
+              overrides: {
+                namespace: {
+                  resource: 'namespace'
+                },
+                pod: {
+                  resource: 'pod'
+                }
+              },
+            },
+            name: {
+              matches: '^container_(.*)_seconds_total$',
+              as: ""
+            },
+            metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>)'
+          },
+          {
+            seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}',
+            seriesFilters: [
+              { isNot: '^container_.*_seconds_total$' },
+            ],
+            resources: {
+              overrides: {
+                namespace: {
+                  resource: 'namespace'
+                },
+                pod: {
+                  resource: 'pod'
+                }
+              },
+            },
+            name: {
+              matches: '^container_(.*)_total$',
+              as: ''
+            },
+            metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[1m])) by (<<.GroupBy>>)'
+          },
+          {
+            seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}',
+            seriesFilters: [
+              { isNot: '^container_.*_total$' },
+            ],
+            resources: {
+              overrides: {
+                namespace: {
+                  resource: 'namespace'
+                },
+                pod: {
+                  resource: 'pod'
+                }
+              },
+            },
+            name: {
+              matches: '^container_(.*)$',
+              as: ''
+            },
+            metricsQuery: 'sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>)'
+          },
+          {
+            seriesQuery: '{namespace!="",__name__!~"^container_.*"}',
+            seriesFilters: [
+              { isNot: '.*_total$' },
+            ],
+            resources: {
+              template: '<<.Resource>>'
+            },
+            name: {
+              matches: '',
+              as: ''
+            },
+            metricsQuery: 'sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>)'
+          },
+          {
+            seriesQuery: '{namespace!="",__name__!~"^container_.*"}',
+            seriesFilters: [
+              { isNot: '.*_seconds_total' },
+            ],
+            resources: {
+              template: '<<.Resource>>'
+            },
+            name: {
+              matches: '^(.*)_total$',
+              as: ''
+            },
+            metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'
+          },
+          {
+            seriesQuery: '{namespace!="",__name__!~"^container_.*"}',
+            seriesFilters: [],
+            resources: {
+              template: '<<.Resource>>'
+            },
+            name: {
+              matches: '^(.*)_seconds_total$',
+              as: ''
+            },
+            metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[1m])) by (<<.GroupBy>>)'
+          }
+        ],
+      },
+    },
+  },
+
+  prometheusAdapter+:: {
+    customMetricsApiService: {
+      apiVersion: 'apiregistration.k8s.io/v1',
+      kind: 'APIService',
+      metadata: {
+        name: 'v1beta1.custom.metrics.k8s.io',
+      },
+      spec: {
+        service: {
+          name: $.prometheusAdapter.service.metadata.name,
+          namespace: $._config.namespace,
+        },
+        group: 'custom.metrics.k8s.io',
+        version: 'v1beta1',
+        insecureSkipTLSVerify: true,
+        groupPriorityMinimum: 100,
+        versionPriority: 100,
+      },
+    },
+    customMetricsClusterRoleServerResources:
+      local clusterRole = k.rbac.v1.clusterRole;
+      local policyRule = clusterRole.rulesType;
+
+      local rules =
+        policyRule.new() +
+        policyRule.withApiGroups(['custom.metrics.k8s.io']) +
+        policyRule.withResources(['*']) +
+        policyRule.withVerbs(['*']);
+
+      clusterRole.new() +
+      clusterRole.mixin.metadata.withName('custom-metrics-server-resources') +
+      clusterRole.withRules(rules),
+
+    customMetricsClusterRoleBindingServerResources:
+      local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+      clusterRoleBinding.new() +
+      clusterRoleBinding.mixin.metadata.withName('custom-metrics-server-resources') +
+      clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') +
+      clusterRoleBinding.mixin.roleRef.withName('custom-metrics-server-resources') +
+      clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' }) +
+      clusterRoleBinding.withSubjects([{
+        kind: 'ServiceAccount',
+        name: $.prometheusAdapter.serviceAccount.metadata.name,
+        namespace: $._config.namespace,
+      }]),
+
+    customMetricsClusterRoleBindingHPA:
+      local clusterRoleBinding = k.rbac.v1.clusterRoleBinding;
+
+      clusterRoleBinding.new() +
+      clusterRoleBinding.mixin.metadata.withName('hpa-controller-custom-metrics') +
+      clusterRoleBinding.mixin.roleRef.withApiGroup('rbac.authorization.k8s.io') +
+      clusterRoleBinding.mixin.roleRef.withName('custom-metrics-server-resources') +
+      clusterRoleBinding.mixin.roleRef.mixinInstance({ kind: 'ClusterRole' }) +
+      clusterRoleBinding.withSubjects([{
+        kind: 'ServiceAccount',
+        name: 'horizontal-pod-autoscaler',
+        namespace: 'kube-system',
+      }]),
+  }
+}
-- 
GitLab