Repository: argoproj/argo
Pull request #4656 (2020-12-07 01:44:35)

feat(controller): Allow to configure main container resources
Some clusters require explicit resources in all containers. This would allow us to configure the resources for the main container.

Signed-off-by: terrytangyuan <terrytangyuan@gmail.com>

Checklist:

* [x] My organization is added to [USERS.md](https://github.com/argoproj/argo/blob/master/USERS.md).

<!--

Please leave your PR in draft if you don't need a review yet. 

To fix failing `CI / Codegen`, run `make codegen`. 

-->


alexec: podSpecPatch?
terrytangyuan: Thanks for the suggestion. It's definitely an option. However, podSpecPatch requires all of our existing users to modify their workflow spec which is not trivial (especially when we have long-running workflows and established usage patterns). Configuring this in the config of controller seems to be a better option for now. 

Patch:
diff --git a/config/config.go b/config/config.go
index b99dbec66..0fee9b66c 100644
--- a/config/config.go
+++ b/config/config.go
@@ -31,6 +31,9 @@ type Config struct {
 	// DEPRECATED: use `executor.resources` in configmap instead
 	ExecutorResources *apiv1.ResourceRequirements `json:"executorResources,omitempty"`
 
+	// MainContainer holds container customization for the main container
+	MainContainer *apiv1.Container `json:"mainContainer,omitempty"`
+
 	// KubeConfig specifies a kube config file for the wait & init containers
 	KubeConfig *KubeConfig `json:"kubeConfig,omitempty"`
 
diff --git a/workflow/controller/workflowpod.go b/workflow/controller/workflowpod.go
index 0da5cf7a5..cc944fcaa 100644
--- a/workflow/controller/workflowpod.go
+++ b/workflow/controller/workflowpod.go
@@ -151,6 +151,12 @@ func (woc *wfOperationCtx) createWorkflowPod(nodeName string, mainCtr apiv1.Cont
 	wfSpec := woc.execWf.Spec.DeepCopy()
 
 	mainCtr.Name = common.MainContainerName
+	// Allow customization of main container resources.
+	if isResourcesSpecified(woc.controller.Config.MainContainer) &&
+		// Container resources in workflow spec takes precedence over the main container's configuration in controller.
+		!(isResourcesSpecified(tmpl.Container) && tmpl.Container.Name == "main") {
+		mainCtr.Resources = woc.controller.Config.MainContainer.Resources
+	}
 
 	var activeDeadlineSeconds *int64
 	wfDeadline := woc.getWorkflowDeadline()


Test patch:
diff --git a/workflow/controller/workflowpod_test.go b/workflow/controller/workflowpod_test.go
index 5bb633ebd..14da76f86 100644
--- a/workflow/controller/workflowpod_test.go
+++ b/workflow/controller/workflowpod_test.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 	apiv1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/yaml"
@@ -1146,6 +1147,33 @@ func TestPodSpecPatch(t *testing.T) {
 
 }
 
+func TestMainContainerCustomization(t *testing.T) {
+	mainCtrSpec := &apiv1.Container{
+		Name: "main",
+		Resources: apiv1.ResourceRequirements{
+			Limits: apiv1.ResourceList{
+				apiv1.ResourceCPU:    resource.MustParse("0.200"),
+				apiv1.ResourceMemory: resource.MustParse("512Mi"),
+			},
+		},
+	}
+	// podSpecPatch in workflow spec takes precedence over the main container's
+	// configuration in controller so here we respect what's specified in podSpecPatch.
+	wf := unmarshalWF(helloWorldWfWithPatch)
+	woc := newWoc(*wf)
+	woc.controller.Config.MainContainer = mainCtrSpec
+	mainCtr := woc.execWf.Spec.Templates[0].Container
+	pod, _ := woc.createWorkflowPod(wf.Name, *mainCtr, &wf.Spec.Templates[0], &createWorkflowPodOpts{})
+	assert.Equal(t, "0.800", pod.Spec.Containers[1].Resources.Limits.Cpu().AsDec().String())
+
+	wf = unmarshalWF(helloWorldWf)
+	woc = newWoc(*wf)
+	woc.controller.Config.MainContainer = mainCtrSpec
+	mainCtr = woc.execWf.Spec.Templates[0].Container
+	pod, _ = woc.createWorkflowPod(wf.Name, *mainCtr, &wf.Spec.Templates[0], &createWorkflowPodOpts{})
+	assert.Equal(t, "0.200", pod.Spec.Containers[1].Resources.Limits.Cpu().AsDec().String())
+}
+
 var helloWindowsWf = `
 apiVersion: argoproj.io/v1alpha1
 kind: Workflow