From 0d654d94e9e6509aec2548217b1795e8d8533de0 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Tue, 14 Mar 2023 13:39:04 +0100 Subject: [PATCH] Use persistent `RESTClientGetter` in CLI This changes the `RESTClientGetter` to one which caches the underlying clients after first initialization. This reduces memory usage for all commands, with observed reductions from ~4MiB for `helm get all`, to ~10MiB for `helm install` (using https://github.com/stefanprodan/podinfo). For charts which make use of Custom Resource Definitions, this is likely even higher as the client will not be initialized twice (one time for the installation process of the CRDs, the second time for the actual installation of the chart). Follow up on #11886 Signed-off-by: Hidde Beydals --- pkg/cli/environment.go | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/pkg/cli/environment.go b/pkg/cli/environment.go index dac2a4bc1..81166c8af 100644 --- a/pkg/cli/environment.go +++ b/pkg/cli/environment.go @@ -106,29 +106,38 @@ func New() *EnvSettings { env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) // bind to kubernetes config flags - env.config = &genericclioptions.ConfigFlags{ - Namespace: &env.namespace, - Context: &env.KubeContext, - BearerToken: &env.KubeToken, - APIServer: &env.KubeAPIServer, - CAFile: &env.KubeCaFile, - KubeConfig: &env.KubeConfig, - Impersonate: &env.KubeAsUser, - Insecure: &env.KubeInsecureSkipTLSVerify, - TLSServerName: &env.KubeTLSServerName, - ImpersonateGroup: &env.KubeAsGroups, - WrapConfigFn: func(config *rest.Config) *rest.Config { - config.Burst = env.BurstLimit - config.Wrap(func(rt http.RoundTripper) http.RoundTripper { - return &retryingRoundTripper{wrapped: rt} - }) - config.UserAgent = version.GetUserAgent() - return config - }, - } + env.config = buildConfigFlagsFromEnv(env) return env } +// buildConfigFlagsFromEnv builds a ConfigFlags object from the environment and +// returns it. It uses a persistent config, meaning that underlying clients will +// be cached and reused. +func buildConfigFlagsFromEnv(env *EnvSettings) *genericclioptions.ConfigFlags { + flags := genericclioptions.NewConfigFlags(true) + + flags.Namespace = &env.namespace + flags.Context = &env.KubeContext + flags.BearerToken = &env.KubeToken + flags.APIServer = &env.KubeAPIServer + flags.CAFile = &env.KubeCaFile + flags.KubeConfig = &env.KubeConfig + flags.Impersonate = &env.KubeAsUser + flags.Insecure = &env.KubeInsecureSkipTLSVerify + flags.TLSServerName = &env.KubeTLSServerName + flags.ImpersonateGroup = &env.KubeAsGroups + flags.WrapConfigFn = func(config *rest.Config) *rest.Config { + config.Burst = env.BurstLimit + config.Wrap(func(rt http.RoundTripper) http.RoundTripper { + return &retryingRoundTripper{wrapped: rt} + }) + config.UserAgent = version.GetUserAgent() + return config + } + + return flags +} + // AddFlags binds flags to the given flagset. func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request")