From 56ad0bdc3a04457c35d906085e74b39e56970f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9opold=20Jacquot?= Date: Mon, 7 Aug 2023 19:13:58 +0200 Subject: [PATCH] feat: add flagd sidecar resources attribute (#514) Signed-off-by: Leopold Jacquot --- .../v1alpha1/flagsourceconfiguration_types.go | 4 + apis/core/v1alpha1/zz_generated.deepcopy.go | 1 + .../featureflagconfiguration_types.go | 3 + apis/core/v1alpha2/zz_generated.deepcopy.go | 1 + .../v1alpha3/flagsourceconfiguration_types.go | 4 + apis/core/v1alpha3/zz_generated.deepcopy.go | 1 + chart/open-feature-operator/README.md | 1 + chart/open-feature-operator/values.yaml | 2 + ...nfeature.dev_flagsourceconfigurations.yaml | 48 ++++++++++++ controllers/common/flagd-injector.go | 8 ++ controllers/common/flagd-injector_test.go | 50 ++++++++++++ docs/crds.md | 77 +++++++++++++++++++ docs/flag_source_configuration.md | 28 ++++--- 13 files changed, 218 insertions(+), 10 deletions(-) diff --git a/apis/core/v1alpha1/flagsourceconfiguration_types.go b/apis/core/v1alpha1/flagsourceconfiguration_types.go index d745336db..89f01c1d3 100644 --- a/apis/core/v1alpha1/flagsourceconfiguration_types.go +++ b/apis/core/v1alpha1/flagsourceconfiguration_types.go @@ -132,6 +132,10 @@ type FlagSourceConfigurationSpec struct { // OtelCollectorUri defines whether to enable --otel-collector-uri flag of flagd sidecar. Default false (disabled). // +optional OtelCollectorUri string `json:"otelCollectorUri"` + + // Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. + // +optional + Resources corev1.ResourceRequirements `json:"resources"` } type Source struct { diff --git a/apis/core/v1alpha1/zz_generated.deepcopy.go b/apis/core/v1alpha1/zz_generated.deepcopy.go index bb80a51e6..779a4fc86 100644 --- a/apis/core/v1alpha1/zz_generated.deepcopy.go +++ b/apis/core/v1alpha1/zz_generated.deepcopy.go @@ -286,6 +286,7 @@ func (in *FlagSourceConfigurationSpec) DeepCopyInto(out *FlagSourceConfiguration *out = new(bool) **out = **in } + in.Resources.DeepCopyInto(&out.Resources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlagSourceConfigurationSpec. diff --git a/apis/core/v1alpha2/featureflagconfiguration_types.go b/apis/core/v1alpha2/featureflagconfiguration_types.go index b284a709c..ad207d9d9 100644 --- a/apis/core/v1alpha2/featureflagconfiguration_types.go +++ b/apis/core/v1alpha2/featureflagconfiguration_types.go @@ -45,6 +45,9 @@ type FeatureFlagConfigurationSpec struct { FlagDSpec *FlagDSpec `json:"flagDSpec"` // FeatureFlagSpec is the structured representation of the feature flag specification FeatureFlagSpec FeatureFlagSpec `json:"featureFlagSpec,omitempty"` + // Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. + // +optional + Resources corev1.ResourceRequirements `json:"resources"` } type FlagDSpec struct { diff --git a/apis/core/v1alpha2/zz_generated.deepcopy.go b/apis/core/v1alpha2/zz_generated.deepcopy.go index 51fc8722a..0e3f805e0 100644 --- a/apis/core/v1alpha2/zz_generated.deepcopy.go +++ b/apis/core/v1alpha2/zz_generated.deepcopy.go @@ -105,6 +105,7 @@ func (in *FeatureFlagConfigurationSpec) DeepCopyInto(out *FeatureFlagConfigurati (*in).DeepCopyInto(*out) } in.FeatureFlagSpec.DeepCopyInto(&out.FeatureFlagSpec) + in.Resources.DeepCopyInto(&out.Resources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FeatureFlagConfigurationSpec. diff --git a/apis/core/v1alpha3/flagsourceconfiguration_types.go b/apis/core/v1alpha3/flagsourceconfiguration_types.go index 56413e113..2eea0d9e7 100644 --- a/apis/core/v1alpha3/flagsourceconfiguration_types.go +++ b/apis/core/v1alpha3/flagsourceconfiguration_types.go @@ -96,6 +96,10 @@ type FlagSourceConfigurationSpec struct { // OtelCollectorUri defines whether to enable --otel-collector-uri flag of flagd sidecar. Default false (disabled). // +optional OtelCollectorUri string `json:"otelCollectorUri"` + + // Resources defines flagd sidecar resources. Default to operator sidecar-cpu-* and sidecar-ram-* flags. + // +optional + Resources corev1.ResourceRequirements `json:"resources"` } type Source struct { diff --git a/apis/core/v1alpha3/zz_generated.deepcopy.go b/apis/core/v1alpha3/zz_generated.deepcopy.go index 29962c22b..9e0f9f634 100644 --- a/apis/core/v1alpha3/zz_generated.deepcopy.go +++ b/apis/core/v1alpha3/zz_generated.deepcopy.go @@ -120,6 +120,7 @@ func (in *FlagSourceConfigurationSpec) DeepCopyInto(out *FlagSourceConfiguration *out = new(bool) **out = **in } + in.Resources.DeepCopyInto(&out.Resources) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlagSourceConfigurationSpec. diff --git a/chart/open-feature-operator/README.md b/chart/open-feature-operator/README.md index 7bfd1936b..7defbc8bb 100644 --- a/chart/open-feature-operator/README.md +++ b/chart/open-feature-operator/README.md @@ -108,6 +108,7 @@ The command removes all the Kubernetes components associated with the chart and | `sidecarConfiguration.probesEnabled` | Enable or Disable Liveness and Readiness probes of the flagd sidecar. When enabled, HTTP probes( paths - `/readyz`, `/healthz`) are set with an initial delay of 5 seconds. | `true` | | `sidecarConfiguration.debugLogging` | Controls the addition of the `--debug` flag to the container startup arguments. | `false` | | `sidecarConfiguration.otelCollectorUri` | Otel exporter uri. | `""` | +| `sidecarConfiguration.resources` | Override resources of the flagd sidecar. | `{}` | ### Flagd-proxy configuration diff --git a/chart/open-feature-operator/values.yaml b/chart/open-feature-operator/values.yaml index a54897333..e7c6e82d9 100644 --- a/chart/open-feature-operator/values.yaml +++ b/chart/open-feature-operator/values.yaml @@ -33,6 +33,8 @@ sidecarConfiguration: debugLogging: false ## @param sidecarConfiguration.otelCollectorUri Otel exporter uri. otelCollectorUri: "" + ## @param sidecarConfiguration.resources Override resources of the flagd sidecar. + resources: { } ## @section Flagd-proxy configuration flagdProxyConfiguration: diff --git a/config/crd/bases/core.openfeature.dev_flagsourceconfigurations.yaml b/config/crd/bases/core.openfeature.dev_flagsourceconfigurations.yaml index 9fce17478..da40f1f67 100644 --- a/config/crd/bases/core.openfeature.dev_flagsourceconfigurations.yaml +++ b/config/crd/bases/core.openfeature.dev_flagsourceconfigurations.yaml @@ -189,6 +189,54 @@ spec: description: ProbesEnabled defines whether to enable liveness and readiness probes of flagd sidecar. Default true (enabled). type: boolean + resources: + description: Resources defines flagd sidecar resources. Default to + operator sidecar-cpu-limit and sidecar-ram-limit flags. + properties: + claims: + description: "Claims lists the names of resources, defined in + spec.resourceClaims, that are used by this container. \n This + is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be set + for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims + of the Pod where this field is used. It makes that resource + available inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute resources + allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object rolloutOnChange: description: RolloutOnChange dictates whether annotated deployments will be restarted when configuration changes are detected in this diff --git a/controllers/common/flagd-injector.go b/controllers/common/flagd-injector.go index f0fa4facb..3ad44679e 100644 --- a/controllers/common/flagd-injector.go +++ b/controllers/common/flagd-injector.go @@ -104,6 +104,14 @@ func (fi *FlagdContainerInjector) InjectFlagd( ) } + if len(flagSourceConfig.Resources.Requests) != 0 { + flagdContainer.Resources.Requests = flagSourceConfig.Resources.Requests + } + + if len(flagSourceConfig.Resources.Limits) != 0 { + flagdContainer.Resources.Limits = flagSourceConfig.Resources.Limits + } + addFlagdContainer(podSpec, flagdContainer) return nil diff --git a/controllers/common/flagd-injector_test.go b/controllers/common/flagd-injector_test.go index b4613b5c7..c988b18d0 100644 --- a/controllers/common/flagd-injector_test.go +++ b/controllers/common/flagd-injector_test.go @@ -9,6 +9,7 @@ import ( "github.com/open-feature/open-feature-operator/pkg/utils" "github.com/stretchr/testify/require" appsV1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -137,6 +138,55 @@ func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithOtelCollectorUri(t require.Equal(t, expectedDeployment, deployment) } +func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithResources(t *testing.T) { + + namespace, fakeClient := initContainerInjectionTestEnv() + + fi := &FlagdContainerInjector{ + Client: fakeClient, + Logger: testr.New(t), + FlagdProxyConfig: getProxyConfig(), + FlagDResourceRequirements: getResourceRequirements(), + } + + deployment := appsV1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + Namespace: namespace, + }, + Spec: appsV1.DeploymentSpec{}, + } + + flagSourceConfig := getFlagSourceConfigSpec() + + flagSourceConfig.DefaultSyncProvider = v1alpha1.SyncProviderGrpc + + flagSourceConfig.Resources = corev1.ResourceRequirements{ + Limits: map[corev1.ResourceName]resource.Quantity{ + corev1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI), + corev1.ResourceMemory: *resource.NewQuantity(256*1<<20, resource.BinarySI), + }, + Requests: map[corev1.ResourceName]resource.Quantity{ + corev1.ResourceCPU: *resource.NewMilliQuantity(100, resource.DecimalSI), + corev1.ResourceMemory: *resource.NewQuantity(256*1<<20, resource.BinarySI), + }, + } + + flagSourceConfig.Sources = []v1alpha1.Source{{}} + + err := fi.InjectFlagd(context.Background(), &deployment.ObjectMeta, &deployment.Spec.Template.Spec, flagSourceConfig) + require.Nil(t, err) + + expectedDeployment := getExpectedDeployment(namespace) + + expectedDeployment.Annotations = nil + + expectedDeployment.Spec.Template.Spec.Containers[0].Args = []string{"start", "--sources", "[{\"uri\":\"\",\"provider\":\"grpc\"}]"} + expectedDeployment.Spec.Template.Spec.Containers[0].Resources = flagSourceConfig.Resources + + require.Equal(t, expectedDeployment, deployment) +} + func TestFlagdContainerInjector_InjectDefaultSyncProvider_WithSyncProviderArgs(t *testing.T) { namespace, fakeClient := initContainerInjectionTestEnv() diff --git a/docs/crds.md b/docs/crds.md index f252a2702..bc8ebbe4e 100644 --- a/docs/crds.md +++ b/docs/crds.md @@ -733,6 +733,13 @@ FlagSourceConfigurationSpec defines the desired state of FlagSourceConfiguration ProbesEnabled defines whether to enable liveness and readiness probes of flagd sidecar. Default true (enabled).
false + + resources + object + + Resources defines flagd sidecar resources. Default to operator sidecar-cpu-limit and sidecar-ram-limit flags.
+ + false rolloutOnChange boolean @@ -1079,6 +1086,76 @@ Selects a key of a secret in the pod's namespace + +### FlagSourceConfiguration.spec.resources +[↩ Parent](#flagsourceconfigurationspec) + + + +Resources defines flagd sidecar resources. Default to operator sidecar-cpu-limit and sidecar-ram-limit flags. + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
claims[]object + Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. + This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. + This field is immutable. It can only be set for containers.
+
false
limitsmap[string]int or string + Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+
false
requestsmap[string]int or string + Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
+
false
+ + +### FlagSourceConfiguration.spec.resources.claims[index] +[↩ Parent](#flagsourceconfigurationspecresources) + + + +ResourceClaim references one entry in PodSpec.ResourceClaims. + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
namestring + Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container.
+
true
+ # core.openfeature.dev/v1alpha2 Resource Types: diff --git a/docs/flag_source_configuration.md b/docs/flag_source_configuration.md index 1b93161f1..a09f81ba7 100644 --- a/docs/flag_source_configuration.md +++ b/docs/flag_source_configuration.md @@ -84,15 +84,16 @@ sources: `FlagSourceConfiguration` further allows to provide configurations to the injected flagd sidecar. Table given below is non-exhaustive list of overriding options, -| Configuration | Explanation | Default | -|------------------|-------------------------------|----------------------------| -| port | Flag evaluation endpoint port | 8013 | -| metricsPort | Metrics port | 8014 | -| evaluator | Evaluator to use | json | -| image | flagD image | ghcr.io/open-feature/flagd | -| tag | flagD image tag | Latest tag | -| probesEnabled | Enable/Disable health probes | true | -| otelCollectorUri | Otel exporter uri | | +| Configuration | Explanation | Default | +|------------------|-------------------------------|------------------------------------------------| +| port | Flag evaluation endpoint port | 8013 | +| metricsPort | Metrics port | 8014 | +| evaluator | Evaluator to use | json | +| image | flagD image | ghcr.io/open-feature/flagd | +| tag | flagD image tag | Latest tag | +| probesEnabled | Enable/Disable health probes | true | +| otelCollectorUri | Otel exporter uri | | +| resources | flagD resources | operator sidecar-cpu-* and sidecar-ram-* flags | ## Merging of configurations @@ -118,7 +119,7 @@ metadata: name: flag-source-sample spec: metricsPort: 8080 - Port: 80 + port: 80 evaluator: json image: my-custom-sidecar-image defaultSyncProvider: filepath @@ -135,6 +136,13 @@ spec: probesEnabled: true debugLogging: false otelCollectorUri: http://localhost:4317 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi ``` The relevant `FlagSourceConfigurations` are passed to the operator by setting the `openfeature.dev/flagsourceconfiguration` annotation, and is responsible for providing the full configuration of the injected sidecar.