Skip to content

Commit 2de00fd

Browse files
committed
feat(metrics): setup prometheus exporter and export manager metrics
1 parent 31b91f2 commit 2de00fd

File tree

8 files changed

+146
-3
lines changed

8 files changed

+146
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ build: manifests generate fmt vet ## Build manager binary.
102102

103103
.PHONY: run
104104
run: manifests generate fmt vet ## Run a controller from your host.
105-
go run ./cmd/main.go
105+
go run ./cmd/main.go ${ARGS}
106106

107107
# If you wish to build the manager image targeting other platforms you can use the --platform flag.
108108
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/alitto/pond/v2"
2525
kuikv1alpha1 "github.com/enix/kube-image-keeper/api/kuik/v1alpha1"
26+
"github.com/enix/kube-image-keeper/internal/controller"
2627
corecontroller "github.com/enix/kube-image-keeper/internal/controller/core"
2728
kuikcontroller "github.com/enix/kube-image-keeper/internal/controller/kuik"
2829
// +kubebuilder:scaffold:imports
@@ -238,6 +239,8 @@ func main() {
238239
os.Exit(1)
239240
}
240241

242+
controller.Metrics.Register(mgr.Elected())
243+
241244
setupLog.Info("starting manager")
242245
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
243246
setupLog.Error(err, "problem running manager")

helm/kube-image-keeper/templates/controller-deployment.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ spec:
5454
{{- end }}
5555
- name: no_proxy
5656
value: {{ join "," (prepend $noProxy (printf "%s-registry" (include "kube-image-keeper.fullname" .))) }}
57+
ports:
58+
- containerPort: 8080
59+
name: metrics
60+
protocol: TCP
5761
{{- with .Values.manager.readinessProbe }}
5862
readinessProbe:
5963
{{- toYaml . | nindent 12 }}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{{- if .Values.manager.podMonitor.create }}
2+
apiVersion: monitoring.coreos.com/v1
3+
kind: PodMonitor
4+
metadata:
5+
name: {{ include "kube-image-keeper.fullname" . }}-manager
6+
labels:
7+
{{- include "kube-image-keeper.manager-labels" . | nindent 4 }}
8+
{{- with .Values.manager.podMonitor.extraLabels }}
9+
{{- . | toYaml | trim | nindent 4 }}
10+
{{- end }}
11+
spec:
12+
selector:
13+
matchLabels:
14+
{{- include "kube-image-keeper.manager-selectorLabels" . | nindent 6 }}
15+
podMetricsEndpoints:
16+
- port: metrics
17+
interval: {{ .Values.manager.podMonitor.scrapeInterval }}
18+
scrapeTimeout: {{ .Values.manager.podMonitor.scrapeTimeout }}
19+
{{- with .Values.manager.podMonitor.relabelings }}
20+
relabelings:
21+
{{- . | toYaml | nindent 4 }}
22+
{{- end }}
23+
{{- end }}

helm/kube-image-keeper/values.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,17 @@ manager:
6060
cpu: "1"
6161
# -- Memory limits for the manager pod
6262
memory: "512Mi"
63+
podMonitor:
64+
# -- Should a PodMonitor object be installed to scrape kuik manager metrics. For prometheus-operator (kube-prometheus) users.
65+
create: false
66+
# -- Target scrape interval set in the PodMonitor
67+
scrapeInterval: 60s
68+
# -- Target scrape timeout set in the PodMonitor
69+
scrapeTimeout: 30s
70+
# -- Additional labels to add to PodMonitor objects
71+
extraLabels: {}
72+
# -- Relabel config for the PodMonitor, see: https://coreos.com/operators/prometheus/docs/latest/api.html#relabelconfig
73+
relabelings: []
6374

6475
rbac:
6576
# -- Create the ClusterRole and ClusterRoleBinding. If false, need to associate permissions with serviceAccount outside this Helm chart.

internal/controller/collector.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package controller
2+
3+
import (
4+
"github.com/enix/kube-image-keeper/internal/info"
5+
"github.com/prometheus/client_golang/prometheus"
6+
"sigs.k8s.io/controller-runtime/pkg/healthz"
7+
"sigs.k8s.io/controller-runtime/pkg/metrics"
8+
)
9+
10+
type kuikMetrics struct {
11+
collectors []prometheus.Collector
12+
}
13+
14+
var Metrics kuikMetrics
15+
16+
func (m *kuikMetrics) Register(elected <-chan struct{}) {
17+
const subsystem = "manager"
18+
19+
m.addCollector(info.NewInfoCollector(subsystem))
20+
21+
m.addCollector(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
22+
Namespace: info.MetricsNamespace,
23+
Subsystem: subsystem,
24+
Name: "is_leader",
25+
Help: "Whether or not this replica is a leader. 1 if it is, 0 otherwise.",
26+
}, func() float64 {
27+
select {
28+
case <-elected:
29+
return 1
30+
default:
31+
return 0
32+
}
33+
}))
34+
35+
m.addCollector(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
36+
Namespace: info.MetricsNamespace,
37+
Subsystem: subsystem,
38+
Name: "up",
39+
Help: "Whether or not this replica is healthy.",
40+
}, func() float64 {
41+
if err := healthz.Ping(nil); err != nil {
42+
return 0
43+
}
44+
return 1
45+
}))
46+
47+
metrics.Registry.MustRegister(m.collectors...)
48+
}
49+
50+
func (m *kuikMetrics) addCollector(collector prometheus.Collector) {
51+
m.collectors = append(m.collectors, collector)
52+
}

internal/controller/kuik/registrymonitor_controller.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,18 @@ func (r *RegistryMonitorReconciler) Reconcile(ctx context.Context, req ctrl.Requ
9191
logImage := logf.Log.WithValues("controller", "imagemonitor", "image", klog.KObj(&image), "reference", image.Reference()).V(1)
9292
logImage.Info("queuing image for monitoring")
9393

94-
monitorPool.Submit(func() {
94+
monitorPool.SubmitErr(func() error {
9595
logImage.Info("monitoring image")
9696
if err := r.monitorAnImage(logf.IntoContext(context.Background(), logImage), &image); err != nil {
9797
logImage.Info("failed to monitor image", "error", err.Error())
98+
return err
9899
}
99100
logImage.Info("image monitored with success")
101+
return nil
100102
})
101103
}
102104

103-
log.Info("queued images for monitoring with success")
105+
log.Info("queued images for monitoring with success", "completed", monitorPool.CompletedTasks(), "failed", monitorPool.FailedTasks())
104106

105107
return ctrl.Result{RequeueAfter: registryMonitor.Spec.Interval.Duration / time.Duration(registryMonitor.Spec.MaxPerInterval)}, nil
106108
}

internal/info/info.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package info
2+
3+
import (
4+
"runtime"
5+
6+
"github.com/prometheus/client_golang/prometheus"
7+
)
8+
9+
const MetricsNamespace = "kube_image_keeper"
10+
11+
// Version and build informations set at link time
12+
var (
13+
Version = "0.0.0"
14+
Revision = ""
15+
BuildDateTime = ""
16+
)
17+
18+
type InfoCollector struct {
19+
metric prometheus.Metric
20+
}
21+
22+
// Describe implements Collector.
23+
func (i *InfoCollector) Describe(ch chan<- *prometheus.Desc) {
24+
ch <- i.metric.Desc()
25+
}
26+
27+
// Collect implements Collector.
28+
func (i *InfoCollector) Collect(ch chan<- prometheus.Metric) {
29+
ch <- i.metric
30+
}
31+
32+
func NewInfoCollector(subsystem string) prometheus.Collector {
33+
infoMetric := prometheus.BuildFQName(MetricsNamespace, subsystem, "build_info")
34+
infoHelp := "A metric with a constant '1' value labeled with version, revision, build date, Go version, Go OS, and Go architecture"
35+
infoConstLabels := prometheus.Labels{
36+
"version": Version,
37+
"revision": Revision,
38+
"built": BuildDateTime,
39+
"goversion": runtime.Version(),
40+
"goos": runtime.GOOS,
41+
"goarch": runtime.GOARCH,
42+
}
43+
infoDesc := prometheus.NewDesc(infoMetric, infoHelp, nil, infoConstLabels)
44+
45+
return &InfoCollector{
46+
metric: prometheus.MustNewConstMetric(infoDesc, prometheus.GaugeValue, float64(1)),
47+
}
48+
}

0 commit comments

Comments
 (0)