Skip to content

Commit f3b587d

Browse files
committed
feat(helm): add metrics endpoint and optional ServiceMonitor support
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 <mesudozdil@gmail.com>
1 parent 8e390a6 commit f3b587d

12 files changed

Lines changed: 406 additions & 2 deletions

helm/kagent/templates/controller-configmap.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ data:
5656
STREAMING_MAX_BUF_SIZE: {{ .Values.controller.streaming.maxBufSize | quote }}
5757
STREAMING_TIMEOUT: {{ .Values.controller.streaming.timeout | quote }}
5858
WATCH_NAMESPACES: {{ include "kagent.watchNamespaces" . | quote }}
59+
{{- if .Values.controller.metrics.enabled }}
60+
METRICS_BIND_ADDRESS: ":{{ .Values.controller.metrics.port }}"
61+
METRICS_SECURE: {{ .Values.controller.metrics.secure | quote }}
62+
{{- end }}
5963
ZAP_LOG_LEVEL: {{ .Values.controller.loglevel | quote }}
6064
{{- $agentHost := "" }}
6165
{{- if and .Values.controller.agentDeployment .Values.controller.agentDeployment.host (not (eq .Values.controller.agentDeployment.host "")) }}

helm/kagent/templates/controller-deployment.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ spec:
133133
- name: http
134134
containerPort: {{ .Values.controller.service.ports.targetPort }}
135135
protocol: TCP
136+
{{- if .Values.controller.metrics.enabled }}
137+
- name: metrics
138+
containerPort: {{ .Values.controller.metrics.port }}
139+
protocol: TCP
140+
{{- end }}
136141
resources:
137142
{{- toYaml .Values.controller.resources | nindent 12 }}
138143
{{- with (.Values.controller.securityContext | default .Values.securityContext) }}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{{- if .Values.controller.metrics.enabled }}
2+
apiVersion: v1
3+
kind: Service
4+
metadata:
5+
name: {{ include "kagent.fullname" . }}-controller-metrics
6+
namespace: {{ include "kagent.namespace" . }}
7+
labels:
8+
{{- include "kagent.labels" . | nindent 4 }}
9+
app.kubernetes.io/component: controller-metrics
10+
spec:
11+
type: ClusterIP
12+
ports:
13+
- port: {{ .Values.controller.metrics.port }}
14+
targetPort: {{ .Values.controller.metrics.port }}
15+
protocol: TCP
16+
name: metrics
17+
selector:
18+
{{- include "kagent.controller.selectorLabels" . | nindent 4 }}
19+
{{- end }}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.serviceMonitor.enabled (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1/ServiceMonitor") }}
2+
apiVersion: monitoring.coreos.com/v1
3+
kind: ServiceMonitor
4+
metadata:
5+
name: {{ include "kagent.fullname" . }}-controller
6+
namespace: {{ include "kagent.namespace" . }}
7+
labels:
8+
{{- include "kagent.labels" . | nindent 4 }}
9+
{{- with .Values.controller.metrics.serviceMonitor.labels }}
10+
{{- toYaml . | nindent 4 }}
11+
{{- end }}
12+
spec:
13+
selector:
14+
matchLabels:
15+
{{- include "kagent.selectorLabels" . | nindent 6 }}
16+
app.kubernetes.io/component: controller-metrics
17+
endpoints:
18+
- port: metrics
19+
interval: {{ .Values.controller.metrics.serviceMonitor.interval }}
20+
scrapeTimeout: {{ .Values.controller.metrics.serviceMonitor.scrapeTimeout }}
21+
{{- if .Values.controller.metrics.secure }}
22+
scheme: https
23+
tlsConfig:
24+
insecureSkipVerify: true
25+
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
26+
{{- end }}
27+
{{- end }}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.secure }}
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: {{ include "kagent.fullname" . }}-metrics-auth-role
6+
labels:
7+
{{- include "kagent.labels" . | nindent 4 }}
8+
rules:
9+
- apiGroups: ["authentication.k8s.io"]
10+
resources: ["tokenreviews"]
11+
verbs: ["create"]
12+
- apiGroups: ["authorization.k8s.io"]
13+
resources: ["subjectaccessreviews"]
14+
verbs: ["create"]
15+
---
16+
apiVersion: rbac.authorization.k8s.io/v1
17+
kind: ClusterRoleBinding
18+
metadata:
19+
name: {{ include "kagent.fullname" . }}-metrics-auth-rolebinding
20+
labels:
21+
{{- include "kagent.labels" . | nindent 4 }}
22+
roleRef:
23+
apiGroup: rbac.authorization.k8s.io
24+
kind: ClusterRole
25+
name: {{ include "kagent.fullname" . }}-metrics-auth-role
26+
subjects:
27+
- kind: ServiceAccount
28+
name: {{ include "kagent.fullname" . }}-controller
29+
namespace: {{ include "kagent.namespace" . }}
30+
{{- end }}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{{- if .Values.controller.metrics.enabled }}
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
kind: ClusterRole
4+
metadata:
5+
name: {{ include "kagent.fullname" . }}-metrics-reader
6+
labels:
7+
{{- include "kagent.labels" . | nindent 4 }}
8+
rules:
9+
- nonResourceURLs: ["/metrics"]
10+
verbs: ["get"]
11+
{{- end }}

helm/kagent/tests/controller-deployment_test.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,29 @@ tests:
7676
- equal:
7777
path: spec.template.spec.containers[0].ports[0].containerPort
7878
value: 8083
79+
- lengthEqual:
80+
path: spec.template.spec.containers[0].ports
81+
count: 1
82+
83+
- it: should add metrics port and env vars when enabled
84+
set:
85+
controller.metrics.enabled: true
86+
asserts:
87+
- contains:
88+
path: spec.template.spec.containers[0].ports
89+
content:
90+
name: metrics
91+
containerPort: 8443
92+
protocol: TCP
93+
template: controller-deployment.yaml
94+
- equal:
95+
path: data.METRICS_BIND_ADDRESS
96+
value: ":8443"
97+
template: controller-configmap.yaml
98+
- equal:
99+
path: data.METRICS_SECURE
100+
value: "true"
101+
template: controller-configmap.yaml
79102

80103
- it: should set A2A_BASE_URL with computed default value
81104
template: controller-configmap.yaml
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
suite: test controller metrics service
2+
templates:
3+
- controller-metrics-service.yaml
4+
tests:
5+
- it: should not render by default
6+
asserts:
7+
- hasDocuments:
8+
count: 0
9+
10+
- it: should render when metrics enabled
11+
set:
12+
controller.metrics.enabled: true
13+
asserts:
14+
- hasDocuments:
15+
count: 1
16+
- isKind:
17+
of: Service
18+
19+
- it: should always be ClusterIP
20+
set:
21+
controller.metrics.enabled: true
22+
controller.service.type: NodePort
23+
asserts:
24+
- equal:
25+
path: spec.type
26+
value: ClusterIP
27+
28+
- it: should expose only the metrics port
29+
set:
30+
controller.metrics.enabled: true
31+
asserts:
32+
- lengthEqual:
33+
path: spec.ports
34+
count: 1
35+
- equal:
36+
path: spec.ports[0].name
37+
value: metrics
38+
- equal:
39+
path: spec.ports[0].port
40+
value: 8443
41+
- equal:
42+
path: spec.ports[0].targetPort
43+
value: 8443
44+
- equal:
45+
path: spec.ports[0].protocol
46+
value: TCP
47+
48+
- it: should have controller-metrics component label
49+
set:
50+
controller.metrics.enabled: true
51+
asserts:
52+
- equal:
53+
path: metadata.labels["app.kubernetes.io/component"]
54+
value: controller-metrics
55+
56+
- it: should use controller pod selector
57+
set:
58+
controller.metrics.enabled: true
59+
asserts:
60+
- equal:
61+
path: spec.selector["app.kubernetes.io/component"]
62+
value: controller
63+
64+
- it: should be in correct namespace
65+
set:
66+
controller.metrics.enabled: true
67+
asserts:
68+
- equal:
69+
path: metadata.namespace
70+
value: NAMESPACE
71+
72+
- it: should use custom namespace when overridden
73+
set:
74+
controller.metrics.enabled: true
75+
namespaceOverride: "custom-namespace"
76+
asserts:
77+
- equal:
78+
path: metadata.namespace
79+
value: custom-namespace

helm/kagent/tests/controller-service_test.yaml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ tests:
2929
- equal:
3030
path: spec.ports[0].protocol
3131
value: TCP
32+
- lengthEqual:
33+
path: spec.ports
34+
count: 1
3235

3336
- it: should have correct selector labels
3437
asserts:
@@ -68,4 +71,15 @@ tests:
6871
asserts:
6972
- equal:
7073
path: metadata.namespace
71-
value: custom-namespace
74+
value: custom-namespace
75+
76+
- it: should not expose metrics port on main service when metrics enabled
77+
set:
78+
controller.metrics.enabled: true
79+
asserts:
80+
- lengthEqual:
81+
path: spec.ports
82+
count: 1
83+
- equal:
84+
path: spec.ports[0].name
85+
value: controller
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
suite: test controller servicemonitor
2+
templates:
3+
- controller-servicemonitor.yaml
4+
tests:
5+
- it: should not render by default
6+
asserts:
7+
- hasDocuments:
8+
count: 0
9+
10+
- it: should not render when CRD is not installed
11+
set:
12+
controller.metrics.enabled: true
13+
controller.metrics.serviceMonitor.enabled: true
14+
asserts:
15+
- hasDocuments:
16+
count: 0
17+
18+
- it: should render ServiceMonitor when both enabled and CRD present
19+
set:
20+
controller.metrics.enabled: true
21+
controller.metrics.serviceMonitor.enabled: true
22+
capabilities:
23+
apiVersions:
24+
- monitoring.coreos.com/v1/ServiceMonitor
25+
asserts:
26+
- isKind:
27+
of: ServiceMonitor
28+
- equal:
29+
path: spec.endpoints[0].port
30+
value: metrics
31+
32+
- it: should target controller-metrics service via selector
33+
set:
34+
controller.metrics.enabled: true
35+
controller.metrics.serviceMonitor.enabled: true
36+
capabilities:
37+
apiVersions:
38+
- monitoring.coreos.com/v1/ServiceMonitor
39+
asserts:
40+
- equal:
41+
path: spec.selector.matchLabels["app.kubernetes.io/component"]
42+
value: controller-metrics
43+
44+
- it: should add TLS config and bearer token when secure is true
45+
set:
46+
controller.metrics.enabled: true
47+
controller.metrics.serviceMonitor.enabled: true
48+
controller.metrics.secure: true
49+
capabilities:
50+
apiVersions:
51+
- monitoring.coreos.com/v1/ServiceMonitor
52+
asserts:
53+
- equal:
54+
path: spec.endpoints[0].scheme
55+
value: https
56+
- equal:
57+
path: spec.endpoints[0].tlsConfig.insecureSkipVerify
58+
value: true
59+
- equal:
60+
path: spec.endpoints[0].bearerTokenFile
61+
value: /var/run/secrets/kubernetes.io/serviceaccount/token
62+
63+
- it: should not add TLS config or bearer token when secure is false
64+
set:
65+
controller.metrics.enabled: true
66+
controller.metrics.serviceMonitor.enabled: true
67+
controller.metrics.secure: false
68+
capabilities:
69+
apiVersions:
70+
- monitoring.coreos.com/v1/ServiceMonitor
71+
asserts:
72+
- isNull:
73+
path: spec.endpoints[0].scheme
74+
- isNull:
75+
path: spec.endpoints[0].tlsConfig
76+
- isNull:
77+
path: spec.endpoints[0].bearerTokenFile

0 commit comments

Comments
 (0)