Skip to content

Commit ae02a43

Browse files
Add configurable container resource requests and limits via CR spec
Allow users to override CPU/memory requests and limits for user-facing containers (llamaStack, lightspeedService, postgres, okp, consolePlugin) through the OpenStackLightspeed CR spec. Internal containers (dataverse exporter, vector-database init) keep hardcoded defaults since they are implementation details not exposed to users. Defaults are applied by the API server via kubebuilder markers.
1 parent c31f299 commit ae02a43

15 files changed

Lines changed: 947 additions & 110 deletions

api/v1beta1/openstacklightspeed_types.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1beta1
1919
import (
2020
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
2121
"github.com/openstack-k8s-operators/lib-common/modules/common/util"
22+
corev1 "k8s.io/api/core/v1"
2223
"k8s.io/apimachinery/pkg/api/resource"
2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/runtime"
@@ -91,6 +92,40 @@ type DatabaseSpec struct {
9192
Class string `json:"class,omitempty"`
9293
}
9394

95+
// ContainerResourcesSpec defines resource requirements for each container
96+
// managed by the operator. Defaults are applied by the API server via
97+
// kubebuilder markers. Users may override any container's resources in
98+
// the CR; the provided value replaces the default entirely.
99+
type ContainerResourcesSpec struct {
100+
// +kubebuilder:validation:Optional
101+
// +kubebuilder:default:={requests: {cpu: "500m", memory: "2Gi"}, limits: {cpu: "2", memory: "8Gi"}}
102+
// LlamaStack sets compute resources for the llama-stack (OGX) container
103+
// in the lightspeed-stack deployment.
104+
LlamaStack corev1.ResourceRequirements `json:"llamaStack,omitempty"`
105+
106+
// +kubebuilder:validation:Optional
107+
// +kubebuilder:default:={requests: {cpu: "250m", memory: "512Mi"}, limits: {cpu: "1", memory: "2Gi"}}
108+
// LightspeedService sets compute resources for the lightspeed-service-api
109+
// container in the lightspeed-stack deployment.
110+
LightspeedService corev1.ResourceRequirements `json:"lightspeedService,omitempty"`
111+
112+
// +kubebuilder:validation:Optional
113+
// +kubebuilder:default:={requests: {cpu: "30m", memory: "300Mi"}, limits: {cpu: "500m", memory: "2Gi"}}
114+
// Postgres sets compute resources for the PostgreSQL container.
115+
Postgres corev1.ResourceRequirements `json:"postgres,omitempty"`
116+
117+
// +kubebuilder:validation:Optional
118+
// +kubebuilder:default:={requests: {cpu: "500m", memory: "2Gi"}, limits: {cpu: "2", memory: "4Gi"}}
119+
// OKP sets compute resources for the Offline Knowledge Portal container.
120+
OKP corev1.ResourceRequirements `json:"okp,omitempty"`
121+
122+
// +kubebuilder:validation:Optional
123+
// +kubebuilder:default:={requests: {cpu: "50m", memory: "64Mi"}, limits: {cpu: "200m", memory: "256Mi"}}
124+
// ConsolePlugin sets compute resources for the lightspeed-console-plugin
125+
// container and its init container.
126+
ConsolePlugin corev1.ResourceRequirements `json:"consolePlugin,omitempty"`
127+
}
128+
94129
// OpenStackLightspeedSpec defines the desired state of OpenStackLightspeed
95130
type OpenStackLightspeedSpec struct {
96131
OpenStackLightspeedCore `json:",inline"`
@@ -105,6 +140,14 @@ type OpenStackLightspeedSpec struct {
105140
// OKP configures the Offline Knowledge Portal (OKP) RAG source.
106141
OKP *OKPSpec `json:"okp,omitempty"`
107142

143+
// +kubebuilder:validation:Optional
144+
// +kubebuilder:default:={}
145+
// Resources configures compute resource requirements for individual
146+
// containers managed by the operator. Each field has sensible defaults
147+
// applied by the API server. Override any container's resources to
148+
// replace its defaults entirely.
149+
Resources ContainerResourcesSpec `json:"resources,omitempty"`
150+
108151
// +kubebuilder:validation:Optional
109152
// +kubebuilder:pruning:PreserveUnknownFields
110153
// Dev contains developer/experimental configuration.

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml

Lines changed: 347 additions & 0 deletions
Large diffs are not rendered by default.

config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml

Lines changed: 347 additions & 0 deletions
Large diffs are not rendered by default.

config/samples/api_v1beta1_openstacklightspeed.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,29 @@ spec:
1515
# database:
1616
# size: "5Gi"
1717
# class: "my-storage-class"
18+
# Uncomment to customize container resource requests/limits:
19+
# resources:
20+
# llamaStack:
21+
# requests:
22+
# cpu: "500m"
23+
# memory: "2Gi"
24+
# limits:
25+
# cpu: "2"
26+
# memory: "8Gi"
27+
# lightspeedService:
28+
# requests:
29+
# cpu: "250m"
30+
# memory: "512Mi"
31+
# limits:
32+
# cpu: "1"
33+
# memory: "2Gi"
34+
# postgres:
35+
# requests:
36+
# cpu: "30m"
37+
# memory: "300Mi"
38+
# limits:
39+
# cpu: "500m"
40+
# memory: "2Gi"
1841
# Uncomment to customize log levels (DEBUG, INFO, WARNING, ERROR, CRITICAL):
1942
# logging:
2043
# ogxLogLevel: "all=info"

internal/controller/console_deployment.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ import (
2020
"fmt"
2121

2222
consolev1 "github.com/openshift/api/console/v1"
23+
apiv1beta1 "github.com/openstack-k8s-operators/lightspeed-operator/api/v1beta1"
2324
appsv1 "k8s.io/api/apps/v1"
2425
corev1 "k8s.io/api/core/v1"
2526
networkingv1 "k8s.io/api/networking/v1"
26-
"k8s.io/apimachinery/pkg/api/resource"
2727
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2828
"k8s.io/apimachinery/pkg/util/intstr"
2929
)
@@ -48,7 +48,9 @@ const consoleLocalesPath = "/usr/share/nginx/html/locales/en/" + consoleLocalesF
4848
// buildConsoleDeploymentSpec builds the Deployment spec for the console plugin.
4949
// Includes an init container that rewrites OpenShift references to OpenStack
5050
// in the locales JSON file using an emptyDir volume.
51-
func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
51+
func buildConsoleDeploymentSpec(consoleImage string, instance *apiv1beta1.OpenStackLightspeed) appsv1.DeploymentSpec {
52+
consoleRes := instance.Spec.Resources.ConsolePlugin
53+
5254
replicas := int32(1)
5355
volumeDefaultMode := VolumeDefaultMode
5456
labels := generateConsoleSelectorLabels()
@@ -86,16 +88,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
8688
"awk '" + consoleLocalesRewriteAwk + "' " +
8789
consoleLocalesPath + " > /locales-rewrite/" + consoleLocalesFilename,
8890
},
89-
Resources: corev1.ResourceRequirements{
90-
Requests: corev1.ResourceList{
91-
corev1.ResourceCPU: resource.MustParse("50m"),
92-
corev1.ResourceMemory: resource.MustParse("64Mi"),
93-
},
94-
Limits: corev1.ResourceList{
95-
corev1.ResourceCPU: resource.MustParse("200m"),
96-
corev1.ResourceMemory: resource.MustParse("256Mi"),
97-
},
98-
},
91+
Resources: consoleRes,
9992
VolumeMounts: []corev1.VolumeMount{
10093
{
10194
Name: "locales-rewrite",
@@ -119,16 +112,7 @@ func buildConsoleDeploymentSpec(consoleImage string) appsv1.DeploymentSpec {
119112
SecurityContext: &corev1.SecurityContext{
120113
AllowPrivilegeEscalation: toPtr(false),
121114
},
122-
Resources: corev1.ResourceRequirements{
123-
Requests: corev1.ResourceList{
124-
corev1.ResourceCPU: resource.MustParse("50m"),
125-
corev1.ResourceMemory: resource.MustParse("64Mi"),
126-
},
127-
Limits: corev1.ResourceList{
128-
corev1.ResourceCPU: resource.MustParse("200m"),
129-
corev1.ResourceMemory: resource.MustParse("256Mi"),
130-
},
131-
},
115+
Resources: consoleRes,
132116
VolumeMounts: []corev1.VolumeMount{
133117
{
134118
Name: "lightspeed-console-plugin-cert",

internal/controller/console_reconciler.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func resolveConsoleImage(ctx context.Context, h *common_helper.Helper) string {
181181
}
182182

183183
// reconcileConsoleDeploymentResource ensures the console plugin deployment exists.
184-
func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error {
184+
func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error {
185185
logger := h.GetLogger()
186186

187187
consoleImage := resolveConsoleImage(ctx, h)
@@ -194,7 +194,7 @@ func reconcileConsoleDeploymentResource(h *common_helper.Helper, ctx context.Con
194194
}
195195

196196
result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), deployment, func() error {
197-
spec := buildConsoleDeploymentSpec(consoleImage)
197+
spec := buildConsoleDeploymentSpec(consoleImage, instance)
198198
deployment.Spec.Replicas = spec.Replicas
199199
deployment.Spec.Selector = spec.Selector
200200
deployment.Spec.Template = spec.Template

internal/controller/console_reconciler_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ var _ = Describe("Console Plugin", func() {
4848
var spec appsv1.DeploymentSpec
4949

5050
BeforeEach(func() {
51-
spec = buildConsoleDeploymentSpec(apiv1beta1.OpenStackLightspeedDefaultValues.ConsoleImagePF5URL)
51+
instance := &apiv1beta1.OpenStackLightspeed{
52+
Spec: apiv1beta1.OpenStackLightspeedSpec{},
53+
}
54+
spec = buildConsoleDeploymentSpec(apiv1beta1.OpenStackLightspeedDefaultValues.ConsoleImagePF5URL, instance)
5255
})
5356

5457
It("should have one replica", func() {

internal/controller/lcore_deployment.go

Lines changed: 25 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,7 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins
109109
TimeoutSeconds: LlamaStackProbeTimeoutSeconds,
110110
FailureThreshold: LlamaStackProbeFailureThreshold,
111111
},
112-
Resources: corev1.ResourceRequirements{
113-
Requests: corev1.ResourceList{
114-
corev1.ResourceCPU: resource.MustParse("500m"),
115-
corev1.ResourceMemory: resource.MustParse("2Gi"),
116-
},
117-
Limits: corev1.ResourceList{
118-
corev1.ResourceCPU: resource.MustParse("2"),
119-
corev1.ResourceMemory: resource.MustParse("8Gi"),
120-
},
121-
},
112+
Resources: instance.Spec.Resources.LlamaStack,
122113
ImagePullPolicy: corev1.PullIfNotPresent,
123114
}
124115

@@ -145,25 +136,16 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins
145136
}
146137

147138
lightspeedStackContainer := corev1.Container{
148-
Name: "lightspeed-service-api",
149-
Image: apiv1beta1.OpenStackLightspeedDefaultValues.LCoreImageURL,
150-
Args: []string{"-c", VectorDBVolumeLightspeedStackConfigPath},
151-
Ports: []corev1.ContainerPort{{Name: "https", ContainerPort: OpenStackLightspeedAppServerContainerPort}},
152-
VolumeMounts: lightspeedStackMounts,
153-
Env: lsEnvVars,
154-
StartupProbe: buildLightspeedStackStartupProbe(),
155-
LivenessProbe: buildLightspeedStackLivenessProbe(),
156-
ReadinessProbe: buildLightspeedStackReadinessProbe(),
157-
Resources: corev1.ResourceRequirements{
158-
Requests: corev1.ResourceList{
159-
corev1.ResourceCPU: resource.MustParse("250m"),
160-
corev1.ResourceMemory: resource.MustParse("512Mi"),
161-
},
162-
Limits: corev1.ResourceList{
163-
corev1.ResourceCPU: resource.MustParse("1"),
164-
corev1.ResourceMemory: resource.MustParse("2Gi"),
165-
},
166-
},
139+
Name: "lightspeed-service-api",
140+
Image: apiv1beta1.OpenStackLightspeedDefaultValues.LCoreImageURL,
141+
Args: []string{"-c", VectorDBVolumeLightspeedStackConfigPath},
142+
Ports: []corev1.ContainerPort{{Name: "https", ContainerPort: OpenStackLightspeedAppServerContainerPort}},
143+
VolumeMounts: lightspeedStackMounts,
144+
Env: lsEnvVars,
145+
StartupProbe: buildLightspeedStackStartupProbe(),
146+
LivenessProbe: buildLightspeedStackLivenessProbe(),
147+
ReadinessProbe: buildLightspeedStackReadinessProbe(),
148+
Resources: instance.Spec.Resources.LightspeedService,
167149
ImagePullPolicy: corev1.PullIfNotPresent,
168150
}
169151
containers := []corev1.Container{llamaStackContainer, lightspeedStackContainer}
@@ -216,7 +198,17 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins
216198
return corev1.PodTemplateSpec{}, err
217199
}
218200

219-
initContainers := buildInitContainers(instance)
201+
initResources := corev1.ResourceRequirements{
202+
Requests: corev1.ResourceList{
203+
corev1.ResourceCPU: resource.MustParse("100m"),
204+
corev1.ResourceMemory: resource.MustParse("256Mi"),
205+
},
206+
Limits: corev1.ResourceList{
207+
corev1.ResourceCPU: resource.MustParse("500m"),
208+
corev1.ResourceMemory: resource.MustParse("1Gi"),
209+
},
210+
}
211+
initContainers := buildInitContainers(instance, initResources)
220212

221213
return corev1.PodTemplateSpec{
222214
ObjectMeta: metav1.ObjectMeta{
@@ -238,7 +230,7 @@ func buildLCorePodTemplateSpec(h *common_helper.Helper, ctx context.Context, ins
238230
// and Lightspeed Stack configuration files, incorporating information from
239231
// the provided vector database images. For details on their logic, see:
240232
// (1) assets/vector_database_collect.sh and (2) assets/vector_database_build.py.
241-
func buildInitContainers(instance *apiv1beta1.OpenStackLightspeed) []corev1.Container {
233+
func buildInitContainers(instance *apiv1beta1.OpenStackLightspeed, initResources corev1.ResourceRequirements) []corev1.Container {
242234
securityContext := &corev1.SecurityContext{
243235
RunAsNonRoot: &[]bool{true}[0],
244236
AllowPrivilegeEscalation: &[]bool{false}[0],
@@ -247,17 +239,6 @@ func buildInitContainers(instance *apiv1beta1.OpenStackLightspeed) []corev1.Cont
247239
},
248240
}
249241

250-
resourceRequirements := corev1.ResourceRequirements{
251-
Requests: corev1.ResourceList{
252-
corev1.ResourceCPU: resource.MustParse("100m"),
253-
corev1.ResourceMemory: resource.MustParse("256Mi"),
254-
},
255-
Limits: corev1.ResourceList{
256-
corev1.ResourceCPU: resource.MustParse("500m"),
257-
corev1.ResourceMemory: resource.MustParse("1Gi"),
258-
},
259-
}
260-
261242
var containers []corev1.Container
262243
containers = append(containers, corev1.Container{
263244
Name: "vector-database-collect",
@@ -268,7 +249,7 @@ func buildInitContainers(instance *apiv1beta1.OpenStackLightspeed) []corev1.Cont
268249
"--enable-okp",
269250
},
270251
SecurityContext: securityContext,
271-
Resources: resourceRequirements,
252+
Resources: initResources,
272253
VolumeMounts: []corev1.VolumeMount{
273254
{
274255
Name: VectorDBVolumeName,
@@ -298,7 +279,7 @@ func buildInitContainers(instance *apiv1beta1.OpenStackLightspeed) []corev1.Cont
298279
Image: apiv1beta1.OpenStackLightspeedDefaultValues.LCoreImageURL,
299280
Command: configBuildCmd,
300281
SecurityContext: securityContext,
301-
Resources: resourceRequirements,
282+
Resources: initResources,
302283
VolumeMounts: []corev1.VolumeMount{
303284
{
304285
Name: VectorDBVolumeName,

internal/controller/okp_reconciler.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
apiv1beta1 "github.com/openstack-k8s-operators/lightspeed-operator/api/v1beta1"
2525
appsv1 "k8s.io/api/apps/v1"
2626
corev1 "k8s.io/api/core/v1"
27-
"k8s.io/apimachinery/pkg/api/resource"
2827
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2928
"k8s.io/apimachinery/pkg/util/intstr"
3029
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -150,16 +149,7 @@ func buildOKPPodTemplateSpec(instance *apiv1beta1.OpenStackLightspeed) corev1.Po
150149
InitialDelaySeconds: 60,
151150
PeriodSeconds: 20,
152151
},
153-
Resources: corev1.ResourceRequirements{
154-
Requests: corev1.ResourceList{
155-
corev1.ResourceCPU: resource.MustParse("500m"),
156-
corev1.ResourceMemory: resource.MustParse("2Gi"),
157-
},
158-
Limits: corev1.ResourceList{
159-
corev1.ResourceCPU: resource.MustParse("2"),
160-
corev1.ResourceMemory: resource.MustParse("4Gi"),
161-
},
162-
},
152+
Resources: instance.Spec.Resources.OKP,
163153
ImagePullPolicy: corev1.PullIfNotPresent,
164154
},
165155
},

0 commit comments

Comments
 (0)