diff --git a/api/config/crd/bases/odigos.io_collectorsgroups.yaml b/api/config/crd/bases/odigos.io_collectorsgroups.yaml index 0fc09ae44..db2de096c 100644 --- a/api/config/crd/bases/odigos.io_collectorsgroups.yaml +++ b/api/config/crd/bases/odigos.io_collectorsgroups.yaml @@ -48,6 +48,48 @@ spec: This can be used to resolve conflicting ports when a collector is using the host network. format: int32 type: integer + memorySettings: + description: |- + Memory settings for the collectors group. + these settings are used to protect the collectors instances from: + - running out of memory and being killed by the k8s OOM killer + - consuming all available memory on the node which can lead to node instability + - pushing back pressure to the instrumented applications + properties: + gomemlimitMiB: + description: |- + the GOMEMLIMIT environment variable value for the collector pod. + this is when go runtime will start garbage collection. + it is recommended to be set to 80% of the hard limit of the memory limiter. + type: integer + memoryLimiterLimitMiB: + description: |- + this parameter sets the "limit_mib" parameter in the memory limiter configuration for the collector. + it is the hard limit after which a force garbage collection will be performed. + this value will end up comparing against the go runtime reported heap Alloc value. + According to the memory limiter docs: + > Note that typically the total memory usage of process will be about 50MiB higher than this value + a test from nov 2024 showed that fresh odigos collector with no traffic takes 38MiB, + thus the 50MiB is a good value to start with. + type: integer + memoryLimiterSpikeLimitMiB: + description: |- + this parameter sets the "spike_limit_mib" parameter in the memory limiter configuration for the collector memory limiter. + note that this is not the processor soft limit itself, but the diff in Mib between the hard limit and the soft limit. + according to the memory limiter docs, it is recommended to set this to 20% of the hard limit. + changing this value allows trade-offs between memory usage and resiliency to bursts. + type: integer + memoryRequestMiB: + description: |- + MemoryRequestMiB is the memory resource request to be used on the pod template. + it will be embedded in the as a resource request of the form "memory: Mi" + type: integer + required: + - gomemlimitMiB + - memoryLimiterLimitMiB + - memoryLimiterSpikeLimitMiB + - memoryRequestMiB + type: object role: enum: - CLUSTER_GATEWAY @@ -55,6 +97,7 @@ spec: type: string required: - collectorOwnMetricsPort + - memorySettings - role type: object status: diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupmemorysettings.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupmemorysettings.go new file mode 100644 index 000000000..e0b50a76e --- /dev/null +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupmemorysettings.go @@ -0,0 +1,65 @@ +/* +Copyright 2022. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha1 + +// CollectorsGroupMemorySettingsApplyConfiguration represents a declarative configuration of the CollectorsGroupMemorySettings type for use +// with apply. +type CollectorsGroupMemorySettingsApplyConfiguration struct { + MemoryRequestMiB *int `json:"memoryRequestMiB,omitempty"` + MemoryLimiterLimitMiB *int `json:"memoryLimiterLimitMiB,omitempty"` + MemoryLimiterSpikeLimitMiB *int `json:"memoryLimiterSpikeLimitMiB,omitempty"` + GomemlimitMiB *int `json:"gomemlimitMiB,omitempty"` +} + +// CollectorsGroupMemorySettingsApplyConfiguration constructs a declarative configuration of the CollectorsGroupMemorySettings type for use with +// apply. +func CollectorsGroupMemorySettings() *CollectorsGroupMemorySettingsApplyConfiguration { + return &CollectorsGroupMemorySettingsApplyConfiguration{} +} + +// WithMemoryRequestMiB sets the MemoryRequestMiB field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MemoryRequestMiB field is set to the value of the last call. +func (b *CollectorsGroupMemorySettingsApplyConfiguration) WithMemoryRequestMiB(value int) *CollectorsGroupMemorySettingsApplyConfiguration { + b.MemoryRequestMiB = &value + return b +} + +// WithMemoryLimiterLimitMiB sets the MemoryLimiterLimitMiB field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MemoryLimiterLimitMiB field is set to the value of the last call. +func (b *CollectorsGroupMemorySettingsApplyConfiguration) WithMemoryLimiterLimitMiB(value int) *CollectorsGroupMemorySettingsApplyConfiguration { + b.MemoryLimiterLimitMiB = &value + return b +} + +// WithMemoryLimiterSpikeLimitMiB sets the MemoryLimiterSpikeLimitMiB field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MemoryLimiterSpikeLimitMiB field is set to the value of the last call. +func (b *CollectorsGroupMemorySettingsApplyConfiguration) WithMemoryLimiterSpikeLimitMiB(value int) *CollectorsGroupMemorySettingsApplyConfiguration { + b.MemoryLimiterSpikeLimitMiB = &value + return b +} + +// WithGomemlimitMiB sets the GomemlimitMiB field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GomemlimitMiB field is set to the value of the last call. +func (b *CollectorsGroupMemorySettingsApplyConfiguration) WithGomemlimitMiB(value int) *CollectorsGroupMemorySettingsApplyConfiguration { + b.GomemlimitMiB = &value + return b +} diff --git a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupspec.go b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupspec.go index 776732e4a..f4ff9a460 100644 --- a/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupspec.go +++ b/api/generated/odigos/applyconfiguration/odigos/v1alpha1/collectorsgroupspec.go @@ -24,8 +24,9 @@ import ( // CollectorsGroupSpecApplyConfiguration represents a declarative configuration of the CollectorsGroupSpec type for use // with apply. type CollectorsGroupSpecApplyConfiguration struct { - Role *v1alpha1.CollectorsGroupRole `json:"role,omitempty"` - CollectorOwnMetricsPort *int32 `json:"collectorOwnMetricsPort,omitempty"` + Role *v1alpha1.CollectorsGroupRole `json:"role,omitempty"` + CollectorOwnMetricsPort *int32 `json:"collectorOwnMetricsPort,omitempty"` + MemorySettings *CollectorsGroupMemorySettingsApplyConfiguration `json:"memorySettings,omitempty"` } // CollectorsGroupSpecApplyConfiguration constructs a declarative configuration of the CollectorsGroupSpec type for use with @@ -49,3 +50,11 @@ func (b *CollectorsGroupSpecApplyConfiguration) WithCollectorOwnMetricsPort(valu b.CollectorOwnMetricsPort = &value return b } + +// WithMemorySettings sets the MemorySettings field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MemorySettings field is set to the value of the last call. +func (b *CollectorsGroupSpecApplyConfiguration) WithMemorySettings(value *CollectorsGroupMemorySettingsApplyConfiguration) *CollectorsGroupSpecApplyConfiguration { + b.MemorySettings = value + return b +} diff --git a/api/generated/odigos/applyconfiguration/utils.go b/api/generated/odigos/applyconfiguration/utils.go index 123503121..954bd9be8 100644 --- a/api/generated/odigos/applyconfiguration/utils.go +++ b/api/generated/odigos/applyconfiguration/utils.go @@ -41,6 +41,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &odigosv1alpha1.CollectorGatewayConfigurationApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CollectorsGroup"): return &odigosv1alpha1.CollectorsGroupApplyConfiguration{} + case v1alpha1.SchemeGroupVersion.WithKind("CollectorsGroupMemorySettings"): + return &odigosv1alpha1.CollectorsGroupMemorySettingsApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CollectorsGroupSpec"): return &odigosv1alpha1.CollectorsGroupSpecApplyConfiguration{} case v1alpha1.SchemeGroupVersion.WithKind("CollectorsGroupStatus"): diff --git a/api/odigos/v1alpha1/collectorsgroup_types.go b/api/odigos/v1alpha1/collectorsgroup_types.go index e04fc37ca..26a688df3 100644 --- a/api/odigos/v1alpha1/collectorsgroup_types.go +++ b/api/odigos/v1alpha1/collectorsgroup_types.go @@ -30,6 +30,37 @@ const ( CollectorsGroupRoleNodeCollector CollectorsGroupRole = CollectorsGroupRole(k8sconsts.CollectorsRoleNodeCollector) ) +// The raw values of the memory settings for the collectors group. +// any defaulting, validations and calculations should be done in the controllers +// that create this CR. +// Values will be used as is without any further processing. +type CollectorsGroupMemorySettings struct { + + // MemoryRequestMiB is the memory resource request to be used on the pod template. + // it will be embedded in the as a resource request of the form "memory: Mi" + MemoryRequestMiB int `json:"memoryRequestMiB"` + + // this parameter sets the "limit_mib" parameter in the memory limiter configuration for the collector. + // it is the hard limit after which a force garbage collection will be performed. + // this value will end up comparing against the go runtime reported heap Alloc value. + // According to the memory limiter docs: + // > Note that typically the total memory usage of process will be about 50MiB higher than this value + // a test from nov 2024 showed that fresh odigos collector with no traffic takes 38MiB, + // thus the 50MiB is a good value to start with. + MemoryLimiterLimitMiB int `json:"memoryLimiterLimitMiB"` + + // this parameter sets the "spike_limit_mib" parameter in the memory limiter configuration for the collector memory limiter. + // note that this is not the processor soft limit itself, but the diff in Mib between the hard limit and the soft limit. + // according to the memory limiter docs, it is recommended to set this to 20% of the hard limit. + // changing this value allows trade-offs between memory usage and resiliency to bursts. + MemoryLimiterSpikeLimitMiB int `json:"memoryLimiterSpikeLimitMiB"` + + // the GOMEMLIMIT environment variable value for the collector pod. + // this is when go runtime will start garbage collection. + // it is recommended to be set to 80% of the hard limit of the memory limiter. + GomemlimitMiB int `json:"gomemlimitMiB"` +} + // CollectorsGroupSpec defines the desired state of Collector type CollectorsGroupSpec struct { Role CollectorsGroupRole `json:"role"` @@ -37,6 +68,13 @@ type CollectorsGroupSpec struct { // The port to use for exposing the collector's own metrics as a prometheus endpoint. // This can be used to resolve conflicting ports when a collector is using the host network. CollectorOwnMetricsPort int32 `json:"collectorOwnMetricsPort"` + + // Memory settings for the collectors group. + // these settings are used to protect the collectors instances from: + // - running out of memory and being killed by the k8s OOM killer + // - consuming all available memory on the node which can lead to node instability + // - pushing back pressure to the instrumented applications + MemorySettings CollectorsGroupMemorySettings `json:"memorySettings"` } // CollectorsGroupStatus defines the observed state of Collector diff --git a/api/odigos/v1alpha1/zz_generated.deepcopy.go b/api/odigos/v1alpha1/zz_generated.deepcopy.go index 41f1abe04..07567069b 100644 --- a/api/odigos/v1alpha1/zz_generated.deepcopy.go +++ b/api/odigos/v1alpha1/zz_generated.deepcopy.go @@ -153,9 +153,25 @@ func (in *CollectorsGroupList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CollectorsGroupMemorySettings) DeepCopyInto(out *CollectorsGroupMemorySettings) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorsGroupMemorySettings. +func (in *CollectorsGroupMemorySettings) DeepCopy() *CollectorsGroupMemorySettings { + if in == nil { + return nil + } + out := new(CollectorsGroupMemorySettings) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CollectorsGroupSpec) DeepCopyInto(out *CollectorsGroupSpec) { *out = *in + out.MemorySettings = in.MemorySettings } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorsGroupSpec. diff --git a/autoscaler/controllers/gateway/configmap.go b/autoscaler/controllers/gateway/configmap.go index ab9a23af2..1547517e1 100644 --- a/autoscaler/controllers/gateway/configmap.go +++ b/autoscaler/controllers/gateway/configmap.go @@ -111,13 +111,13 @@ func addSelfTelemetryPipeline(c *config.Config, ownTelemetryPort int32) error { return nil } -func syncConfigMap(dests *odigosv1.DestinationList, allProcessors *odigosv1.ProcessorList, gateway *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme, memConfig *memoryConfigurations) (string, []odigoscommon.ObservabilitySignal, error) { +func syncConfigMap(dests *odigosv1.DestinationList, allProcessors *odigosv1.ProcessorList, gateway *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme) (string, []odigoscommon.ObservabilitySignal, error) { logger := log.FromContext(ctx) memoryLimiterConfiguration := config.GenericMap{ "check_interval": "1s", - "limit_mib": memConfig.memoryLimiterLimitMiB, - "spike_limit_mib": memConfig.memoryLimiterSpikeLimitMiB, + "limit_mib": gateway.Spec.MemorySettings.MemoryLimiterLimitMiB, + "spike_limit_mib": gateway.Spec.MemorySettings.MemoryLimiterSpikeLimitMiB, } processors := common.FilterAndSortProcessorsByOrderHint(allProcessors, odigosv1.CollectorsGroupRoleClusterGateway) diff --git a/autoscaler/controllers/gateway/deployment.go b/autoscaler/controllers/gateway/deployment.go index 1a23eae84..8e71814da 100644 --- a/autoscaler/controllers/gateway/deployment.go +++ b/autoscaler/controllers/gateway/deployment.go @@ -34,7 +34,7 @@ const ( ) func syncDeployment(dests *odigosv1.DestinationList, gateway *odigosv1.CollectorsGroup, configData string, - ctx context.Context, c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, memConfig *memoryConfigurations) (*appsv1.Deployment, error) { + ctx context.Context, c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string) (*appsv1.Deployment, error) { logger := log.FromContext(ctx) secretsVersionHash, err := destinationsSecretsVersionsHash(ctx, c, dests) @@ -44,7 +44,7 @@ func syncDeployment(dests *odigosv1.DestinationList, gateway *odigosv1.Collector // Calculate the hash of the config data and the secrets version hash, this is used to make sure the gateway will restart when the config changes configDataHash := common.Sha256Hash(fmt.Sprintf("%s-%s", configData, secretsVersionHash)) - desiredDeployment, err := getDesiredDeployment(dests, configDataHash, gateway, scheme, imagePullSecrets, odigosVersion, memConfig) + desiredDeployment, err := getDesiredDeployment(dests, configDataHash, gateway, scheme, imagePullSecrets, odigosVersion) if err != nil { return nil, errors.Join(err, errors.New("failed to get desired deployment")) } @@ -88,9 +88,9 @@ func patchDeployment(existing *appsv1.Deployment, desired *appsv1.Deployment, ct } func getDesiredDeployment(dests *odigosv1.DestinationList, configDataHash string, - gateway *odigosv1.CollectorsGroup, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, memConfig *memoryConfigurations) (*appsv1.Deployment, error) { + gateway *odigosv1.CollectorsGroup, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string) (*appsv1.Deployment, error) { - requestMemoryQuantity := resource.MustParse(fmt.Sprintf("%dMi", memConfig.memoryRequestMiB)) + requestMemoryQuantity := resource.MustParse(fmt.Sprintf("%dMi", gateway.Spec.MemorySettings.MemoryRequestMiB)) desiredDeployment := &appsv1.Deployment{ ObjectMeta: v1.ObjectMeta{ @@ -158,7 +158,7 @@ func getDesiredDeployment(dests *odigosv1.DestinationList, configDataHash string }, { Name: "GOMEMLIMIT", - Value: fmt.Sprintf("%dMiB", memConfig.gomemlimitMiB), + Value: fmt.Sprintf("%dMiB", gateway.Spec.MemorySettings.GomemlimitMiB), }, }, SecurityContext: &corev1.SecurityContext{ diff --git a/autoscaler/controllers/gateway/hpa.go b/autoscaler/controllers/gateway/hpa.go index 7a4732615..a718cde6a 100644 --- a/autoscaler/controllers/gateway/hpa.go +++ b/autoscaler/controllers/gateway/hpa.go @@ -30,12 +30,12 @@ var ( stabilizationWindowSeconds = intPtr(300) // cooldown period for scaling down ) -func syncHPA(gateway *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme, memConfig *memoryConfigurations, kubeVersion *version.Version) error { +func syncHPA(gateway *odigosv1.CollectorsGroup, ctx context.Context, c client.Client, scheme *runtime.Scheme, kubeVersion *version.Version) error { logger := log.FromContext(ctx) var hpa client.Object - memLimit := memConfig.gomemlimitMiB * memoryLimitPercentageForHPA / 100.0 + memLimit := gateway.Spec.MemorySettings.GomemlimitMiB * memoryLimitPercentageForHPA / 100.0 metricQuantity := resource.MustParse(fmt.Sprintf("%dMi", memLimit)) switch { diff --git a/autoscaler/controllers/gateway/root.go b/autoscaler/controllers/gateway/root.go index 422a23752..552296b40 100644 --- a/autoscaler/controllers/gateway/root.go +++ b/autoscaler/controllers/gateway/root.go @@ -6,10 +6,8 @@ import ( odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" commonconf "github.com/odigos-io/odigos/autoscaler/controllers/common" controllerconfig "github.com/odigos-io/odigos/autoscaler/controllers/controller_config" - odigoscommon "github.com/odigos-io/odigos/common" k8sconsts "github.com/odigos-io/odigos/k8sutils/pkg/consts" "github.com/odigos-io/odigos/k8sutils/pkg/env" - "github.com/odigos-io/odigos/k8sutils/pkg/utils" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -49,14 +47,7 @@ func Sync(ctx context.Context, k8sClient client.Client, scheme *runtime.Scheme, // Add the generic batch processor to the list of processors processors.Items = append(processors.Items, commonconf.GetGenericBatchProcessor()) - odigosConfig, err := utils.GetCurrentOdigosConfig(ctx, k8sClient) - if err != nil { - logger.Error(err, "failed to get odigos config") - return err - } - - err = syncGateway(&dests, &processors, &gatewayCollectorGroup, ctx, k8sClient, scheme, imagePullSecrets, odigosVersion, &odigosConfig, - config) + err = syncGateway(&dests, &processors, &gatewayCollectorGroup, ctx, k8sClient, scheme, imagePullSecrets, odigosVersion, config) statusPatchString := commonconf.GetCollectorsGroupDeployedConditionsPatch(err) statusErr := k8sClient.Status().Patch(ctx, &gatewayCollectorGroup, client.RawPatch(types.MergePatchType, []byte(statusPatchString))) if statusErr != nil { @@ -68,14 +59,12 @@ func Sync(ctx context.Context, k8sClient client.Client, scheme *runtime.Scheme, func syncGateway(dests *odigosv1.DestinationList, processors *odigosv1.ProcessorList, gateway *odigosv1.CollectorsGroup, ctx context.Context, - c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, odigosConfig *odigoscommon.OdigosConfiguration, + c client.Client, scheme *runtime.Scheme, imagePullSecrets []string, odigosVersion string, config *controllerconfig.ControllerConfig) error { logger := log.FromContext(ctx) logger.V(0).Info("Syncing gateway") - memConfig := getMemoryConfigurations(odigosConfig) - - configData, signals, err := syncConfigMap(dests, processors, gateway, ctx, c, scheme, memConfig) + configData, signals, err := syncConfigMap(dests, processors, gateway, ctx, c, scheme) if err != nil { logger.Error(err, "Failed to sync config map") return err @@ -93,7 +82,7 @@ func syncGateway(dests *odigosv1.DestinationList, processors *odigosv1.Processor return err } - _, err = syncDeployment(dests, gateway, configData, ctx, c, scheme, imagePullSecrets, odigosVersion, memConfig) + _, err = syncDeployment(dests, gateway, configData, ctx, c, scheme, imagePullSecrets, odigosVersion) if err != nil { logger.Error(err, "Failed to sync deployment") return err @@ -105,7 +94,7 @@ func syncGateway(dests *odigosv1.DestinationList, processors *odigosv1.Processor return err } - err = syncHPA(gateway, ctx, c, scheme, memConfig, config.K8sVersion) + err = syncHPA(gateway, ctx, c, scheme, config.K8sVersion) if err != nil { logger.Error(err, "Failed to sync HPA") } diff --git a/autoscaler/controllers/odigosconfig_controller.go b/autoscaler/controllers/odigosconfig_controller.go deleted file mode 100644 index b57330b70..000000000 --- a/autoscaler/controllers/odigosconfig_controller.go +++ /dev/null @@ -1,43 +0,0 @@ -package controllers - -import ( - "context" - - controllerconfig "github.com/odigos-io/odigos/autoscaler/controllers/controller_config" - odigospredicate "github.com/odigos-io/odigos/k8sutils/pkg/predicate" - - "github.com/odigos-io/odigos/autoscaler/controllers/gateway" - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/runtime" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/predicate" -) - -type OdigosConfigReconciler struct { - client.Client - Scheme *runtime.Scheme - ImagePullSecrets []string - OdigosVersion string - Config *controllerconfig.ControllerConfig -} - -func (r *OdigosConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - logger := log.FromContext(ctx) - logger.V(0).Info("Reconciling Odigos Configuration") - - err := gateway.Sync(ctx, r.Client, r.Scheme, r.ImagePullSecrets, r.OdigosVersion, r.Config) - if err != nil { - return ctrl.Result{}, err - } - - return ctrl.Result{}, nil -} - -func (r *OdigosConfigReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&v1.ConfigMap{}). - WithEventFilter(predicate.And(odigospredicate.OdigosConfigMapPredicate, odigospredicate.ConfigMapDataChangedPredicate{})). - Complete(r) -} diff --git a/autoscaler/main.go b/autoscaler/main.go index 9fc6aa117..5053d7614 100644 --- a/autoscaler/main.go +++ b/autoscaler/main.go @@ -234,16 +234,6 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "InstrumentedApplication") os.Exit(1) } - if err = (&controllers.OdigosConfigReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - ImagePullSecrets: imagePullSecrets, - OdigosVersion: odigosVersion, - Config: config, - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "OdigosConfig") - os.Exit(1) - } if err = (&controllers.SecretReconciler{ Client: mgr.GetClient(), Scheme: mgr.GetScheme(), diff --git a/scheduler/controllers/clustercollectorsgroup/common.go b/scheduler/controllers/clustercollectorsgroup/common.go index c4f180661..a88c0424b 100644 --- a/scheduler/controllers/clustercollectorsgroup/common.go +++ b/scheduler/controllers/clustercollectorsgroup/common.go @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -func newClusterCollectorGroup(namespace string) *odigosv1.CollectorsGroup { +func newClusterCollectorGroup(namespace string, memorySettings *odigosv1.CollectorsGroupMemorySettings) *odigosv1.CollectorsGroup { return &odigosv1.CollectorsGroup{ TypeMeta: metav1.TypeMeta{ Kind: "CollectorsGroup", @@ -24,6 +24,7 @@ func newClusterCollectorGroup(namespace string) *odigosv1.CollectorsGroup { Spec: odigosv1.CollectorsGroupSpec{ Role: odigosv1.CollectorsGroupRoleClusterGateway, CollectorOwnMetricsPort: consts.OdigosClusterCollectorOwnTelemetryPortDefault, + MemorySettings: *memorySettings, }, } } @@ -38,8 +39,15 @@ func sync(ctx context.Context, c client.Client) error { return err } + odigosConfig, err := utils.GetCurrentOdigosConfig(ctx, c) + if err != nil { + return err + } + + memorySettings := getMemorySettings(&odigosConfig) + if len(dests.Items) > 0 { - err := utils.ApplyCollectorGroup(ctx, c, newClusterCollectorGroup(namespace)) + err := utils.ApplyCollectorGroup(ctx, c, newClusterCollectorGroup(namespace, memorySettings)) if err != nil { return err } diff --git a/scheduler/controllers/clustercollectorsgroup/manager.go b/scheduler/controllers/clustercollectorsgroup/manager.go index 09411b7d4..a0d398ff0 100644 --- a/scheduler/controllers/clustercollectorsgroup/manager.go +++ b/scheduler/controllers/clustercollectorsgroup/manager.go @@ -3,6 +3,7 @@ package clustercollectorsgroup import ( odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" odigospredicates "github.com/odigos-io/odigos/k8sutils/pkg/predicate" + corev1 "k8s.io/api/core/v1" ctrl "sigs.k8s.io/controller-runtime" ) @@ -20,5 +21,17 @@ func SetupWithManager(mgr ctrl.Manager) error { return err } + err = ctrl.NewControllerManagedBy(mgr). + For(&corev1.ConfigMap{}). + Named("clustercollectorgroup-odigosconfig"). + WithEventFilter(&odigospredicates.OdigosConfigMapPredicate). + Complete(&odigosConfigController{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }) + if err != nil { + return err + } + return nil } diff --git a/autoscaler/controllers/gateway/memory.go b/scheduler/controllers/clustercollectorsgroup/memory.go similarity index 75% rename from autoscaler/controllers/gateway/memory.go rename to scheduler/controllers/clustercollectorsgroup/memory.go index 14f14232f..8f0a0dda6 100644 --- a/autoscaler/controllers/gateway/memory.go +++ b/scheduler/controllers/clustercollectorsgroup/memory.go @@ -1,6 +1,7 @@ -package gateway +package clustercollectorsgroup import ( + odigosv1 "github.com/odigos-io/odigos/api/odigos/v1alpha1" "github.com/odigos-io/odigos/common" ) @@ -20,14 +21,9 @@ const ( defaultGoMemLimitPercentage = 80.0 ) -type memoryConfigurations struct { - memoryRequestMiB int - memoryLimiterLimitMiB int - memoryLimiterSpikeLimitMiB int - gomemlimitMiB int -} - -func getMemoryConfigurations(odigosConfig *common.OdigosConfiguration) *memoryConfigurations { +// process the memory settings from odigos config and return the memory settings for the collectors group. +// apply any defaulting and calculations here. +func getMemorySettings(odigosConfig *common.OdigosConfiguration) *odigosv1.CollectorsGroupMemorySettings { memoryRequestMiB := defaultRequestMemoryMiB if odigosConfig.CollectorGateway != nil && odigosConfig.CollectorGateway.RequestMemoryMiB > 0 { memoryRequestMiB = odigosConfig.CollectorGateway.RequestMemoryMiB @@ -49,10 +45,10 @@ func getMemoryConfigurations(odigosConfig *common.OdigosConfiguration) *memoryCo gomemlimitMiB = odigosConfig.CollectorGateway.GoMemLimitMib } - return &memoryConfigurations{ - memoryRequestMiB: memoryRequestMiB, - memoryLimiterLimitMiB: memoryLimiterLimitMiB, - memoryLimiterSpikeLimitMiB: memoryLimiterSpikeLimitMiB, - gomemlimitMiB: gomemlimitMiB, + return &odigosv1.CollectorsGroupMemorySettings{ + MemoryRequestMiB: memoryRequestMiB, + MemoryLimiterLimitMiB: memoryLimiterLimitMiB, + MemoryLimiterSpikeLimitMiB: memoryLimiterSpikeLimitMiB, + GomemlimitMiB: gomemlimitMiB, } } diff --git a/scheduler/controllers/clustercollectorsgroup/odigosconfig_controller.go b/scheduler/controllers/clustercollectorsgroup/odigosconfig_controller.go new file mode 100644 index 000000000..2fe8de2d3 --- /dev/null +++ b/scheduler/controllers/clustercollectorsgroup/odigosconfig_controller.go @@ -0,0 +1,19 @@ +package clustercollectorsgroup + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +type odigosConfigController struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *odigosConfigController) Reconcile(ctx context.Context, _ ctrl.Request) (ctrl.Result, error) { + err := sync(ctx, r.Client) + return ctrl.Result{}, err +}