From 212ba52e56d9b9481fe09df48837dc87ad1a18eb Mon Sep 17 00:00:00 2001 From: Ayush Date: Tue, 25 Aug 2026 11:12:23 +0530 Subject: [PATCH 1/2] feat(chart): add prometheus servicemonitor support --- .../templates/servicemonitor.yaml | 38 ++++++ .../tests/servicemonitor_test.yaml | 108 ++++++++++++++++++ charts/node-readiness-controller/values.yaml | 15 +++ 3 files changed, 161 insertions(+) create mode 100644 charts/node-readiness-controller/templates/servicemonitor.yaml create mode 100644 charts/node-readiness-controller/tests/servicemonitor_test.yaml diff --git a/charts/node-readiness-controller/templates/servicemonitor.yaml b/charts/node-readiness-controller/templates/servicemonitor.yaml new file mode 100644 index 00000000..d8884cad --- /dev/null +++ b/charts/node-readiness-controller/templates/servicemonitor.yaml @@ -0,0 +1,38 @@ +{{- if .Values.metrics.serviceMonitor.enabled }} +{{- if not .Values.metrics.enabled }} +{{- fail "You enabled metrics.serviceMonitor.enabled, but metrics.enabled is false. Please enable metrics to use the ServiceMonitor." }} +{{- end }} +{{- if .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "node-readiness-controller.fullname" . }} + namespace: {{ include "node-readiness-controller.namespace" . }} + labels: + {{- include "node-readiness-controller.labels" . | nindent 4 }} + {{- with .Values.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "node-readiness-controller.selectorLabels" . | nindent 6 }} + endpoints: + - port: {{ ternary "https" "http" .Values.metrics.secure }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- if .Values.metrics.secure }} + scheme: https + tlsConfig: + insecureSkipVerify: true + {{- end }} + {{- with .Values.metrics.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/node-readiness-controller/tests/servicemonitor_test.yaml b/charts/node-readiness-controller/tests/servicemonitor_test.yaml new file mode 100644 index 00000000..37061a1a --- /dev/null +++ b/charts/node-readiness-controller/tests/servicemonitor_test.yaml @@ -0,0 +1,108 @@ +suite: Test ServiceMonitor Template +templates: + - servicemonitor.yaml + +tests: + - it: does not render when metrics.enabled is false + set: + metrics: + enabled: false + serviceMonitor: + enabled: true + asserts: + - failedTemplate: + errorMessage: You enabled metrics.serviceMonitor.enabled, but metrics.enabled is false. Please enable metrics to use the ServiceMonitor. + + - it: does not render when metrics.serviceMonitor.enabled is false + set: + metrics: + enabled: true + serviceMonitor: + enabled: false + asserts: + - hasDocuments: + count: 0 + + # Note: testing .Capabilities.APIVersions.Has is not fully supported by helm-unittest, + # but assuming the environment supports it, we can test standard rendering. + + - it: renders correctly when both flags are true (assumes monitoring.coreos.com/v1 exists) + capabilities: + apiVersions: + - monitoring.coreos.com/v1 + set: + metrics: + enabled: true + serviceMonitor: + enabled: true + asserts: + - isKind: + of: ServiceMonitor + - equal: + path: apiVersion + value: monitoring.coreos.com/v1 + - equal: + path: spec.endpoints[0].port + value: http + - equal: + path: spec.endpoints[0].interval + value: 30s + - equal: + path: spec.endpoints[0].scrapeTimeout + value: 10s + + - it: uses https scheme and injects tlsConfig when metrics.secure is true + capabilities: + apiVersions: + - monitoring.coreos.com/v1 + set: + metrics: + enabled: true + secure: true + serviceMonitor: + enabled: true + asserts: + - equal: + path: spec.endpoints[0].port + value: https + - equal: + path: spec.endpoints[0].scheme + value: https + - equal: + path: spec.endpoints[0].tlsConfig.insecureSkipVerify + value: true + + - it: merges custom labels + capabilities: + apiVersions: + - monitoring.coreos.com/v1 + set: + metrics: + enabled: true + serviceMonitor: + enabled: true + labels: + release: prometheus + asserts: + - equal: + path: metadata.labels.release + value: prometheus + + - it: applies custom interval and timeout + capabilities: + apiVersions: + - monitoring.coreos.com/v1 + set: + metrics: + enabled: true + serviceMonitor: + enabled: true + interval: 1m + scrapeTimeout: 30s + asserts: + - equal: + path: spec.endpoints[0].interval + value: 1m + - equal: + path: spec.endpoints[0].scrapeTimeout + value: 30s diff --git a/charts/node-readiness-controller/values.yaml b/charts/node-readiness-controller/values.yaml index 4a348e0c..9230dc8a 100644 --- a/charts/node-readiness-controller/values.yaml +++ b/charts/node-readiness-controller/values.yaml @@ -124,6 +124,21 @@ metrics: targetPort: 8443 certDir: /tmp/k8s-metrics-server/metrics-certs certSecretName: metrics-server-cert + # -- Prometheus Operator ServiceMonitor. + # Requires metrics.enabled=true and the Prometheus Operator CRD + # (monitoring.coreos.com/v1) to be installed in the cluster. + serviceMonitor: + enabled: false + # -- Additional labels for the ServiceMonitor (e.g. release: prometheus) + labels: {} + # -- Scrape interval + interval: 30s + # -- Scrape timeout + scrapeTimeout: 10s + # -- Metric relabeling configs + metricRelabelings: [] + # -- Relabeling configs + relabelings: [] # Webhook server configuration webhook: From 7bf6ccd2ec81f7d478ca1f8c4499a079ee6452e0 Mon Sep 17 00:00:00 2001 From: Ayush Date: Wed, 26 Aug 2026 01:17:32 +0530 Subject: [PATCH 2/2] address PR feedback for serviceMonitor configuration --- charts/node-readiness-controller/README.md | 10 ++++++++ .../templates/NOTES.txt | 24 +++++++++++++++++++ .../templates/servicemonitor.yaml | 9 ++++++- .../tests/servicemonitor_test.yaml | 19 ++++++++++++--- charts/node-readiness-controller/values.yaml | 7 ++++++ 5 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 charts/node-readiness-controller/templates/NOTES.txt diff --git a/charts/node-readiness-controller/README.md b/charts/node-readiness-controller/README.md index 60eddbfe..2b8b6aef 100644 --- a/charts/node-readiness-controller/README.md +++ b/charts/node-readiness-controller/README.md @@ -11,6 +11,8 @@ helm install my-release --namespace nrr-system --create-namespace ./charts/node- ``` > Published chart releases via `registry.k8s.io` OCI are WIP. +> +> **Note on Secure Metrics and ServiceMonitors:** If you enable secure metrics (`metrics.secure: true`), the Prometheus Operator requires RBAC permissions to scrape the `/metrics` endpoint. This Helm chart does *not* automatically create a `ClusterRoleBinding` for Prometheus. The cluster administrator must manually bind the `metrics-reader` ClusterRole (or equivalent) to the Prometheus ServiceAccount in their monitoring namespace. ## Introduction @@ -93,6 +95,14 @@ The following table lists the configurable parameters of the _node-readiness-con | `metrics.service.targetPort` | The target port for the metrics service | `8443` | | `metrics.certDir` | Directory for metrics server certificates | `/tmp/k8s-metrics-server/metrics-certs` | | `metrics.certSecretName` | Name of the secret containing metrics server certificates | `metrics-server-cert` | +| `metrics.serviceMonitor.enabled` | Deploy a Prometheus Operator ServiceMonitor to scrape metrics (requires `monitoring.coreos.com/v1` CRD installed) | `false` | +| `metrics.serviceMonitor.labels` | Additional labels for the ServiceMonitor | `{}` | +| `metrics.serviceMonitor.interval` | Scrape interval | `30s` | +| `metrics.serviceMonitor.scrapeTimeout` | Scrape timeout | `10s` | +| `metrics.serviceMonitor.bearerTokenFile` | Bearer token file for authenticating with secure metrics endpoints | `""` (defaults to Prometheus token) | +| `metrics.serviceMonitor.tlsConfig` | TLS configuration for scraping secure metrics (e.g. providing a `caFile`) | `{"insecureSkipVerify": true}` | +| `metrics.serviceMonitor.metricRelabelings`| Metric relabeling configs | `[]` | +| `metrics.serviceMonitor.relabelings` | Relabeling configs | `[]` | | `webhook.enabled` | Enable the webhook server | `false` | | `webhook.port` | The port for the webhook server | `9443` | | `webhook.service.port` | The port exposed by the webhook service | `443` | diff --git a/charts/node-readiness-controller/templates/NOTES.txt b/charts/node-readiness-controller/templates/NOTES.txt new file mode 100644 index 00000000..029aeec7 --- /dev/null +++ b/charts/node-readiness-controller/templates/NOTES.txt @@ -0,0 +1,24 @@ +Thanks for installing the {{ template "node-readiness-controller.fullname" . }} chart! + +To verify that the controller pods are running, execute: + kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "node-readiness-controller.name" . }} + +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +{{- if not (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") }} + +=================================================================================== +WARNING: Prometheus ServiceMonitor requested but CRD is missing! +=================================================================================== +You have enabled `metrics.serviceMonitor.enabled: true`, but the Kubernetes +API server does not report the `monitoring.coreos.com/v1` API as available. + +The ServiceMonitor resource was NOT created. + +If you are using offline rendering (e.g., `helm template`), this warning is +expected because Helm cannot detect cluster capabilities offline. You can +bypass this warning and force rendering by passing: + --api-versions "monitoring.coreos.com/v1" +=================================================================================== + +{{- end }} +{{- end }} diff --git a/charts/node-readiness-controller/templates/servicemonitor.yaml b/charts/node-readiness-controller/templates/servicemonitor.yaml index d8884cad..ca7e0b32 100644 --- a/charts/node-readiness-controller/templates/servicemonitor.yaml +++ b/charts/node-readiness-controller/templates/servicemonitor.yaml @@ -23,8 +23,15 @@ spec: scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} {{- if .Values.metrics.secure }} scheme: https + {{- if .Values.metrics.serviceMonitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.metrics.serviceMonitor.bearerTokenFile }} + {{- else }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- with .Values.metrics.serviceMonitor.tlsConfig }} tlsConfig: - insecureSkipVerify: true + {{- toYaml . | nindent 8 }} + {{- end }} {{- end }} {{- with .Values.metrics.serviceMonitor.metricRelabelings }} metricRelabelings: diff --git a/charts/node-readiness-controller/tests/servicemonitor_test.yaml b/charts/node-readiness-controller/tests/servicemonitor_test.yaml index 37061a1a..cd9772dd 100644 --- a/charts/node-readiness-controller/tests/servicemonitor_test.yaml +++ b/charts/node-readiness-controller/tests/servicemonitor_test.yaml @@ -23,8 +23,15 @@ tests: - hasDocuments: count: 0 - # Note: testing .Capabilities.APIVersions.Has is not fully supported by helm-unittest, - # but assuming the environment supports it, we can test standard rendering. + - it: does not render when monitoring.coreos.com/v1 capability is missing + set: + metrics: + enabled: true + serviceMonitor: + enabled: true + asserts: + - hasDocuments: + count: 0 - it: renders correctly when both flags are true (assumes monitoring.coreos.com/v1 exists) capabilities: @@ -51,7 +58,7 @@ tests: path: spec.endpoints[0].scrapeTimeout value: 10s - - it: uses https scheme and injects tlsConfig when metrics.secure is true + - it: uses https scheme, bearer token, and injects custom tlsConfig when secure is true capabilities: apiVersions: - monitoring.coreos.com/v1 @@ -61,6 +68,9 @@ tests: secure: true serviceMonitor: enabled: true + bearerTokenFile: /custom/path/to/token + tlsConfig: + insecureSkipVerify: true asserts: - equal: path: spec.endpoints[0].port @@ -68,6 +78,9 @@ tests: - equal: path: spec.endpoints[0].scheme value: https + - equal: + path: spec.endpoints[0].bearerTokenFile + value: /custom/path/to/token - equal: path: spec.endpoints[0].tlsConfig.insecureSkipVerify value: true diff --git a/charts/node-readiness-controller/values.yaml b/charts/node-readiness-controller/values.yaml index 9230dc8a..638f229f 100644 --- a/charts/node-readiness-controller/values.yaml +++ b/charts/node-readiness-controller/values.yaml @@ -135,6 +135,13 @@ metrics: interval: 30s # -- Scrape timeout scrapeTimeout: 10s + # -- Bearer token for scraping secure metrics + # Defaults to Prometheus's default token path if metrics.secure is true + bearerTokenFile: "" + # -- TLS configuration for scraping secure metrics + # e.g. providing a caFile, or setting insecureSkipVerify: false + tlsConfig: + insecureSkipVerify: true # -- Metric relabeling configs metricRelabelings: [] # -- Relabeling configs