From d2b3a4c17c8b3f848e745a429a0505524658aca1 Mon Sep 17 00:00:00 2001 From: dongjiang Date: Fri, 25 Jul 2025 14:21:00 +0800 Subject: [PATCH] add automemlimit option Signed-off-by: dongjiang --- go/controller/cmd/main.go | 5 +++++ go/go.mod | 2 ++ go/go.sum | 4 ++++ go/internal/goruntime/memory.go | 36 +++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 go/internal/goruntime/memory.go diff --git a/go/controller/cmd/main.go b/go/controller/cmd/main.go index 3724a3ffb..b908af398 100644 --- a/go/controller/cmd/main.go +++ b/go/controller/cmd/main.go @@ -65,6 +65,8 @@ import ( // +kubebuilder:scaffold:imports ) +const defaultMemlimitRatio = 0.0 + var ( scheme = runtime.NewScheme() setupLog = ctrl.Log.WithName("setup") @@ -102,6 +104,7 @@ func main() { var databasePath string var databaseType string var databaseURL string + var memlimitRatio float64 flag.StringVar(&metricsAddr, "metrics-bind-address", "0", "The address the metrics endpoint binds to. "+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.") @@ -129,6 +132,7 @@ func main() { flag.StringVar(&databasePath, "sqlite-database-path", "./kagent.db", "The path to the SQLite database file.") flag.StringVar(&databaseURL, "postgres-database-url", "postgres://postgres:kagent@db.kagent.svc.cluster.local:5432/crud", "The URL of the PostgreSQL database.") + flag.Float64Var(&memlimitRatio, "auto-gomemlimit-ratio", defaultMemlimitRatio, "The ratio of reserved GOMEMLIMIT memory to the detected maximum container or system memory. The value should be greater than 0.0 and less than 1.0. Default: 0.0 (disabled).") flag.StringVar(&watchNamespaces, "watch-namespaces", "", "The namespaces to watch for .") opts := zap.Options{ @@ -142,6 +146,7 @@ func main() { ctrl.SetLogger(logger) goruntime.SetMaxProcs(logger) + goruntime.SetMemLimit(logger, memlimitRatio) setupLog.Info("Starting KAgent Controller", "version", Version, "git_commit", GitCommit, "build_date", BuildDate) diff --git a/go/go.mod b/go/go.mod index 2dcedbf52..72e645b07 100644 --- a/go/go.mod +++ b/go/go.mod @@ -3,6 +3,7 @@ module github.com/kagent-dev/kagent/go go 1.24.4 require ( + github.com/KimMachineGun/automemlimit v0.7.4 github.com/abiosoft/ishell/v2 v2.0.2 github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db github.com/briandowns/spinner v1.23.2 @@ -90,6 +91,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/onsi/ginkgo/v2 v2.23.4 // indirect github.com/onsi/gomega v1.37.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect diff --git a/go/go.sum b/go/go.sum index e4811c2be..6b2d11f1f 100644 --- a/go/go.sum +++ b/go/go.sum @@ -1,5 +1,7 @@ cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk= +github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= github.com/abiosoft/ishell v2.0.0+incompatible/go.mod h1:HQR9AqF2R3P4XXpMpI0NAzgHf/aS6+zVXRj14cVk9qg= github.com/abiosoft/ishell/v2 v2.0.2 h1:5qVfGiQISaYM8TkbBl7RFO6MddABoXpATrsFbVI+SNo= @@ -171,6 +173,8 @@ github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/go/internal/goruntime/memory.go b/go/internal/goruntime/memory.go new file mode 100644 index 000000000..d75ecee7c --- /dev/null +++ b/go/internal/goruntime/memory.go @@ -0,0 +1,36 @@ +package goruntime + +import ( + "fmt" + "runtime/debug" + + "github.com/KimMachineGun/automemlimit/memlimit" + "github.com/go-logr/logr" +) + +func SetMemLimit(logger logr.Logger, memlimitRatio float64) { + if memlimitRatio >= 1.0 { + memlimitRatio = 1.0 + } else if memlimitRatio <= 0.0 { + memlimitRatio = 0.0 + } + + // the memlimitRatio argument to 0, effectively disabling auto memory limit for all users. + if memlimitRatio == 0.0 { + return + } + + if _, err := memlimit.SetGoMemLimitWithOpts( + memlimit.WithRatio(memlimitRatio), + memlimit.WithProvider( + memlimit.ApplyFallback( + memlimit.FromCgroup, + memlimit.FromSystem, + ), + ), + ); err != nil { + logger.Error(err, "Failed to set GOMEMLIMIT automatically", "component", "automemlimit") + } + + logger.Info(fmt.Sprintf("GOMEMLIMIT set to %d", debug.SetMemoryLimit(-1))) +}