Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kic: Add "no-limit" option to cpus & memory flags #17491

Merged
merged 2 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,11 @@ func validateRequestedMemorySize(req int, drvName string) {
exitIfNotForced(reason.RsrcInsufficientSysMemory, "System only has {{.size}}MiB available, less than the required {{.req}}MiB for Kubernetes", out.V{"size": sysLimit, "req": minUsableMem})
}

// if --memory=no-limit, ignore remaining checks
if req == 0 && driver.IsKIC(drvName) {
return
}

if req < minUsableMem {
exitIfNotForced(reason.RsrcInsufficientReqMemory, "Requested memory allocation {{.requested}}MiB is less than the usable minimum of {{.minimum_memory}}MB", out.V{"requested": req, "minimum_memory": minUsableMem})
}
Expand Down Expand Up @@ -1208,6 +1213,21 @@ func validateCPUCount(drvName string) {
availableCPUs = ci
}

if availableCPUs < 2 {
if drvName == oci.Docker && runtime.GOOS == "darwin" {
exitIfNotForced(reason.RsrcInsufficientDarwinDockerCores, "Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available")
} else if drvName == oci.Docker && runtime.GOOS == "windows" {
exitIfNotForced(reason.RsrcInsufficientWindowsDockerCores, "Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available")
} else {
exitIfNotForced(reason.RsrcInsufficientCores, "{{.driver_name}} has less than 2 CPUs available, but Kubernetes requires at least 2 to be available", out.V{"driver_name": driver.FullName(viper.GetString("driver"))})
}
}

// if --cpus=no-limit, ignore remaining checks
if cpuCount == 0 && driver.IsKIC(drvName) {
return
}

if cpuCount < minimumCPUS {
exitIfNotForced(reason.RsrcInsufficientCores, "Requested cpu count {{.requested_cpus}} is less than the minimum allowed of {{.minimum_cpus}}", out.V{"requested_cpus": cpuCount, "minimum_cpus": minimumCPUS})
}
Expand All @@ -1226,19 +1246,6 @@ func validateCPUCount(drvName string) {

exitIfNotForced(reason.RsrcInsufficientCores, "Requested cpu count {{.requested_cpus}} is greater than the available cpus of {{.avail_cpus}}", out.V{"requested_cpus": cpuCount, "avail_cpus": availableCPUs})
}

// looks good
if availableCPUs >= 2 {
return
}

if drvName == oci.Docker && runtime.GOOS == "darwin" {
exitIfNotForced(reason.RsrcInsufficientDarwinDockerCores, "Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available")
} else if drvName == oci.Docker && runtime.GOOS == "windows" {
exitIfNotForced(reason.RsrcInsufficientWindowsDockerCores, "Docker Desktop has less than 2 CPUs configured, but Kubernetes requires at least 2 to be available")
} else {
exitIfNotForced(reason.RsrcInsufficientCores, "{{.driver_name}} has less than 2 CPUs available, but Kubernetes requires at least 2 to be available", out.V{"driver_name": driver.FullName(viper.GetString("driver"))})
}
}

// validateFlags validates the supplied flags against known bad combinations
Expand Down Expand Up @@ -1505,13 +1512,18 @@ func validateChangedMemoryFlags(drvName string) {
var req int
var err error
memString := viper.GetString(memory)
if memString == constants.MaxResources {
if memString == constants.NoLimit && driver.IsKIC(drvName) {
req = 0
} else if memString == constants.MaxResources {
sysLimit, containerLimit, err := memoryLimits(drvName)
if err != nil {
klog.Warningf("Unable to query memory limits: %+v", err)
}
req = noLimitMemory(sysLimit, containerLimit, drvName)
} else {
if memString == constants.NoLimit {
exit.Message(reason.Usage, "The '{{.name}}' driver does not support --memory=no-limit", out.V{"name": drvName})
}
req, err = util.CalculateSizeInMB(memString)
if err != nil {
exitIfNotForced(reason.Usage, "Unable to parse memory '{{.memory}}': {{.error}}", out.V{"memory": memString, "error": err})
Expand Down
14 changes: 11 additions & 3 deletions cmd/minikube/cmd/start_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ func initMinikubeFlags() {
startCmd.Flags().Bool(interactive, true, "Allow user prompts for more information")
startCmd.Flags().Bool(dryRun, false, "dry-run mode. Validates configuration, but does not mutate system state")

startCmd.Flags().String(cpus, "2", fmt.Sprintf("Number of CPUs allocated to Kubernetes. Use %q to use the maximum number of CPUs.", constants.MaxResources))
startCmd.Flags().String(memory, "", fmt.Sprintf("Amount of RAM to allocate to Kubernetes (format: <number>[<unit>], where unit = b, k, m or g). Use %q to use the maximum amount of memory.", constants.MaxResources))
startCmd.Flags().String(cpus, "2", fmt.Sprintf("Number of CPUs allocated to Kubernetes. Use %q to use the maximum number of CPUs. Use %q to not specify a limit (Docker/Podman only)", constants.MaxResources, constants.NoLimit))
startCmd.Flags().String(memory, "", fmt.Sprintf("Amount of RAM to allocate to Kubernetes (format: <number>[<unit>], where unit = b, k, m or g). Use %q to use the maximum amount of memory. Use %q to not specify a limit (Docker/Podman only)", constants.MaxResources, constants.NoLimit))
startCmd.Flags().String(humanReadableDiskSize, defaultDiskSize, "Disk size allocated to the minikube VM (format: <number>[<unit>], where unit = b, k, m or g).")
startCmd.Flags().Bool(downloadOnly, false, "If true, only download and cache files for later use - don't install or start anything.")
startCmd.Flags().Bool(cacheImages, true, "If true, cache docker images for the current bootstrapper and load them into the machine. Always false with --driver=none.")
Expand Down Expand Up @@ -337,6 +337,12 @@ func generateClusterConfig(cmd *cobra.Command, existing *config.ClusterConfig, k
}

func getCPUCount(drvName string) int {
if viper.GetString(cpus) == constants.NoLimit {
if driver.IsKIC(drvName) {
return 0
}
exit.Message(reason.Usage, "The '{{.name}}' driver does not support --cpus=no-limit", out.V{"name": drvName})
}
if viper.GetString(cpus) != constants.MaxResources {
return viper.GetInt(cpus)
}
Expand Down Expand Up @@ -370,7 +376,9 @@ func getMemorySize(cmd *cobra.Command, drvName string) int {
if cmd.Flags().Changed(memory) || viper.IsSet(memory) {
memString := viper.GetString(memory)
var err error
if memString == constants.MaxResources {
if memString == constants.NoLimit && driver.IsKIC(drvName) {
mem = 0
} else if memString == constants.MaxResources {
mem = noLimitMemory(sysLimit, containerLimit, drvName)
} else {
mem, err = pkgutil.CalculateSizeInMB(memString)
Expand Down
5 changes: 4 additions & 1 deletion pkg/drivers/kic/kic.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,16 @@ func (d *Driver) Create() error {
ClusterLabel: oci.ProfileLabelKey + "=" + d.MachineName,
NodeLabel: oci.NodeLabelKey + "=" + d.NodeConfig.MachineName,
CPUs: strconv.Itoa(d.NodeConfig.CPU),
Memory: strconv.Itoa(d.NodeConfig.Memory) + "mb",
Memory: strconv.Itoa(d.NodeConfig.Memory),
Envs: d.NodeConfig.Envs,
ExtraArgs: append([]string{"--expose", fmt.Sprintf("%d", d.NodeConfig.APIServerPort)}, d.NodeConfig.ExtraArgs...),
OCIBinary: d.NodeConfig.OCIBinary,
APIServerPort: d.NodeConfig.APIServerPort,
GPUs: d.NodeConfig.GPUs,
}
if params.Memory != "0" {
params.Memory += "mb"
}

networkName := d.NodeConfig.Network
if networkName == "" {
Expand Down
12 changes: 6 additions & 6 deletions pkg/drivers/kic/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func checkRunning(p CreateParams) func() error {
}

// CreateContainerNode creates a new container node
func CreateContainerNode(p CreateParams) error {
func CreateContainerNode(p CreateParams) error { //nolint to suppress cyclomatic complexity
// on windows os, if docker desktop is using Windows Containers. Exit early with error
if p.OCIBinary == Docker && runtime.GOOS == "windows" {
info, err := DaemonInfo(p.OCIBinary)
Expand Down Expand Up @@ -203,11 +203,11 @@ func CreateContainerNode(p CreateParams) error {
// podman mounts var/lib with no-exec by default https://github.com/containers/libpod/issues/5103
runArgs = append(runArgs, "--volume", fmt.Sprintf("%s:/var:exec", p.Name))

if memcgSwap {
if memcgSwap && p.Memory != NoLimit {
runArgs = append(runArgs, fmt.Sprintf("--memory-swap=%s", p.Memory))
}

if memcg {
if memcg && p.Memory != NoLimit {
runArgs = append(runArgs, fmt.Sprintf("--memory=%s", p.Memory))
}

Expand All @@ -218,10 +218,10 @@ func CreateContainerNode(p CreateParams) error {
// ignore apparmore github actions docker: https://github.com/kubernetes/minikube/issues/7624
runArgs = append(runArgs, "--security-opt", "apparmor=unconfined")

if memcg {
if memcg && p.Memory != NoLimit {
runArgs = append(runArgs, fmt.Sprintf("--memory=%s", p.Memory))
}
if memcgSwap {
if memcgSwap && p.Memory != NoLimit {
// Disable swap by setting the value to match
runArgs = append(runArgs, fmt.Sprintf("--memory-swap=%s", p.Memory))
}
Expand All @@ -244,7 +244,7 @@ func CreateContainerNode(p CreateParams) error {
}
}

if cpuCfsPeriod && cpuCfsQuota {
if cpuCfsPeriod && cpuCfsQuota && p.CPUs != NoLimit {
runArgs = append(runArgs, fmt.Sprintf("--cpus=%s", p.CPUs))
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/drivers/kic/oci/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const (
nodeRoleLabelKey = "role.minikube.sigs.k8s.io"
// CreatedByLabelKey is applied to any container/volume that is created by minikube created_by.minikube.sigs.k8s.io=true
CreatedByLabelKey = "created_by.minikube.sigs.k8s.io"
// NoLimit is the value that specifies that no resource limit should be set
NoLimit = "0"
)

// CreateParams are parameters needed to create a container
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ const (
TimeFormat = time.RFC822
// MaxResources is the value that can be passed into the memory and cpus flags to specify to use maximum resources
MaxResources = "max"
// NoLimit is the value that can be passed into the memory and cpus flags to specify to not set the resource limit on the container (Docker & Podman only)
NoLimit = "no-limit"

// DefaultCertExpiration is the amount of time in the future a certificate will expire in by default, which is 3 years
DefaultCertExpiration = time.Hour * 24 * 365 * 3
Expand Down
2 changes: 1 addition & 1 deletion pkg/minikube/machine/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ func showHostInfo(h *host.Host, cfg config.ClusterConfig) {
}
if driver.IsKIC(cfg.Driver) { // TODO:medyagh add free disk space on docker machine
register.Reg.SetStep(register.CreatingContainer)
out.Step(style.StartingVM, "Creating {{.driver_name}} {{.machine_type}} (CPUs={{.number_of_cpus}}, Memory={{.memory_size}}MB) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "memory_size": cfg.Memory, "machine_type": machineType})
out.Step(style.StartingVM, "Creating {{.driver_name}} {{.machine_type}} (CPUs={{if not .number_of_cpus}}no-limit{{else}}{{.number_of_cpus}}{{end}}, Memory={{if not .memory_size}}no-limit{{else}}{{.memory_size}}MB{{end}}) ...", out.V{"driver_name": cfg.Driver, "number_of_cpus": cfg.CPUs, "memory_size": cfg.Memory, "machine_type": machineType})
return
}
register.Reg.SetStep(register.CreatingVM)
Expand Down
Loading