Skip to content

Commit e6996e3

Browse files
authored
Added PodMonitor when using sidecar mode (#2404)
* Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> * Added PodMonitor when using sidecar mode Signed-off-by: Yuri Sa <[email protected]> --------- Signed-off-by: Yuri Sa <[email protected]>
1 parent 0ad467d commit e6996e3

18 files changed

+328
-27
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
2+
change_type: 'enhancement'
3+
4+
# The name of the component, or a single word describing the area of concern, (e.g. operator, target allocator, github action)
5+
component: operator
6+
7+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
8+
note: Create PodMonitor when deploying collector in sidecar mode and Prometheus exporters are used.
9+
10+
# One or more tracking issues related to the change
11+
issues: [2306]
12+
13+
# (Optional) One or more lines of additional information to render under the primary note.
14+
# These lines will be padded with 2 spaces and then inserted directly into the document.
15+
# Use pipe (|) for multiline entries.
16+
subtext:

apis/v1alpha1/opentelemetrycollector_types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ type PodDisruptionBudgetSpec struct {
483483

484484
// MetricsConfigSpec defines a metrics config.
485485
type MetricsConfigSpec struct {
486-
// EnableMetrics specifies if ServiceMonitor should be created for the OpenTelemetry Collector and Prometheus Exporters.
486+
// EnableMetrics specifies if ServiceMonitor or PodMonitor(for sidecar mode) should be created for the OpenTelemetry Collector and Prometheus Exporters.
487487
// The operator.observability.prometheus feature gate must be enabled to use this feature.
488488
//
489489
// +optional

bundle/manifests/opentelemetry-operator.clusterserviceversion.yaml

+6-4
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ metadata:
6565
categories: Logging & Tracing,Monitoring
6666
certified: "false"
6767
containerImage: ghcr.io/open-telemetry/opentelemetry-operator/opentelemetry-operator
68-
createdAt: "2023-11-17T13:24:32Z"
68+
createdAt: "2023-12-05T15:43:53Z"
6969
description: Provides the OpenTelemetry components, including the Collector
7070
operators.operatorframework.io/builder: operator-sdk-v1.29.0
7171
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
@@ -135,9 +135,10 @@ spec:
135135
- description: Metrics defines the metrics configuration for operands.
136136
displayName: Metrics Config
137137
path: observability.metrics
138-
- description: EnableMetrics specifies if ServiceMonitor should be created for
139-
the OpenTelemetry Collector and Prometheus Exporters. The operator.observability.prometheus
140-
feature gate must be enabled to use this feature.
138+
- description: EnableMetrics specifies if ServiceMonitor or PodMonitor(for sidecar
139+
mode) should be created for the OpenTelemetry Collector and Prometheus Exporters.
140+
The operator.observability.prometheus feature gate must be enabled to use
141+
this feature.
141142
displayName: Create ServiceMonitors for OpenTelemetry Collector
142143
path: observability.metrics.enableMetrics
143144
version: v1alpha1
@@ -233,6 +234,7 @@ spec:
233234
- apiGroups:
234235
- monitoring.coreos.com
235236
resources:
237+
- podmonitors
236238
- servicemonitors
237239
verbs:
238240
- create

bundle/manifests/opentelemetry.io_opentelemetrycollectors.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -3707,9 +3707,9 @@ spec:
37073707
description: Metrics defines the metrics configuration for operands.
37083708
properties:
37093709
enableMetrics:
3710-
description: EnableMetrics specifies if ServiceMonitor should
3711-
be created for the OpenTelemetry Collector and Prometheus
3712-
Exporters. The operator.observability.
3710+
description: EnableMetrics specifies if ServiceMonitor or
3711+
PodMonitor(for sidecar mode) should be created for the OpenTelemetry
3712+
Collector and Prometheus Exporters. The operator.observability.
37133713
type: boolean
37143714
type: object
37153715
type: object

config/crd/bases/opentelemetry.io_opentelemetrycollectors.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -3704,9 +3704,9 @@ spec:
37043704
description: Metrics defines the metrics configuration for operands.
37053705
properties:
37063706
enableMetrics:
3707-
description: EnableMetrics specifies if ServiceMonitor should
3708-
be created for the OpenTelemetry Collector and Prometheus
3709-
Exporters. The operator.observability.
3707+
description: EnableMetrics specifies if ServiceMonitor or
3708+
PodMonitor(for sidecar mode) should be created for the OpenTelemetry
3709+
Collector and Prometheus Exporters. The operator.observability.
37103710
type: boolean
37113711
type: object
37123712
type: object

config/manifests/bases/opentelemetry-operator.clusterserviceversion.yaml

+4-3
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ spec:
8181
- description: Metrics defines the metrics configuration for operands.
8282
displayName: Metrics Config
8383
path: observability.metrics
84-
- description: EnableMetrics specifies if ServiceMonitor should be created for
85-
the OpenTelemetry Collector and Prometheus Exporters. The operator.observability.prometheus
86-
feature gate must be enabled to use this feature.
84+
- description: EnableMetrics specifies if ServiceMonitor or PodMonitor(for sidecar
85+
mode) should be created for the OpenTelemetry Collector and Prometheus Exporters.
86+
The operator.observability.prometheus feature gate must be enabled to use
87+
this feature.
8788
displayName: Create ServiceMonitors for OpenTelemetry Collector
8889
path: observability.metrics.enableMetrics
8990
version: v1alpha1

config/rbac/role.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ rules:
7979
- apiGroups:
8080
- monitoring.coreos.com
8181
resources:
82+
- podmonitors
8283
- servicemonitors
8384
verbs:
8485
- create

controllers/opentelemetrycollector_controller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func NewReconciler(p Params) *OpenTelemetryCollectorReconciler {
8484
// +kubebuilder:rbac:groups=autoscaling,resources=horizontalpodautoscalers,verbs=get;list;watch;create;update;patch;delete
8585
// +kubebuilder:rbac:groups=policy,resources=poddisruptionbudgets,verbs=get;list;watch;create;update;patch;delete
8686
// +kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;list;create;update
87-
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;create;update;patch;delete
87+
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors;podmonitors,verbs=get;list;watch;create;update;patch;delete
8888
// +kubebuilder:rbac:groups=networking.k8s.io,resources=ingresses,verbs=get;list;watch;create;update;patch;delete
8989
// +kubebuilder:rbac:groups=route.openshift.io,resources=routes;routes/custom-host,verbs=get;list;watch;create;update;patch;delete
9090
// +kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=get;list;watch;update;patch
@@ -142,6 +142,7 @@ func (r *OpenTelemetryCollectorReconciler) SetupWithManager(mgr ctrl.Manager) er
142142

143143
if featuregate.PrometheusOperatorIsAvailable.IsEnabled() {
144144
builder.Owns(&monitoringv1.ServiceMonitor{})
145+
builder.Owns(&monitoringv1.PodMonitor{})
145146
}
146147

147148
return builder.Complete(r)

docs/api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17287,7 +17287,7 @@ Metrics defines the metrics configuration for operands.
1728717287
<td><b>enableMetrics</b></td>
1728817288
<td>boolean</td>
1728917289
<td>
17290-
EnableMetrics specifies if ServiceMonitor should be created for the OpenTelemetry Collector and Prometheus Exporters. The operator.observability.<br/>
17290+
EnableMetrics specifies if ServiceMonitor or PodMonitor(for sidecar mode) should be created for the OpenTelemetry Collector and Prometheus Exporters. The operator.observability.<br/>
1729117291
</td>
1729217292
<td>false</td>
1729317293
</tr></tbody>

internal/manifests/collector/collector.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ func Build(params manifests.Params) ([]client.Object, error) {
5252
manifests.Factory(Ingress),
5353
}...)
5454
if params.OtelCol.Spec.Observability.Metrics.EnableMetrics && featuregate.PrometheusOperatorIsAvailable.IsEnabled() {
55-
manifestFactories = append(manifestFactories, manifests.Factory(ServiceMonitor))
55+
if params.OtelCol.Spec.Mode == v1alpha1.ModeSidecar {
56+
manifestFactories = append(manifestFactories, manifests.Factory(PodMonitor))
57+
} else {
58+
manifestFactories = append(manifestFactories, manifests.Factory(ServiceMonitor))
59+
}
5660
}
5761
for _, factory := range manifestFactories {
5862
res, err := factory(params)
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package collector
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
21+
"github.com/go-logr/logr"
22+
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
23+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24+
25+
"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
26+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
27+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests/collector/adapters"
28+
"github.com/open-telemetry/opentelemetry-operator/internal/naming"
29+
)
30+
31+
// ServiceMonitor returns the service monitor for the given instance.
32+
func PodMonitor(params manifests.Params) (*monitoringv1.PodMonitor, error) {
33+
if !params.OtelCol.Spec.Observability.Metrics.EnableMetrics {
34+
params.Log.V(2).Info("Metrics disabled for this OTEL Collector",
35+
"params.OtelCol.name", params.OtelCol.Name,
36+
"params.OtelCol.namespace", params.OtelCol.Namespace,
37+
)
38+
return nil, nil
39+
}
40+
var pm monitoringv1.PodMonitor
41+
42+
if params.OtelCol.Spec.Mode != v1alpha1.ModeSidecar {
43+
return nil, nil
44+
}
45+
46+
pm = monitoringv1.PodMonitor{
47+
ObjectMeta: metav1.ObjectMeta{
48+
Namespace: params.OtelCol.Namespace,
49+
Name: naming.PodMonitor(params.OtelCol.Name),
50+
Labels: map[string]string{
51+
"app.kubernetes.io/name": naming.PodMonitor(params.OtelCol.Name),
52+
"app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name),
53+
"app.kubernetes.io/managed-by": "opentelemetry-operator",
54+
},
55+
},
56+
Spec: monitoringv1.PodMonitorSpec{
57+
JobLabel: "app.kubernetes.io/instance",
58+
PodTargetLabels: []string{"app.kubernetes.io/name", "app.kubernetes.io/instance", "app.kubernetes.io/managed-by"},
59+
NamespaceSelector: monitoringv1.NamespaceSelector{
60+
MatchNames: []string{params.OtelCol.Namespace},
61+
},
62+
Selector: metav1.LabelSelector{
63+
MatchLabels: map[string]string{
64+
"app.kubernetes.io/managed-by": "opentelemetry-operator",
65+
"app.kubernetes.io/instance": fmt.Sprintf("%s.%s", params.OtelCol.Namespace, params.OtelCol.Name),
66+
},
67+
},
68+
PodMetricsEndpoints: append(
69+
[]monitoringv1.PodMetricsEndpoint{
70+
{
71+
Port: "monitoring",
72+
},
73+
}, metricsEndpointsFromConfig(params.Log, params.OtelCol)...),
74+
},
75+
}
76+
77+
return &pm, nil
78+
}
79+
80+
func metricsEndpointsFromConfig(logger logr.Logger, otelcol v1alpha1.OpenTelemetryCollector) []monitoringv1.PodMetricsEndpoint {
81+
config, err := adapters.ConfigFromString(otelcol.Spec.Config)
82+
if err != nil {
83+
logger.V(2).Error(err, "Error while parsing the configuration")
84+
return []monitoringv1.PodMetricsEndpoint{}
85+
}
86+
exporterPorts, err := adapters.ConfigToComponentPorts(logger, adapters.ComponentTypeExporter, config)
87+
if err != nil {
88+
logger.Error(err, "couldn't build endpoints to podMonitors from configuration")
89+
return []monitoringv1.PodMetricsEndpoint{}
90+
}
91+
metricsEndpoints := []monitoringv1.PodMetricsEndpoint{}
92+
for _, port := range exporterPorts {
93+
if strings.Contains(port.Name, "prometheus") {
94+
e := monitoringv1.PodMetricsEndpoint{
95+
Port: port.Name,
96+
}
97+
metricsEndpoints = append(metricsEndpoints, e)
98+
}
99+
}
100+
return metricsEndpoints
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package collector
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
21+
"github.com/open-telemetry/opentelemetry-operator/internal/manifests"
22+
23+
"github.com/stretchr/testify/assert"
24+
25+
"testing"
26+
)
27+
28+
func sidecarParams() manifests.Params {
29+
return paramsWithMode(v1alpha1.ModeSidecar)
30+
}
31+
32+
func TestDesiredPodMonitors(t *testing.T) {
33+
params := sidecarParams()
34+
35+
actual, err := PodMonitor(params)
36+
assert.NoError(t, err)
37+
assert.Nil(t, actual)
38+
39+
params.OtelCol.Spec.Observability.Metrics.EnableMetrics = true
40+
actual, err = PodMonitor(params)
41+
assert.NoError(t, err)
42+
assert.NotNil(t, actual)
43+
assert.Equal(t, fmt.Sprintf("%s-collector", params.OtelCol.Name), actual.Name)
44+
assert.Equal(t, params.OtelCol.Namespace, actual.Namespace)
45+
assert.Equal(t, "monitoring", actual.Spec.PodMetricsEndpoints[0].Port)
46+
47+
params, err = newParams("", "testdata/prometheus-exporter.yaml")
48+
assert.NoError(t, err)
49+
params.OtelCol.Spec.Mode = v1alpha1.ModeSidecar
50+
params.OtelCol.Spec.Observability.Metrics.EnableMetrics = true
51+
actual, err = PodMonitor(params)
52+
assert.NoError(t, err)
53+
assert.NotNil(t, actual)
54+
assert.Equal(t, fmt.Sprintf("%s-collector", params.OtelCol.Name), actual.Name)
55+
assert.Equal(t, params.OtelCol.Namespace, actual.Namespace)
56+
assert.Equal(t, "monitoring", actual.Spec.PodMetricsEndpoints[0].Port)
57+
assert.Equal(t, "prometheus-dev", actual.Spec.PodMetricsEndpoints[1].Port)
58+
assert.Equal(t, "prometheus-prod", actual.Spec.PodMetricsEndpoints[2].Port)
59+
}

internal/manifests/collector/servicemonitor.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ func ServiceMonitor(params manifests.Params) (*monitoringv1.ServiceMonitor, erro
3737
)
3838
return nil, nil
3939
}
40+
var sm monitoringv1.ServiceMonitor
4041

41-
sm := monitoringv1.ServiceMonitor{
42+
if params.OtelCol.Spec.Mode == v1alpha1.ModeSidecar {
43+
return nil, nil
44+
}
45+
sm = monitoringv1.ServiceMonitor{
4246
ObjectMeta: metav1.ObjectMeta{
4347
Namespace: params.OtelCol.Namespace,
4448
Name: naming.ServiceMonitor(params.OtelCol.Name),
@@ -49,7 +53,11 @@ func ServiceMonitor(params manifests.Params) (*monitoringv1.ServiceMonitor, erro
4953
},
5054
},
5155
Spec: monitoringv1.ServiceMonitorSpec{
52-
Endpoints: []monitoringv1.Endpoint{},
56+
Endpoints: append([]monitoringv1.Endpoint{
57+
{
58+
Port: "monitoring",
59+
},
60+
}, endpointsFromConfig(params.Log, params.OtelCol)...),
5361
NamespaceSelector: monitoringv1.NamespaceSelector{
5462
MatchNames: []string{params.OtelCol.Namespace},
5563
},
@@ -62,13 +70,6 @@ func ServiceMonitor(params manifests.Params) (*monitoringv1.ServiceMonitor, erro
6270
},
6371
}
6472

65-
endpoints := []monitoringv1.Endpoint{
66-
{
67-
Port: "monitoring",
68-
},
69-
}
70-
71-
sm.Spec.Endpoints = append(endpoints, endpointsFromConfig(params.Log, params.OtelCol)...)
7273
return &sm, nil
7374
}
7475

internal/manifests/mutate.go

+11
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ func MutateFuncFor(existing, desired client.Object) controllerutil.MutateFn {
136136
wantSvcMonitor := desired.(*monitoringv1.ServiceMonitor)
137137
mutateServiceMonitor(svcMonitor, wantSvcMonitor)
138138

139+
case *monitoringv1.PodMonitor:
140+
podMonitor := existing.(*monitoringv1.PodMonitor)
141+
wantPodMonitor := desired.(*monitoringv1.PodMonitor)
142+
mutatePodMonitor(podMonitor, wantPodMonitor)
143+
139144
case *networkingv1.Ingress:
140145
ing := existing.(*networkingv1.Ingress)
141146
wantIng := desired.(*networkingv1.Ingress)
@@ -245,6 +250,12 @@ func mutateServiceMonitor(existing, desired *monitoringv1.ServiceMonitor) {
245250
existing.Spec = desired.Spec
246251
}
247252

253+
func mutatePodMonitor(existing, desired *monitoringv1.PodMonitor) {
254+
existing.Annotations = desired.Annotations
255+
existing.Labels = desired.Labels
256+
existing.Spec = desired.Spec
257+
}
258+
248259
func mutateService(existing, desired *corev1.Service) error {
249260
existing.Spec.Ports = desired.Spec.Ports
250261
if err := mergeWithOverride(&existing.Spec.Selector, desired.Spec.Selector); err != nil {

internal/naming/main.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,16 @@ func ServiceAccount(otelcol string) string {
140140
return DNSName(Truncate("%s-collector", 63, otelcol))
141141
}
142142

143-
// ServiceMonitor builds the service account name based on the instance.
143+
// ServiceMonitor builds the service Monitor name based on the instance.
144144
func ServiceMonitor(otelcol string) string {
145145
return DNSName(Truncate("%s-collector", 63, otelcol))
146146
}
147147

148+
// PodMonitor builds the pod Monitor name based on the instance.
149+
func PodMonitor(otelcol string) string {
150+
return DNSName(Truncate("%s-collector", 63, otelcol))
151+
}
152+
148153
// TargetAllocatorServiceAccount returns the TargetAllocator service account resource name.
149154
func TargetAllocatorServiceAccount(otelcol string) string {
150155
return DNSName(Truncate("%s-targetallocator", 63, otelcol))

0 commit comments

Comments
 (0)