diff --git a/api/v1/coherencejobresource_types.go b/api/v1/coherencejobresource_types.go index 7f043bf2..5aa2c1d9 100644 --- a/api/v1/coherencejobresource_types.go +++ b/api/v1/coherencejobresource_types.go @@ -76,6 +76,13 @@ func (in *CoherenceJob) GetGlobalSpec() *GlobalSpec { return in.Spec.Global } +func (in *CoherenceJob) GetInitResources() *corev1.ResourceRequirements { + if in == nil { + return nil + } + return in.Spec.InitResources +} + // GetSpec returns this resource's CoherenceResourceSpec func (in *CoherenceJob) GetSpec() *CoherenceResourceSpec { return &in.Spec.CoherenceResourceSpec @@ -453,6 +460,12 @@ type CoherenceJobResourceSpec struct { EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"` // Global contains attributes that will be applied to all resources managed by the Coherence Operator. Global *GlobalSpec `json:"global,omitempty"` + // InitResources is the optional resource requests and limits for the init-container that the Operator + // adds to the Pod. + // ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // The Coherence operator does not apply any default resources. + // +optional + InitResources *corev1.ResourceRequirements `json:"initResources,omitempty"` } // GetRestartPolicy returns the name of the application image to use diff --git a/api/v1/coherenceresource.go b/api/v1/coherenceresource.go index 9626da46..936cc714 100644 --- a/api/v1/coherenceresource.go +++ b/api/v1/coherenceresource.go @@ -98,4 +98,6 @@ type CoherenceResource interface { GetEnvVarFrom() []corev1.EnvFromSource // GetGlobalSpec returns the attributes to be applied to all resources GetGlobalSpec() *GlobalSpec + // GetInitResources returns the optional resource requirements for the init container + GetInitResources() *corev1.ResourceRequirements } diff --git a/api/v1/coherenceresource_types.go b/api/v1/coherenceresource_types.go index 525329e1..e4b024e3 100644 --- a/api/v1/coherenceresource_types.go +++ b/api/v1/coherenceresource_types.go @@ -194,6 +194,13 @@ func (in *Coherence) GetGlobalSpec() *GlobalSpec { return in.Spec.Global } +func (in *Coherence) GetInitResources() *corev1.ResourceRequirements { + if in == nil { + return nil + } + return in.Spec.InitResources +} + // FindFullyQualifiedPortServiceNames returns a map of the exposed ports of this resource mapped to their Service's // fully qualified domain name. func (in *Coherence) FindFullyQualifiedPortServiceNames() map[string]string { @@ -497,6 +504,12 @@ type CoherenceStatefulSetResourceSpec struct { EnvFrom []corev1.EnvFromSource `json:"envFrom,omitempty"` // Global contains attributes that will be applied to all resources managed by the Coherence Operator. Global *GlobalSpec `json:"global,omitempty"` + // InitResources is the optional resource requests and limits for the init-container that the Operator + // adds to the Pod. + // ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + // The Coherence operator does not apply any default resources. + // +optional + InitResources *corev1.ResourceRequirements `json:"initResources,omitempty"` } // CreateStatefulSetResource creates the deployment's StatefulSet resource. diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 6fab9fd6..f4164f01 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -1046,6 +1046,12 @@ func (in *CoherenceResourceSpec) CreateOperatorInitContainer(deployment Coherenc // set the persistence volume mounts if required in.Coherence.AddPersistenceVolumeMounts(&c) + // set the container resources if specified + r := deployment.GetInitResources() + if r != nil { + c.Resources = *r + } + return c } diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index 7c0dfd9d..75ce9d6e 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -280,6 +280,31 @@ func TestCreateStatefulSetWithPodAnnotations(t *testing.T) { assertStatefulSetCreation(t, deployment, stsExpected) } +func TestCreateStatefulSetWithInitContainerResources(t *testing.T) { + res := corev1.ResourceRequirements{ + Limits: map[corev1.ResourceName]resource.Quantity{ + corev1.ResourceCPU: resource.MustParse("8"), + }, + Requests: map[corev1.ResourceName]resource.Quantity{ + corev1.ResourceCPU: resource.MustParse("4"), + }, + } + + spec := coh.CoherenceStatefulSetResourceSpec{ + InitResources: &res, + } + + // Create the test deployment + deployment := createTestCoherenceDeployment(spec) + + // Create expected StatefulSet + stsExpected := createMinimalExpectedStatefulSet(deployment) + stsExpected.Spec.Template.Spec.InitContainers[0].Resources = res + + // assert that the StatefulSet is as expected + assertStatefulSetCreation(t, deployment, stsExpected) +} + func TestCreateStatefulSetWithResources(t *testing.T) { res := corev1.ResourceRequirements{ Limits: map[corev1.ResourceName]resource.Quantity{ diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 077547b0..0ab6f2f3 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -352,6 +352,11 @@ func (in *CoherenceJobResourceSpec) DeepCopyInto(out *CoherenceJobResourceSpec) *out = new(GlobalSpec) (*in).DeepCopyInto(*out) } + if in.InitResources != nil { + in, out := &in.InitResources, &out.InitResources + *out = new(corev1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoherenceJobResourceSpec. @@ -898,6 +903,11 @@ func (in *CoherenceStatefulSetResourceSpec) DeepCopyInto(out *CoherenceStatefulS *out = new(GlobalSpec) (*in).DeepCopyInto(*out) } + if in.InitResources != nil { + in, out := &in.InitResources, &out.InitResources + *out = new(corev1.ResourceRequirements) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CoherenceStatefulSetResourceSpec. diff --git a/config/manager/webhook-secret.yaml b/config/manager/webhook-secret.yaml index 95dec509..df6957c8 100644 --- a/config/manager/webhook-secret.yaml +++ b/config/manager/webhook-secret.yaml @@ -7,3 +7,5 @@ kind: Secret metadata: name: coherence-webhook-server-cert namespace: coherence + labels: + control-plane: coherence diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml index 4190ec80..36bfb341 100644 --- a/config/rbac/leader_election_role.yaml +++ b/config/rbac/leader_election_role.yaml @@ -3,6 +3,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: leader-election-role + labels: + control-plane: coherence rules: - apiGroups: - "" diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml index f6f38be3..b9958d30 100644 --- a/config/rbac/leader_election_role_binding.yaml +++ b/config/rbac/leader_election_role_binding.yaml @@ -2,6 +2,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: leader-election-rolebinding + labels: + control-plane: coherence roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 472c2756..500e3dc5 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,8 +2,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role + labels: + control-plane: coherence rules: - apiGroups: - "" diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index 24fca13b..59289807 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -921,6 +921,9 @@ m| allowUnsafeDelete | AllowUnsafeDelete controls whether the Operator will add m| actions | Actions to execute once all the Pods are ready after an initial deployment m| []<> | false m| envFrom | List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. m| []https://{k8s-doc-link}/#envfromsource-v1-core[corev1.EnvFromSource] | false m| global | Global contains attributes that will be applied to all resources managed by the Coherence Operator. m| *<> | false +m| initResources | InitResources is the optional resource requests and limits for the init-container that the Operator adds to the Pod. + + ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + + +The Coherence operator does not apply any default resources. m| *https://{k8s-doc-link}/#resourcerequirements-v1-core[corev1.ResourceRequirements] | false |=== <> diff --git a/docs/other/100_resources.adoc b/docs/other/100_resources.adoc index 59680928..d6b8fccf 100644 --- a/docs/other/100_resources.adoc +++ b/docs/other/100_resources.adoc @@ -1,6 +1,6 @@ /////////////////////////////////////////////////////////////////////////////// - Copyright (c) 2020, Oracle and/or its affiliates. + Copyright (c) 2020, 2024, Oracle and/or its affiliates. Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. @@ -37,7 +37,36 @@ spec: memory: "128Mi" cpu: "500m" ---- -<1> The `coherence` container in the `Pods` has a request of 0.25 cpu and 64MiB of memory. -The `coherence` container has a limit of 0.5 cpu and 128MiB of memory. +<1> The `coherence` container in the `Pods` will have requests of 0.25 cpu and 64MiB of memory, +and limits of 0.5 cpu and 128MiB of memory. +== InitContainer Resource Limits + +The Coherence Operator adds an init-container to the Pods that it manages. This init container does nothing more +than copy some files and ensure some directories exist. In terms of resource use it is extremely light. +Some customers have expressed a desire to still be able to set limits fo this init container, so this is possible +using the `spec.initResources` field. + +For example: + +[source,yaml] +---- +apiVersion: coherence.oracle.com/v1 +kind: Coherence +metadata: + name: test-cluster +spec: + initResources: # <1> + requests: + memory: "64Mi" + cpu: "250m" + limits: + memory: "128Mi" + cpu: "500m" +---- +<1> The `coherence-k8s-utils` init-container in the `Pods` will have requests of 0.25 cpu and 64MiB of memory, +and limits of 0.5 cpu and 128MiB of memory. + +These resources only applies to the init-container that the Operator creates, any other init-containers added in the +`spec.initContainers` section should have their own resources configured. diff --git a/helm-charts/coherence-operator/templates/rbac.yaml b/helm-charts/coherence-operator/templates/rbac.yaml index 44d6d509..b419250a 100644 --- a/helm-charts/coherence-operator/templates/rbac.yaml +++ b/helm-charts/coherence-operator/templates/rbac.yaml @@ -246,6 +246,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: leader-election-role + labels: + control-plane: coherence rules: - apiGroups: - "" @@ -287,6 +289,8 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: leader-election-rolebinding + labels: + control-plane: coherence roleRef: apiGroup: rbac.authorization.k8s.io kind: Role