From e533da10f31960b78b9e7bf28abb15b1ba713644 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Tue, 9 Jan 2024 09:32:55 -0800 Subject: [PATCH] Add support to ignore resource requests/limits for local dev purposes (#2400) --- .../01-command-line/acorn_install.md | 1 + integration/helper/config.go | 28 +++++++++++++ integration/run/run_test.go | 41 +++++++++++++++++++ pkg/apis/api.acorn.io/v1/types.go | 21 +++++----- .../api.acorn.io/v1/zz_generated.deepcopy.go | 5 +++ pkg/config/config.go | 6 +++ pkg/controller/scheduling/scheduling.go | 4 ++ pkg/openapi/generated/openapi_generated.go | 8 +++- pkg/profiles/default.go | 1 + pkg/profiles/production.go | 1 + 10 files changed, 105 insertions(+), 11 deletions(-) diff --git a/docs/docs/100-reference/01-command-line/acorn_install.md b/docs/docs/100-reference/01-command-line/acorn_install.md index be398071e..b7f9465fa 100644 --- a/docs/docs/100-reference/01-command-line/acorn_install.md +++ b/docs/docs/100-reference/01-command-line/acorn_install.md @@ -47,6 +47,7 @@ acorn install --features strings Enable or disable features. (example foo=true,bar=false) -h, --help help for install --http-endpoint-pattern string Go template for formatting application http endpoints. Valid variables to use are: App, Container, Namespace, Hash and ClusterDomain. (default pattern is {{hashConcat 8 .Container .App .Namespace | truncate}}.{{.ClusterDomain}}) + --ignore-resource-requirements Ignore memory and CPU requests and limits, intended for local development (default is false) --ignore-user-labels-and-annotations Don't propagate user-defined labels and annotations to dependent objects --image string Override the default image used for the deployment --ingress-class-name string The ingress class name to assign to all created ingress resources (default '') diff --git a/integration/helper/config.go b/integration/helper/config.go index 4898bc1d7..46f1398a3 100644 --- a/integration/helper/config.go +++ b/integration/helper/config.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/acorn-io/runtime/pkg/config" + "github.com/acorn-io/z" kclient "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -41,3 +42,30 @@ func EnableFeatureWithRestore(t *testing.T, ctx context.Context, kclient kclient t.Fatal(err) } } + +func SetIgnoreResourceRequirementsWithRestore(t *testing.T, ctx context.Context, kclient kclient.WithWatch) { + t.Helper() + + cfg, err := config.Get(ctx, kclient) + if err != nil { + t.Fatal(err) + } + + state := z.Dereference(cfg.IgnoreResourceRequirements) + + cfg.IgnoreResourceRequirements = z.Pointer(true) + + t.Cleanup(func() { + cfg.IgnoreResourceRequirements = z.Pointer(state) + + err = config.Set(ctx, kclient, cfg) + if err != nil { + t.Fatal(err) + } + }) + + err = config.Set(ctx, kclient, cfg) + if err != nil { + t.Fatal(err) + } +} diff --git a/integration/run/run_test.go b/integration/run/run_test.go index 4c72b2f18..bc58f6bcb 100644 --- a/integration/run/run_test.go +++ b/integration/run/run_test.go @@ -1788,3 +1788,44 @@ func TestAutoUpgradeLocalImage(t *testing.T) { t.Fatal(err) } } + +func TestIgnoreResourceRequirements(t *testing.T) { + ctx := helper.GetCTX(t) + + helper.StartController(t) + restConfig, err := restconfig.New(scheme.Scheme) + if err != nil { + t.Fatal("error while getting rest config:", err) + } + kclient := helper.MustReturn(kclient.Default) + project := helper.TempProject(t, kclient) + + helper.SetIgnoreResourceRequirementsWithRestore(t, ctx, kclient) + + c, err := client.New(restConfig, project.Name, project.Name) + if err != nil { + t.Fatal(err) + } + + image, err := c.AcornImageBuild(ctx, "./testdata/simple/Acornfile", &client.AcornImageBuildOptions{ + Cwd: "./testdata/simple", + }) + if err != nil { + t.Fatal(err) + } + + // deploy an app with memory request configured, verify that it doesn't have the constraints + app, err := c.AppRun(ctx, image.ID, &client.AppRunOptions{ + Memory: map[string]*int64{ + "": z.Pointer(int64(1073741824)), + }, + }) + if err != nil { + t.Fatal(err) + } + + app = helper.WaitForObject(t, helper.Watcher(t, c), &apiv1.AppList{}, app, func(obj *apiv1.App) bool { + return obj.Status.Condition(v1.AppInstanceConditionParsed).Success + }) + assert.Empty(t, app.Status.Scheduling["simple"].Requirements) +} diff --git a/pkg/apis/api.acorn.io/v1/types.go b/pkg/apis/api.acorn.io/v1/types.go index 5dfa25c81..a5553e3c4 100644 --- a/pkg/apis/api.acorn.io/v1/types.go +++ b/pkg/apis/api.acorn.io/v1/types.go @@ -560,16 +560,17 @@ type Config struct { AutoConfigureKarpenterDontEvictAnnotations *bool `json:"autoConfigureKarpenterDontEvictAnnotations" name:"auto-configure-karpenter-dont-evict-annotations" usage:"Automatically configure Karpenter to not evict pods with the given annotations if app is running a single replica. (default false)"` // Flags for setting resource request and limits on sytem components - ControllerMemory *string `json:"controllerMemory" name:"controller-memory" usage:"The memory to allocate to the runtime-controller in the format of : (example 256Mi:1Gi)"` - ControllerCPU *string `json:"controllerCPU" name:"controller-cpu" usage:"The CPU to allocate to the runtime-controller in the format of : (example 200m:1000m)"` - APIServerMemory *string `json:"apiServerMemory" name:"api-server-memory" usage:"The memory to allocate to the runtime-api-server in the format of : (example 256Mi:1Gi)"` - APIServerCPU *string `json:"apiServerCPU" name:"api-server-cpu" usage:"The CPU to allocate to the runtime-api-server in the format of : (example 200m:1000m)"` - BuildkitdMemory *string `json:"buildkitdMemory" name:"buildkitd-memory" usage:"The memory to allocate to buildkitd in the format of : (example 256Mi:1Gi)"` - BuildkitdCPU *string `json:"buildkitdCPU" name:"buildkitd-cpu" usage:"The CPU to allocate to buildkitd in the format of : (example 200m:1000m)"` - BuildkitdServiceMemory *string `json:"buildkitdServiceMemory" name:"buildkitd-service-memory" usage:"The memory to allocate to the buildkitd service in the format of : (example 256Mi:1Gi)"` - BuildkitdServiceCPU *string `json:"buildkitdServiceCPU" name:"buildkitd-service-cpu" usage:"The CPU to allocate to the buildkitd service in the format of : (example 200m:1000m)"` - RegistryMemory *string `json:"registryMemory" name:"registry-memory" usage:"The memory to allocate to the registry in the format of : (example 256Mi:1Gi)"` - RegistryCPU *string `json:"registryCPU" name:"registry-cpu" usage:"The CPU to allocate to the registry in the format of : (example 200m:1000m)"` + ControllerMemory *string `json:"controllerMemory" name:"controller-memory" usage:"The memory to allocate to the runtime-controller in the format of : (example 256Mi:1Gi)"` + ControllerCPU *string `json:"controllerCPU" name:"controller-cpu" usage:"The CPU to allocate to the runtime-controller in the format of : (example 200m:1000m)"` + APIServerMemory *string `json:"apiServerMemory" name:"api-server-memory" usage:"The memory to allocate to the runtime-api-server in the format of : (example 256Mi:1Gi)"` + APIServerCPU *string `json:"apiServerCPU" name:"api-server-cpu" usage:"The CPU to allocate to the runtime-api-server in the format of : (example 200m:1000m)"` + BuildkitdMemory *string `json:"buildkitdMemory" name:"buildkitd-memory" usage:"The memory to allocate to buildkitd in the format of : (example 256Mi:1Gi)"` + BuildkitdCPU *string `json:"buildkitdCPU" name:"buildkitd-cpu" usage:"The CPU to allocate to buildkitd in the format of : (example 200m:1000m)"` + BuildkitdServiceMemory *string `json:"buildkitdServiceMemory" name:"buildkitd-service-memory" usage:"The memory to allocate to the buildkitd service in the format of : (example 256Mi:1Gi)"` + BuildkitdServiceCPU *string `json:"buildkitdServiceCPU" name:"buildkitd-service-cpu" usage:"The CPU to allocate to the buildkitd service in the format of : (example 200m:1000m)"` + RegistryMemory *string `json:"registryMemory" name:"registry-memory" usage:"The memory to allocate to the registry in the format of : (example 256Mi:1Gi)"` + RegistryCPU *string `json:"registryCPU" name:"registry-cpu" usage:"The CPU to allocate to the registry in the format of : (example 200m:1000m)"` + IgnoreResourceRequirements *bool `json:"ignoreResourceRequirements" name:"ignore-resource-requirements" usage:"Ignore memory and CPU requests and limits, intended for local development (default is false)"` } type EncryptionKey struct { diff --git a/pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go b/pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go index eaffbcaf7..ed9a7dffe 100644 --- a/pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go +++ b/pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go @@ -649,6 +649,11 @@ func (in *Config) DeepCopyInto(out *Config) { *out = new(string) **out = **in } + if in.IgnoreResourceRequirements != nil { + in, out := &in.IgnoreResourceRequirements, &out.IgnoreResourceRequirements + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. diff --git a/pkg/config/config.go b/pkg/config/config.go index 7b454ca64..c09153cab 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -143,6 +143,9 @@ func complete(ctx context.Context, c *apiv1.Config, getter kclient.Reader, inclu if c.APIServerCPU == nil { c.APIServerCPU = profile.APIServerCPU } + if c.IgnoreResourceRequirements == nil { + c.IgnoreResourceRequirements = profile.IgnoreResourceRequirements + } if c.Features == nil { c.Features = profile.Features } else { @@ -456,6 +459,9 @@ func merge(oldConfig, newConfig *apiv1.Config) *apiv1.Config { if newConfig.APIServerCPU != nil { mergedConfig.APIServerCPU = newConfig.APIServerCPU } + if newConfig.IgnoreResourceRequirements != nil { + mergedConfig.IgnoreResourceRequirements = newConfig.IgnoreResourceRequirements + } if newConfig.AutoConfigureKarpenterDontEvictAnnotations != nil { mergedConfig.AutoConfigureKarpenterDontEvictAnnotations = newConfig.AutoConfigureKarpenterDontEvictAnnotations } diff --git a/pkg/controller/scheduling/scheduling.go b/pkg/controller/scheduling/scheduling.go index ad5fa50e8..d17f60924 100644 --- a/pkg/controller/scheduling/scheduling.go +++ b/pkg/controller/scheduling/scheduling.go @@ -159,6 +159,10 @@ func ResourceRequirements(req router.Request, app *v1.AppInstance, containerName } requirements := &corev1.ResourceRequirements{Limits: corev1.ResourceList{}, Requests: corev1.ResourceList{}} + if z.Dereference(cfg.IgnoreResourceRequirements) { + return requirements, nil + } + if computeClass != nil && computeClass.Resources != nil { if computeClass.Resources.Requests != nil { requirements.Requests = computeClass.Resources.Requests diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index 30e1805ba..8a3429632 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -2630,8 +2630,14 @@ func schema_pkg_apis_apiacornio_v1_Config(ref common.ReferenceCallback) common.O Format: "", }, }, + "ignoreResourceRequirements": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, }, - Required: []string{"ingressClassName", "clusterDomains", "letsEncrypt", "letsEncryptEmail", "letsEncryptTOSAgree", "setPodSecurityEnforceProfile", "podSecurityEnforceProfile", "httpEndpointPattern", "internalClusterDomain", "acornDNS", "acornDNSEndpoint", "autoUpgradeInterval", "recordBuilds", "publishBuilders", "builderPerProject", "internalRegistryPrefix", "ignoreUserLabelsAndAnnotations", "allowUserLabels", "allowUserAnnotations", "allowUserMetadataNamespaces", "workloadMemoryDefault", "workloadMemoryMaximum", "useCustomCABundle", "propagateProjectAnnotations", "propagateProjectLabels", "manageVolumeClasses", "volumeSizeDefault", "networkPolicies", "ingressControllerNamespace", "allowTrafficFromNamespace", "serviceLBAnnotations", "awsIdentityProviderArn", "eventTTL", "features", "certManagerIssuer", "profile", "autoConfigureKarpenterDontEvictAnnotations", "controllerMemory", "controllerCPU", "apiServerMemory", "apiServerCPU", "buildkitdMemory", "buildkitdCPU", "buildkitdServiceMemory", "buildkitdServiceCPU", "registryMemory", "registryCPU"}, + Required: []string{"ingressClassName", "clusterDomains", "letsEncrypt", "letsEncryptEmail", "letsEncryptTOSAgree", "setPodSecurityEnforceProfile", "podSecurityEnforceProfile", "httpEndpointPattern", "internalClusterDomain", "acornDNS", "acornDNSEndpoint", "autoUpgradeInterval", "recordBuilds", "publishBuilders", "builderPerProject", "internalRegistryPrefix", "ignoreUserLabelsAndAnnotations", "allowUserLabels", "allowUserAnnotations", "allowUserMetadataNamespaces", "workloadMemoryDefault", "workloadMemoryMaximum", "useCustomCABundle", "propagateProjectAnnotations", "propagateProjectLabels", "manageVolumeClasses", "volumeSizeDefault", "networkPolicies", "ingressControllerNamespace", "allowTrafficFromNamespace", "serviceLBAnnotations", "awsIdentityProviderArn", "eventTTL", "features", "certManagerIssuer", "profile", "autoConfigureKarpenterDontEvictAnnotations", "controllerMemory", "controllerCPU", "apiServerMemory", "apiServerCPU", "buildkitdMemory", "buildkitdCPU", "buildkitdServiceMemory", "buildkitdServiceCPU", "registryMemory", "registryCPU", "ignoreResourceRequirements"}, }, }, } diff --git a/pkg/profiles/default.go b/pkg/profiles/default.go index 3ea66ae73..dd4d83296 100644 --- a/pkg/profiles/default.go +++ b/pkg/profiles/default.go @@ -73,6 +73,7 @@ func defaultProfile() apiv1.Config { ControllerCPU: new(string), APIServerMemory: new(string), APIServerCPU: new(string), + IgnoreResourceRequirements: z.Pointer(false), AutoConfigureKarpenterDontEvictAnnotations: z.Pointer(true), } } diff --git a/pkg/profiles/production.go b/pkg/profiles/production.go index 78fdec1ab..01cd49964 100644 --- a/pkg/profiles/production.go +++ b/pkg/profiles/production.go @@ -33,6 +33,7 @@ func productionProfile() apiv1.Config { conf.ControllerCPU = z.Pointer("100m") conf.APIServerMemory = z.Pointer("256Mi") conf.APIServerCPU = z.Pointer("100m") + conf.IgnoreResourceRequirements = z.Pointer(false) conf.AutoConfigureKarpenterDontEvictAnnotations = z.Pointer(true) return conf