This is an automated email from the ASF dual-hosted git repository.
gfournier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push:
new 58034c08f feat(ctrl): default builder pod resources
58034c08f is described below
commit 58034c08ffd3103b4a9568e4f8877580e25c797d
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Sat Feb 1 09:23:01 2025 +0100
feat(ctrl): default builder pod resources
Closes #5811
---
e2e/native/native_with_sources_test.go | 9 ++--
pkg/controller/build/build_pod.go | 37 +++++++++----
pkg/controller/build/build_pod_test.go | 95 ++++++++++++++++++++++++++++++++++
pkg/trait/builder.go | 12 ++++-
4 files changed, 138 insertions(+), 15 deletions(-)
diff --git a/e2e/native/native_with_sources_test.go
b/e2e/native/native_with_sources_test.go
index 6ceeb3cf9..5adfa807d 100644
--- a/e2e/native/native_with_sources_test.go
+++ b/e2e/native/native_with_sources_test.go
@@ -41,7 +41,8 @@ func TestNativeHighMemoryIntegrations(t *testing.T) {
t.Run("java native support", func(t *testing.T) {
name := javaNativeName
- g.Expect(KamelRun(t, ctx, ns, "files/Java.java",
"--name", name, "-t", "quarkus.build-mode=native", "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
+ g.Expect(KamelRun(t, ctx, ns, "files/Java.java",
"--name", name, "-t", "quarkus.build-mode=native",
+ "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns, name),
TestTimeoutVeryLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPod(t, ctx, ns, name),
TestTimeoutShort).
@@ -52,7 +53,8 @@ func TestNativeHighMemoryIntegrations(t *testing.T) {
t.Run("java native same should not rebuild", func(t
*testing.T) {
name := javaNativeCloneName
- g.Expect(KamelRun(t, ctx, ns,
"files/Java.java", "--name", name, "-t", "quarkus.build-mode=native", "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
+ g.Expect(KamelRun(t, ctx, ns,
"files/Java.java", "--name", name, "-t", "quarkus.build-mode=native",
+ "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
// This one should run quickly as it suppose to
reuse an IntegrationKit
g.Eventually(IntegrationPodPhase(t, ctx, ns,
name), TestTimeoutShort).Should(Equal(corev1.PodRunning))
@@ -66,7 +68,8 @@ func TestNativeHighMemoryIntegrations(t *testing.T) {
t.Run("java native should rebuild", func(t *testing.T) {
name := javaNative2Name
- g.Expect(KamelRun(t, ctx, ns,
"files/Java2.java", "--name", name, "-t", "quarkus.build-mode=native", "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
+ g.Expect(KamelRun(t, ctx, ns,
"files/Java2.java", "--name", name, "-t", "quarkus.build-mode=native",
+ "-t",
"builder.tasks-limit-memory=quarkus-native:9.5Gi").Execute()).To(Succeed())
g.Eventually(IntegrationPodPhase(t, ctx, ns,
name), TestTimeoutVeryLong).Should(Equal(corev1.PodRunning))
g.Eventually(IntegrationPod(t, ctx, ns, name),
TestTimeoutShort).
diff --git a/pkg/controller/build/build_pod.go
b/pkg/controller/build/build_pod.go
index 2b2b87798..15995a56a 100644
--- a/pkg/controller/build/build_pod.go
+++ b/pkg/controller/build/build_pod.go
@@ -107,8 +107,15 @@ func newBuildPod(ctx context.Context, client
client.Client, build *v1.Build) *co
return pod
}
-func configureResources(taskName string, build *v1.Build, container
*corev1.Container) {
+func configureTaskResources(taskName string, build *v1.Build, container
*corev1.Container) {
conf := build.TaskConfiguration(taskName)
+ configureResources(taskName, build, container,
+ conf.RequestCPU, conf.LimitCPU, conf.RequestMemory,
conf.LimitMemory)
+}
+
+func configureResources(
+ taskName string, build *v1.Build, container *corev1.Container,
+ requestCPU, limitCPU, requestMemory, limitMemory string) {
requestsList := container.Resources.Requests
limitsList := container.Resources.Limits
var err error
@@ -119,25 +126,25 @@ func configureResources(taskName string, build *v1.Build,
container *corev1.Cont
limitsList = make(corev1.ResourceList)
}
- requestsList, err = kubernetes.ConfigureResource(conf.RequestCPU,
requestsList, corev1.ResourceCPU)
+ requestsList, err = kubernetes.ConfigureResource(requestCPU,
requestsList, corev1.ResourceCPU)
if err != nil {
Log.WithValues("request-namespace", build.Namespace,
"request-name", build.Name).
- Errorf(err, "Could not configure builder resource cpu,
leaving default value")
+ Errorf(err, "Could not configure %s resource cpu,
leaving default value", taskName)
}
- requestsList, err = kubernetes.ConfigureResource(conf.RequestMemory,
requestsList, corev1.ResourceMemory)
+ requestsList, err = kubernetes.ConfigureResource(requestMemory,
requestsList, corev1.ResourceMemory)
if err != nil {
Log.WithValues("request-namespace", build.Namespace,
"request-name", build.Name).
- Errorf(err, "Could not configure builder resource
memory, leaving default value")
+ Errorf(err, "Could not configure %s resource memory,
leaving default value", taskName)
}
- limitsList, err = kubernetes.ConfigureResource(conf.LimitCPU,
limitsList, corev1.ResourceCPU)
+ limitsList, err = kubernetes.ConfigureResource(limitCPU, limitsList,
corev1.ResourceCPU)
if err != nil {
Log.WithValues("request-namespace", build.Namespace,
"request-name", build.Name).
- Errorf(err, "Could not configure builder limit cpu,
leaving default value")
+ Errorf(err, "Could not configure %s limit cpu, leaving
default value", taskName)
}
- limitsList, err = kubernetes.ConfigureResource(conf.LimitMemory,
limitsList, corev1.ResourceMemory)
+ limitsList, err = kubernetes.ConfigureResource(limitMemory, limitsList,
corev1.ResourceMemory)
if err != nil {
Log.WithValues("request-namespace", build.Namespace,
"request-name", build.Name).
- Errorf(err, "Could not configure builder limit memory,
leaving default value")
+ Errorf(err, "Could not configure %s limit memory,
leaving default value", taskName)
}
container.Resources.Requests = requestsList
@@ -228,7 +235,12 @@ func addBuildTaskToPod(ctx context.Context, client
client.Client, build *v1.Buil
}
}
- configureResources(taskName, build, &container)
+ // Default resources for a build. We set a high upper bound limit
+ // in order to let any heavy Maven build to run without problems.
+ // If the process cannot complete, then the user should increase these
limits accordingly.
+ configureResources(taskName, build, &container, "500m", "1", "512Mi",
"4Gi")
+ // possible user based resource configuration
+ configureTaskResources(taskName, build, &container)
addContainerToPod(build, container, pod)
}
@@ -249,7 +261,10 @@ func addCustomTaskToPod(build *v1.Build, task
*v1.UserTask, pod *corev1.Pod) {
}
}
- configureResources(task.Name, build, &container)
+ // Default resources for a custom task. We assume some
+ // lighter process which won't require too much resources.
+ configureResources(task.Name, build, &container, "250m", "500m",
"256Mi", "1Gi")
+ configureTaskResources(task.Name, build, &container)
addContainerToPod(build, container, pod)
}
diff --git a/pkg/controller/build/build_pod_test.go
b/pkg/controller/build/build_pod_test.go
index 7a41d3923..97727f454 100644
--- a/pkg/controller/build/build_pod_test.go
+++ b/pkg/controller/build/build_pod_test.go
@@ -25,6 +25,7 @@ import (
"github.com/apache/camel-k/v2/pkg/internal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+ corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
@@ -67,3 +68,97 @@ func TestNewBuildPodConfiguration(t *testing.T) {
assert.Equal(t, map[string]string{"node": "selector"},
pod.Spec.NodeSelector)
assert.Equal(t, map[string]string{"annotation": "value"},
pod.Annotations)
}
+
+func TestConfigureResourcesDefault(t *testing.T) {
+ build := v1.Build{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "theBuildName",
+ },
+ Spec: v1.BuildSpec{
+ Tasks: []v1.Task{
+ {
+ Builder: &v1.BuilderTask{
+ BaseTask: v1.BaseTask{
+ Name:
"builder",
+ Configuration:
v1.BuildConfiguration{},
+ },
+ },
+ },
+ },
+ },
+ }
+
+ container := corev1.Container{}
+ configureResources("builder", &build, &container, "250m", "500m",
"512Mi", "1Gi")
+ configureTaskResources("builder", &build, &container)
+
+ assert.Equal(t, "250m", container.Resources.Requests.Cpu().String())
+ assert.Equal(t, "500m", container.Resources.Limits.Cpu().String())
+ assert.Equal(t, "512Mi", container.Resources.Requests.Memory().String())
+ assert.Equal(t, "1Gi", container.Resources.Limits.Memory().String())
+}
+
+func TestConfigureResources(t *testing.T) {
+ build := v1.Build{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "theBuildName",
+ },
+ Spec: v1.BuildSpec{
+ Tasks: []v1.Task{
+ {
+ Builder: &v1.BuilderTask{
+ BaseTask: v1.BaseTask{
+ Name: "builder",
+ Configuration:
v1.BuildConfiguration{
+ RequestCPU:
"500m",
+ LimitCPU:
"1000m",
+ RequestMemory:
"512Mi",
+ LimitMemory:
"2048Mi",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ container := corev1.Container{}
+ configureTaskResources("builder", &build, &container)
+
+ assert.Equal(t, "500m", container.Resources.Requests.Cpu().String())
+ assert.Equal(t, "1", container.Resources.Limits.Cpu().String())
+ assert.Equal(t, "512Mi", container.Resources.Requests.Memory().String())
+ assert.Equal(t, "2Gi", container.Resources.Limits.Memory().String())
+}
+
+func TestConfigureResourcesOverride(t *testing.T) {
+ build := v1.Build{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "theBuildName",
+ },
+ Spec: v1.BuildSpec{
+ Tasks: []v1.Task{
+ {
+ Builder: &v1.BuilderTask{
+ BaseTask: v1.BaseTask{
+ Name: "builder",
+ Configuration:
v1.BuildConfiguration{
+ RequestCPU:
"500m",
+ LimitCPU:
"1000m",
+ RequestMemory:
"512Mi",
+ LimitMemory:
"2048Mi",
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+ container := corev1.Container{}
+ configureResources("builder", &build, &container, "10m", "50m",
"100Mi", "200Mi")
+ configureTaskResources("builder", &build, &container)
+
+ assert.Equal(t, "500m", container.Resources.Requests.Cpu().String())
+ assert.Equal(t, "1", container.Resources.Limits.Cpu().String())
+ assert.Equal(t, "512Mi", container.Resources.Requests.Memory().String())
+ assert.Equal(t, "2Gi", container.Resources.Limits.Memory().String())
+}
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index 5291add36..6b066e48d 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -124,6 +124,7 @@ func (t *builderTrait) configureForQuarkus(trait Trait, e
*Environment, conditio
return condition, err
}
+ //nolint: nestif
if ok && (isNativeIntegration || isNativeKit) {
// TODO expect maven repository in local repo (need to change
builder pod accordingly!)
command :=
builder.QuarkusRuntimeSupport(e.CamelCatalog.GetCamelQuarkusVersion()).BuildCommands()
@@ -136,7 +137,9 @@ func (t *builderTrait) configureForQuarkus(trait Trait, e
*Environment, conditio
// it should be performed as the last custom task
t.Tasks = append(t.Tasks,
fmt.Sprintf(`quarkus-native;%s;/bin/bash -c "%s"`, nativeBuilderImage, command))
// Force the build to run in a separate Pod and strictly
sequential
- m := "This is a Quarkus native build: setting build
configuration with build Pod strategy and native container sensible resources
(if not specified by the user). Make sure your cluster can handle it."
+ m := "This is a Quarkus native build: setting default build
configuration with build Pod strategy and " +
+ "native container sensible resources (max 4 cpus, 16 Gi
memory, unless specified by the user). " +
+ "Make sure your cluster can handle it."
t.L.Info(m)
condition = newOrAppend(condition, m)
@@ -149,11 +152,18 @@ func (t *builderTrait) configureForQuarkus(trait Trait, e
*Environment, conditio
if !existsTaskRequest(t.TasksRequestMemory, "quarkus-native") {
t.TasksRequestMemory = append(t.TasksRequestMemory,
"quarkus-native:4Gi")
}
+ if !existsTaskRequest(t.TasksLimitCPU, "quarkus-native") {
+ t.TasksLimitCPU = append(t.TasksLimitCPU,
"quarkus-native:4000m")
+ }
+ if !existsTaskRequest(t.TasksLimitMemory, "quarkus-native") {
+ t.TasksLimitMemory = append(t.TasksLimitMemory,
"quarkus-native:16Gi")
+ }
}
return condition, nil
}
+//nolint:unparam
func existsTaskRequest(tasks []string, taskName string) bool {
for _, task := range tasks {
ts := strings.Split(task, ":")