Compare commits

..
Author SHA1 Message Date
Mikkel Oscar Lyderik Larsen 2be79ae0f2 dependabot: update gh actions monthly
Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
2025-09-12 09:34:07 +02:00
Antoine DeschênesandGitHub bf80e85e58 Add Prometheus server aliases and bearer token authentication support (#815)
Adds --prometheus-server-token-file flag to support authenticating to
a prometheus server using a bearer token file.

Adds --additional-prometheus-servers=<name>=<url>,... and
--additional-prometheus-server-token-files=<name>=<url>,... to
support additional servers through the new "prometheus-server-alias"
HPA annotation

Signed-off-by: Antoine Deschênes <antoine@antoinedeschenes.com>
2025-09-11 10:30:12 +02:00
Noor Muhammad MalikandGitHub c5017c7f89 Merge pull request #807 from thaniri/issue-97-add-configurable-collection-intervals
feat: add config flags for collection intervals
2025-06-06 17:16:51 +02:00
Marek Slabicki 613d6ba302 feat: add config flags for collection intervals
The garbage collection interval should never be less than the collection
interval as this results in "gaps" in metrics.

By making these configurations tuneable it allows users to configure
kube-metrics-adapter to suit the needs of their clusters.

An example configuration that solves this issue is:

- --default-collection-interval=30s
- --metrics-ttl=30s
- --garbage-collector-interval=30s
- --metrics-ttl=45s

This ensures metrics are collected every 30 seconds, retained for 45
seconds, and garbage collected every 30 seconds. Resulting in zero
"gaps".

Signed-off-by: Marek Slabicki <mslabicki@demonware.net>
2025-05-22 15:02:13 -07:00
Noor Muhammad MalikandGitHub 2ed22f04c2 Merge pull request #805 from zalando-incubator/helm/fix-wrong-image-src
helm: fix wrong image as we moved to ghcr
2025-05-20 13:25:11 +02:00
9 changed files with 167 additions and 73 deletions
+5
View File
@@ -19,3 +19,8 @@ updates:
interval: monthly
time: "07:00"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
+4
View File
@@ -243,6 +243,10 @@ metadata:
# If specified, then this prometheus server is used,
# instead of the prometheus server specified as the CLI argument `--prometheus-server`.
metric-config.external.processed-events-per-second.prometheus/prometheus-server: http://prometheus.my-namespace.svc
# This annotation is optional.
# If specified, this will use one of the additional prometheus servers configured via the
# --additional-prometheus-server <name>=<url>,<name>=<url>,... CLI argument.
metric-config.external.processed-events-per-second.prometheus/prometheus-server-alias: external-prometheus
# metric-config.<metricType>.<metricName>.<collectorType>/<configKey>
metric-config.external.processed-events-per-second.prometheus/query: |
scalar(sum(rate(event-service_events_count{application="event-service",processed="true"}[1m])))
+70 -55
View File
@@ -39,170 +39,179 @@ spec:
args:
{{- if .Values.addDirectoryHeader }}
- --add_dir_header={{ .Values.addDirectoryHeader }}
{{- end}}
{{- end }}
{{- if .Values.log.alsoToStderr }}
- --alsologtostderr={{ .Values.log.alsoToStderr }}
{{- end}}
{{- end }}
{{- if .Values.authentication.kubeConfig }}
- --authentication-kubeconfig={{ .Values.authentication.kubeConfig }}
{{- end}}
{{- end }}
{{- if .Values.authentication.skipLookup }}
- --authentication-skip-lookup={{ .Values.authentication.skipLookup }}
{{- end}}
{{- end }}
{{- if .Values.authentication.tokenWebhookCacheTtl }}
- --authentication-token-webhook-cache-ttl={{ .Values.authentication.tokenWebhookCacheTtl }}
{{- end}}
{{- end }}
{{- if .Values.authentication.tolerateLookupFailure }}
- --authentication-tolerate-lookup-failure={{ .Values.authentication.tolerateLookupFailure }}
{{- end}}
{{- end }}
{{- if .Values.authorization.alwaysAllowPaths }}
- --authorization-always-allow-paths={{ .Values.authorization.alwaysAllowPaths }}
{{- end}}
{{- end }}
{{- if .Values.authorization.kubeConfig }}
- --authorization-kubeconfig={{ .Values.authorization.kubeConfig }}
{{- end}}
{{- end }}
{{- if .Values.authorization.webhookCache.authorizedTtl }}
- --authorization-webhook-cache-authorized-ttl={{ .Values.authorization.webhookCache.authorizedTtl }}
{{- end}}
{{- end }}
{{- if .Values.authorization.webhookCache.unauthorizedTtl }}
- --authorization-webhook-cache-unauthorized-ttl={{ .Values.authorization.webhookCache.unauthorizedTtl }}
{{- end}}
{{- end }}
{{- if .Values.aws.externalMetrics }}
- --aws-external-metrics={{ .Values.aws.externalMetrics }}
{{- end}}
{{- end }}
{{- if .Values.aws.region }}
- --aws-region={{ .Values.aws.region }}
{{- end}}
{{- end }}
{{- if .Values.tls.certificateDirectory }}
- --cert-dir={{ .Values.tls.certificateDirectory }}
{{- end}}
{{- end }}
{{- if .Values.tls.clientCaFile }}
- --client-ca-file={{ .Values.tls.clientCaFile }}
{{- end}}
{{- end }}
{{- if .Values.contentionProfiling }}
- --contention-profiling={{ .Values.contentionProfiling }}
{{- end}}
{{- end }}
{{- if .Values.credentialsDirectory }}
- --credentials-dir={{ .Values.credentialsDirectory }}
{{- end}}
{{- end }}
{{- if .Values.disregardIncompatibleHPAs }}
- --disregard-incompatible-hpas={{ .Values.disregardIncompatibleHPAs }}
{{- end}}
{{- end }}
{{- if .Values.enableCustomMetricsApi }}
- --enable-custom-metrics-api={{ .Values.enableCustomMetricsApi }}
{{- end}}
{{- end }}
{{- if .Values.enableExternalMetricsApi }}
- --enable-external-metrics-api={{ .Values.enableExternalMetricsApi }}
{{- end}}
{{- end }}
{{- if .Values.http2MaxStreamsPerConnection }}
- --http2-max-streams-per-connection={{ .Values.http2MaxStreamsPerConnection }}
{{- end}}
{{- end }}
{{- if .Values.influxDB.address }}
- --influxdb-address={{ .Values.influxDB.address }}
{{- end}}
{{- end }}
{{- if .Values.influxDB.organization }}
- --influxdb-org={{ .Values.influxDB.organization }}
{{- end}}
{{- end }}
{{- if .Values.influxDB.token }}
- --influxdb-token={{ .Values.influxDB.token }}
{{- end}}
{{- end }}
{{- if .Values.listerKubeConfig }}
- --lister-kubeconfig={{ .Values.listerKubeConfig }}
{{- end}}
{{- end }}
{{- if .Values.log.flushFrequency }}
- --log-flush-frequency={{ .Values.log.flushFrequency }}
{{- end}}
{{- end }}
{{- if .Values.log.backtraceAtTraceLocation }}
- --log_backtrace_at={{ .Values.log.backtraceAtTraceLocation }}
{{- end}}
{{- end }}
{{- if .Values.log.directory }}
- --log_dir={{ .Values.log.directory }}
{{- end}}
{{- end }}
{{- if .Values.log.file }}
- --log_file={{ .Values.log.file }}
{{- end}}
{{- end }}
{{- if .Values.log.fileMaxSize }}
- --log_file_max_size={{ .Values.log.fileMaxSize }}
{{- end}}
{{- end }}
{{- if .Values.log.toStderr }}
- --logtostderr={{ .Values.log.toStderr }}
{{- end}}
{{- end }}
{{- if .Values.prometheus.metricsAddress }}
- --metrics-address={{ .Values.prometheus.metricsAddress }}
{{- end}}
{{- end }}
{{- if .Values.profiling }}
- --profiling={{ .Values.profiling }}
{{- end}}
{{- end }}
{{- if .Values.prometheus.server }}
- --prometheus-server={{ .Values.prometheus.server }}
{{- end}}
{{- end }}
{{- if .Values.prometheus.serverTokenFile }}
- --prometheus-server-token-file={{ .Values.prometheus.serverTokenFile }}
{{- end }}
{{- range $name, $url := .Values.prometheus.additionalServers }}
- --additional-prometheus-server={{ $name }}={{ $url }}
{{- end }}
{{- range $name, $path := .Values.prometheus.additionalServerTokenFiles }}
- --additional-prometheus-server-token-file={{ $name }}={{ $path }}
{{- end }}
{{- if .Values.requestHeader.allowedNames }}
- --requestheader-allowed-names={{ .Values.requestHeader.allowedNames }}
{{- end}}
{{- end }}
{{- if .Values.requestHeader.clientCaFile }}
- --requestheader-client-ca-file={{ .Values.requestHeader.clientCaFile }}
{{- end}}
{{- end }}
{{- if .Values.requestHeader.extraHeadersPrefix }}
- --requestheader-extra-headers-prefix={{ .Values.requestHeader.extraHeadersPrefix }}
{{- end}}
{{- end }}
{{- if .Values.requestHeader.groupHeaders }}
- --requestheader-group-headers={{ .Values.requestHeader.groupHeaders }}
{{- end}}
{{- end }}
{{- if .Values.requestHeader.usernameHeaders }}
- --requestheader-username-headers={{ .Values.requestHeader.usernameHeaders }}
{{- end}}
{{- end }}
- --secure-port={{ .Values.service.internalPort }}
{{- if .Values.log.skipHeaders }}
- --skip_headers={{ .Values.log.skipHeaders }}
{{- end}}
{{- end }}
{{- if .Values.log.skipLogHeaders }}
- --skip_log_headers={{ .Values.log.skipLogHeaders }}
{{- end}}
{{- end }}
{{- if .Values.skipperBackendsAnnotation }}
- --skipper-backends-annotation={{ .Values.skipperBackendsAnnotation }}
{{- end}}
{{- end }}
{{- if .Values.skipperIngressMetrics }}
- --skipper-ingress-metrics={{ .Values.skipperIngressMetrics }}
{{- end}}
{{- end }}
{{- if .Values.skipperRouteGroupMetrics }}
- --skipper-routegroup-metrics={{ .Values.skipperRouteGroupMetrics }}
{{- end}}
{{- end }}
{{- if .Values.log.stderrThreshold }}
- --stderrthreshold={{ .Values.log.stderrThreshold }}
{{- end}}
{{- end }}
{{- if .Values.tls.certFile }}
- --tls-cert-file={{ .Values.tls.certFile }}
{{- end}}
{{- end }}
{{- if .Values.tls.cipherSuites }}
- --tls-cipher-suites={{ .Values.tls.cipherSuites }}
{{- end}}
{{- end }}
{{- if .Values.tls.minVersion }}
- --tls-min-version={{ .Values.tls.minVersion }}
{{- end}}
{{- end }}
{{- if .Values.tls.privateKeyFile }}
- --tls-private-key-file={{ .Values.tls.privateKeyFile }}
{{- end}}
{{- end }}
{{- if .Values.tls.sniCertKey }}
- --tls-sni-cert-key={{ .Values.tls.sniCertKey }}
{{- end}}
{{- end }}
{{- if .Values.token }}
- --token={{ .Values.token }}
{{- end}}
{{- end }}
{{- if .Values.log.level }}
- --v={{ .Values.log.level }}
{{- end}}
{{- end }}
{{- if .Values.vmodule }}
- --vmodule={{ .Values.vmodule }}
{{- end}}
{{- end }}
{{- if .Values.zmon.kariosdbEndpoint }}
- --zmon-kariosdb-endpoint={{ .Values.zmon.kariosdbEndpoint }}
{{- end}}
{{- end }}
{{- if .Values.zmon.tokenName }}
- --zmon-token-name={{ .Values.zmon.tokenName }}
{{- end}}
{{- end }}
{{- if .Values.scalingSchedule.enabled }}
- --scaling-schedule
{{- end}}
{{- end }}
resources:
limits:
cpu: {{ .Values.resources.limits.cpu }}
@@ -210,3 +219,9 @@ spec:
requests:
cpu: {{ .Values.resources.requests.cpu }}
memory: {{ .Values.resources.requests.memory }}
{{- if .Values.volumeMounts }}
volumeMounts: {{- toYaml .Values.volumeMounts | nindent 12 }}
{{- end }}
{{- if .Values.volumes }}
volumes: {{- toYaml .Values.volumes | nindent 8 }}
{{- end }}
+7
View File
@@ -63,6 +63,9 @@ log:
prometheus:
server: http://prometheus.kube-system.svc.cluster.local
serverTokenFile:
additionalServers: {}
additionalServerTokenFiles: {}
metricsAddress:
requestHeader:
@@ -109,3 +112,7 @@ priorityClassName: ""
podAnnotations: {}
serviceAccountAnnotations: {}
volumes: []
volumeMounts: []
+2
View File
@@ -105,6 +105,7 @@ require (
github.com/influxdata/line-protocol v0.0.0-20210922203350-b1ad95c89adf // indirect
github.com/iris-contrib/schema v0.0.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kataras/blocks v0.0.8 // indirect
github.com/kataras/golog v0.1.12 // indirect
@@ -126,6 +127,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+1 -1
View File
@@ -279,7 +279,7 @@ func TestExternalRPSPrometheusCollectorInteraction(t *testing.T) {
}
factory := NewCollectorFactory()
promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus")
promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus", "", map[string]string{}, map[string]string{})
require.NoError(t, err)
factory.RegisterExternalCollector([]string{PrometheusMetricType, PrometheusMetricNameLegacy}, promPlugin)
hostnamePlugin, err := NewExternalRPSCollectorPlugin(promPlugin, "a_metric")
+51 -12
View File
@@ -9,6 +9,7 @@ import (
"github.com/prometheus/client_golang/api"
promv1 "github.com/prometheus/client_golang/api/prometheus/v1"
promconfig "github.com/prometheus/common/config"
"github.com/prometheus/common/model"
autoscalingv2 "k8s.io/api/autoscaling/v2"
"k8s.io/apimachinery/pkg/api/resource"
@@ -19,10 +20,11 @@ import (
)
const (
PrometheusMetricType = "prometheus"
PrometheusMetricNameLegacy = "prometheus-query"
prometheusQueryNameLabelKey = "query-name"
prometheusServerAnnotationKey = "prometheus-server"
PrometheusMetricType = "prometheus"
PrometheusMetricNameLegacy = "prometheus-query"
prometheusQueryNameLabelKey = "query-name"
prometheusServerAnnotationKey = "prometheus-server"
prometheusServerAliasAnnotationKey = "prometheus-server-alias"
)
type NoResultError struct {
@@ -34,14 +36,26 @@ func (r NoResultError) Error() string {
}
type PrometheusCollectorPlugin struct {
promAPI promv1.API
client kubernetes.Interface
promAPI promv1.API
client kubernetes.Interface
additionalPromAPIs map[string]promv1.API
}
func NewPrometheusCollectorPlugin(client kubernetes.Interface, prometheusServer string) (*PrometheusCollectorPlugin, error) {
func getPrometheusAPI(prometheusServer, tokenFile string) (promv1.API, error) {
roundTripper := http.DefaultTransport
// If a token file is specified, use it for authentication.
if tokenFile != "" {
roundTripper = promconfig.NewAuthorizationCredentialsRoundTripper(
"Bearer",
promconfig.NewFileSecret(tokenFile),
roundTripper,
)
}
cfg := api.Config{
Address: prometheusServer,
RoundTripper: http.DefaultTransport,
RoundTripper: roundTripper,
}
promClient, err := api.NewClient(cfg)
@@ -49,14 +63,33 @@ func NewPrometheusCollectorPlugin(client kubernetes.Interface, prometheusServer
return nil, err
}
return promv1.NewAPI(promClient), nil
}
func NewPrometheusCollectorPlugin(client kubernetes.Interface, prometheusServer, tokenFile string, additionalServers, additionalServerTokenFiles map[string]string) (*PrometheusCollectorPlugin, error) {
promAPI, err := getPrometheusAPI(prometheusServer, tokenFile)
if err != nil {
return nil, err
}
additionalPromAPIs := make(map[string]promv1.API)
for alias, server := range additionalServers {
additionalPromAPIs[alias], err = getPrometheusAPI(server, additionalServerTokenFiles[alias])
if err != nil {
return nil, err
}
}
return &PrometheusCollectorPlugin{
client: client,
promAPI: promv1.NewAPI(promClient),
client: client,
promAPI: promAPI,
additionalPromAPIs: additionalPromAPIs,
}, nil
}
func (p *PrometheusCollectorPlugin) NewCollector(_ context.Context, hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (Collector, error) {
return NewPrometheusCollector(p.client, p.promAPI, hpa, config, interval)
return NewPrometheusCollector(p.client, p.promAPI, p.additionalPromAPIs, hpa, config, interval)
}
type PrometheusCollector struct {
@@ -71,7 +104,7 @@ type PrometheusCollector struct {
hpa *autoscalingv2.HorizontalPodAutoscaler
}
func NewPrometheusCollector(client kubernetes.Interface, promAPI promv1.API, hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (*PrometheusCollector, error) {
func NewPrometheusCollector(client kubernetes.Interface, promAPI promv1.API, additionalPromAPIs map[string]promv1.API, hpa *autoscalingv2.HorizontalPodAutoscaler, config *MetricConfig, interval time.Duration) (*PrometheusCollector, error) {
c := &PrometheusCollector{
client: client,
promAPI: promAPI,
@@ -127,6 +160,12 @@ func NewPrometheusCollector(client kubernetes.Interface, promAPI promv1.API, hpa
return nil, err
}
c.promAPI = promv1.NewAPI(promClient)
} else if promServerAlias, ok := config.Config[prometheusServerAliasAnnotationKey]; ok {
if promAPI, ok := additionalPromAPIs[promServerAlias]; ok {
c.promAPI = promAPI
} else {
return nil, fmt.Errorf("no additional prometheus server found for alias %s", promServerAlias)
}
}
}
+1 -1
View File
@@ -173,7 +173,7 @@ func TestNewPrometheusCollector(t *testing.T) {
} {
t.Run(tc.msg, func(t *testing.T) {
collectorFactory := NewCollectorFactory()
promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus")
promPlugin, err := NewPrometheusCollectorPlugin(nil, "http://prometheus", "", map[string]string{}, map[string]string{})
require.NoError(t, err)
collectorFactory.RegisterExternalCollector([]string{PrometheusMetricType, PrometheusMetricNameLegacy}, promPlugin)
configs, err := ParseHPAMetrics(tc.hpa)
+26 -4
View File
@@ -101,6 +101,14 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
"whether to enable External Metrics API")
flags.StringVar(&o.PrometheusServer, "prometheus-server", o.PrometheusServer, ""+
"url of prometheus server to query")
flags.StringVar(&o.PrometheusServerTokenFile, "prometheus-server-token-file", o.PrometheusServerTokenFile, ""+
"path to file containing bearer token for prometheus server authentication")
flags.StringToStringVar(&o.AdditionalPrometheusServers, "additional-prometheus-server", o.AdditionalPrometheusServers, ""+
"additional prometheus servers that can be used using the 'prometheus-server-alias' annotation. "+
"Format is <name>=<url> (e.g. internal=http://prometheus-internal:9090), can be repeated")
flags.StringToStringVar(&o.AdditionalPrometheusServerTokenFiles, "additional-prometheus-server-token-file", o.AdditionalPrometheusServerTokenFiles, ""+
"token files for additional prometheus servers. Format is <name>=<path>"+
"(e.g. internal=/var/run/secrets/tokens/name-token), can be repeated")
flags.StringVar(&o.InfluxDBAddress, "influxdb-address", o.InfluxDBAddress, ""+
"address of InfluxDB 2.x server to query (e.g. http://localhost:9999)")
flags.StringVar(&o.InfluxDBToken, "influxdb-token", o.InfluxDBToken, ""+
@@ -133,6 +141,8 @@ func NewCommandStartAdapterServer(stopCh <-chan struct{}) *cobra.Command {
"disregard failing to create collectors for incompatible HPAs")
flags.DurationVar(&o.MetricsTTL, "metrics-ttl", 15*time.Minute, "TTL for metrics that are stored in in-memory cache.")
flags.DurationVar(&o.GCInterval, "garbage-collector-interval", 10*time.Minute, "Interval to clean up metrics that are stored in in-memory cache.")
flags.DurationVar(&o.CollectionInterval, "default-collection-interval", 60*time.Second, "Default interval used for collecting metrics.")
flags.DurationVar(&o.ResourceUpdateInterval, "resource-update-interval", 30*time.Second, "Interval at which HPA resources get updated.")
flags.BoolVar(&o.ScalingScheduleMetrics, "scaling-schedule", o.ScalingScheduleMetrics, ""+
"whether to enable time-based ScalingSchedule metrics")
flags.DurationVar(&o.DefaultScheduledScalingWindow, "scaling-schedule-default-scaling-window", 10*time.Minute, "Default rampup and rampdown window duration for ScalingSchedules")
@@ -208,7 +218,7 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
collectorFactory := collector.NewCollectorFactory()
if o.PrometheusServer != "" {
promPlugin, err := collector.NewPrometheusCollectorPlugin(client, o.PrometheusServer)
promPlugin, err := collector.NewPrometheusCollectorPlugin(client, o.PrometheusServer, o.PrometheusServerTokenFile, o.AdditionalPrometheusServers, o.AdditionalPrometheusServerTokenFiles)
if err != nil {
return fmt.Errorf("failed to initialize prometheus collector plugin: %v", err)
}
@@ -391,7 +401,7 @@ func (o AdapterServerOptions) RunCustomMetricsAdapterServer(stopCh <-chan struct
go scheduledScalingController.Run(ctx)
}
hpaProvider := provider.NewHPAProvider(client, 30*time.Second, 1*time.Minute, collectorFactory, o.DisregardIncompatibleHPAs, o.MetricsTTL, o.GCInterval)
hpaProvider := provider.NewHPAProvider(client, o.ResourceUpdateInterval, o.CollectionInterval, collectorFactory, o.DisregardIncompatibleHPAs, o.MetricsTTL, o.GCInterval)
go hpaProvider.Run(ctx)
@@ -464,9 +474,17 @@ type AdapterServerOptions struct {
EnableCustomMetricsAPI bool
// EnableExternalMetricsAPI switches on sample apiserver for External Metrics API
EnableExternalMetricsAPI bool
// PrometheusServer enables prometheus queries to the specified
// server
// PrometheusServer enables prometheus queries to the specified server
PrometheusServer string
// PrometheusServerTokenFile specifies the path to a file containing bearer token
// for prometheus server authentication
PrometheusServerTokenFile string
// AdditionalPrometheusServers allows defining additional prometheus servers
// that can be used on a per-metric basis using the "prometheus-server-alias" annotation.
AdditionalPrometheusServers map[string]string
// AdditionalPrometheusServerTokenFiles allows defining token files for the
// additional prometheus servers.
AdditionalPrometheusServerTokenFiles map[string]string
// InfluxDBAddress enables Flux queries to the specified InfluxDB instance
InfluxDBAddress string
// InfluxDBToken is the token used for querying InfluxDB
@@ -509,6 +527,10 @@ type AdapterServerOptions struct {
MetricsTTL time.Duration
// Interval to clean up metrics that are stored in in-memory cache
GCInterval time.Duration
// Default interval used for collecting metrics
CollectionInterval time.Duration
// Interval at which HPA resources get updated
ResourceUpdateInterval time.Duration
// Time-based scaling based on the CRDs ScheduleScaling and ClusterScheduleScaling.
ScalingScheduleMetrics bool
// Default ramp-up/ramp-down window duration for scheduled metrics