Skip to content

feat(helm): add metrics endpoint and optional ServiceMonitor support - #1802

Closed
moezdil wants to merge 4 commits into
kagent-dev:mainfrom
moezdil:feat/helm-metrics-servicemonitor
Closed

moezdil wants to merge 4 commits into
kagent-dev:mainfrom
moezdil:feat/helm-metrics-servicemonitor

Conversation

@moezdil

@moezdil moezdil commented May 5, 2026 •

Copy link
Copy Markdown
Contributor

Revives #1435 which was closed by stalebot. The controller already supports METRICS_BIND_ADDRESS and METRICS_SECURE via flags, this just wires them up properly in the chart.

When controller.metrics.enabled is true the chart sets the env vars, exposes the metrics port on the Deployment, creates a dedicated internal ClusterIP Service for metrics (separate from the main controller Service), and optionally creates a ServiceMonitor for Prometheus Operator.

The metrics port is served over HTTPS with authn/authz by default (secure: true), matching the controller binary default. Set secure: false for plain HTTP scraping.

Usage:
```yaml
controller:
metrics:
enabled: true
port: 9093
secure: true
serviceMonitor:
enabled: true
labels:
release: prometheus
```

Closes #1369

Copilot AI review requested due to automatic review settings May 5, 2026 19:29
@github-actions github-actions Bot added the enhancement New feature or request label May 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Helm-chart support for exposing the controller’s existing metrics endpoint and optionally creating a Prometheus Operator ServiceMonitor, so observability can be enabled from chart values instead of manual env/service customization.

Changes:

  • Adds controller.metrics values for enabling metrics, choosing the port, configuring secure mode, and toggling ServiceMonitor creation.
  • Wires metrics settings into the controller ConfigMap, Deployment, and Service so the endpoint is exposed when enabled.
  • Adds Helm unit tests covering Service, Deployment, and ServiceMonitor rendering for the new metrics options.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
helm/kagent/values.yaml Adds chart values for controller metrics and ServiceMonitor settings.
helm/kagent/tests/controller-servicemonitor_test.yaml Adds render tests for the new ServiceMonitor template.
helm/kagent/tests/controller-service_test.yaml Verifies the controller Service adds a metrics port when enabled.
helm/kagent/tests/controller-deployment_test.yaml Verifies the controller Deployment/ConfigMap pick up metrics ports and env vars.
helm/kagent/templates/controller-servicemonitor.yaml Introduces the optional Prometheus Operator ServiceMonitor.
helm/kagent/templates/controller-service.yaml Exposes the metrics port on the controller Service.
helm/kagent/templates/controller-deployment.yaml Exposes the metrics port on the controller container.
helm/kagent/templates/controller-configmap.yaml Sets metrics-related env vars consumed by the controller.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,20 @@
{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.serviceMonitor.enabled }}
Comment on lines +17 to +19
- port: metrics
interval: {{ .Values.controller.metrics.serviceMonitor.interval }}
scrapeTimeout: {{ .Values.controller.metrics.serviceMonitor.scrapeTimeout }}
Comment thread helm/kagent/values.yaml Outdated
metrics:
enabled: false
port: 9093
secure: false
Comment on lines +15 to +19
{{- if .Values.controller.metrics.enabled }}
- port: {{ .Values.controller.metrics.port }}
targetPort: {{ .Values.controller.metrics.port }}
protocol: TCP
name: metrics

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this comment, I think we need a separate internal service for this.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 5, 2026
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from 47384db to 2008de2 Compare May 5, 2026 19:49
@danielorbach

danielorbach commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

Hey — I've put up an alternative shape for #1369 in #1803. The main substantive difference is RBAC: the controller binary defaults --metrics-secure=true, which engages controller-runtime's WithAuthenticationAndAuthorization filter on /metrics. That filter calls TokenReview and SubjectAccessReview against the API server for every scrape, so the controller's ServiceAccount needs create rights on authentication.k8s.io/tokenreviews and authorization.k8s.io/subjectaccessreviews. As things stand here, enabling metrics with secure-serving on (the default) returns 5xx on every scrape because those rights aren't granted, and there's no unbound metrics-reader ClusterRole for cluster operators to bind to their scraper's ServiceAccount.

The kubebuilder/operator-sdk default — and what the kmcp sub-chart already shipped in this same umbrella does — is two ClusterRoles plus a single auth ClusterRoleBinding. That's the shape #1803 takes. It also uses a separate dedicated metrics Service rather than reusing the existing one, again matching kmcp. ServiceMonitor is deferred there.

Both shapes should solve #1369; happy to converge in either direction if maintainers have a preference.

@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from 5a3305c to eace68e Compare May 6, 2026 07:23

@EItanya EItanya left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this PR makes sense, however I do think we need a separate internal service for metrics so we don't expose them

@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch 2 times, most recently from 92a932a to 977620a Compare May 7, 2026 18:50
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels May 7, 2026
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from 7c7c0ab to c70f6eb Compare May 7, 2026 19:01
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch 2 times, most recently from 0f35b2e to d34e401 Compare May 11, 2026 19:03
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch 2 times, most recently from c40bed7 to 1537799 Compare May 15, 2026 11:01
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from b5debe1 to 6d24a3d Compare May 22, 2026 15:58
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from b8ae8c5 to f3b587d Compare June 4, 2026 14:32
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch 3 times, most recently from 05be69a to 3c56e26 Compare June 8, 2026 17:26
@moezdil moezdil changed the title feat(helm): add metrics endpoint and optional ServiceMonitor support feat(observability): add configurable grafana.prometheusDatasourceName to agent chart Jun 15, 2026
@moezdil moezdil changed the title feat(observability): add configurable grafana.prometheusDatasourceName to agent chart feat(helm): add metrics endpoint and optional ServiceMonitor support Jun 15, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Jun 15, 2026
The controller already exposes /metrics via METRICS_BIND_ADDRESS and
METRICS_SECURE flags. This wires them up in the chart.

When controller.metrics.enabled is true:
- Sets METRICS_BIND_ADDRESS and METRICS_SECURE env vars
- Exposes the metrics port on the Deployment
- Creates a dedicated internal ClusterIP metrics Service
- Creates auth RBAC (TokenReview/SubjectAccessReview) gated on secure: true
- Creates an unbound metrics-reader ClusterRole for scraper SAs
- Optionally creates a ServiceMonitor (gated on Capabilities.APIVersions)

Defaults to port 8443, secure: true to match the controller binary default.

Closes #1369

Signed-off-by: mesutoezdil <[email protected]>
@moezdil
moezdil force-pushed the feat/helm-metrics-servicemonitor branch from 4ba3108 to ab72739 Compare June 17, 2026 17:16
@EItanya

EItanya commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Sorry, I really thought I responded 🙈

This was already done in 7fb3aa6?

@EItanya

EItanya commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

(I’ll set aside the question of why the other person did this and the ethical debate surrounding it).

I think the only solution here is a best 2/3 chess match 😆

@EItanya EItanya closed this Jun 18, 2026
@moezdil
moezdil deleted the feat/helm-metrics-servicemonitor branch June 18, 2026 13:56
pull Bot pushed a commit to zhaocongqi/kagent that referenced this pull request Sep 15, 2026
…agent-dev#2401)

## Description

This adds native
[ServiceMonitor](https://prometheus-operator.dev/docs/api-reference/api/#monitoring.coreos.com/v1.ServiceMonitor)
support to the kagent Helm chart so controller metrics are collected by
[Prometheus Operator](https://prometheus-operator.dev/) out of the box.

This is the follow up that
[kagent-dev#1803](kagent-dev#1803) deferred. That
PR landed the metrics Service and the scrape RBAC and closed
[kagent-dev#1369](kagent-dev#1369), but left the
ServiceMonitor out of scope.
[kagent-dev#1802](kagent-dev#1802) carried one and
was closed as a duplicate of kagent-dev#1803, so the ServiceMonitor half of kagent-dev#1369
was never reviewed on its own and no template for it exists in the chart
today. This PR is additive on top of what kagent-dev#1803 merged and changes none
of it.

Today controller.metrics.enabled provisions the metrics Service and the
ClusterRoles for authenticated scrapes, but not the resource that makes
Prometheus actually scrape them. Every user running
[kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)
has to hand write a ServiceMonitor outside the chart and keep its port
name and namespace in sync with the chart by hand. The bundled
[kagent-tools](https://github.com/kagent-dev/tools) subchart already
ships one, so this closes the gap for the controller.

New values live under controller.metrics.serviceMonitor, disabled by
default and gated on controller.metrics.enabled. Interval, scrape
timeout, honorLabels, relabelings, metric relabelings, extra labels,
annotations and a namespace override are exposed. With secure serving
on, the endpoint defaults to https with the ServiceAccount token and
insecureSkipVerify, which matches the self signed certificate the
controller serves, and both are overridable.

The metrics Service port name moved into a shared helper used by both
the Service and the ServiceMonitor endpoint, so the two cannot drift
when secure serving is flipped. Rendered output for existing installs is
unchanged.

## Changelog

Added an optional Prometheus Operator ServiceMonitor for the controller
metrics endpoint, configurable under controller.metrics.serviceMonitor.

## Testing

1. helm unittest helm/kagent passes with 298 tests, 15 of them new in
helm/kagent/tests/controller-servicemonitor_test.yaml.
2. Nothing renders unless both controller.metrics.enabled and
controller.metrics.serviceMonitor.enabled are set, and the bindAddress
disable sentinel still suppresses it.
3. Rendered the secure and plaintext variants with helm template, then
validated them against a live cluster with kubectl apply
--dry-run=server so the manifest is checked against the real
ServiceMonitor CRD rather than only the chart.

## Additional Notes

Rendering the ServiceMonitor does not authorize the scrape on its own.
With secure serving, the metrics reader ClusterRole still has to be
bound to the Prometheus ServiceAccount, which the values comment calls
out.

The chart does not gate on the monitoring.coreos.com API being present,
matching what kagent-tools does. The explicit opt in flag is the gate,
so a missing CRD fails loudly at install time instead of silently
dropping the resource during helm template.

---------

Signed-off-by: younsl <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Helm Chart: Add support for enabling metrics endpoint and optional ServiceMonitor

4 participants