@@ -116,7 +116,7 @@ const (
116
116
minUsableMem = 1024 // Kubernetes will not start with less than 1GB
117
117
minRecommendedMem = 2000 // Warn at no lower than existing configurations
118
118
minimumCPUS = 2
119
- minimumDiskSize = "2000mb"
119
+ minimumDiskSize = 2000
120
120
autoUpdate = "auto-update-drivers"
121
121
hostOnlyNicType = "host-only-nic-type"
122
122
natNicType = "nat-nic-type"
@@ -337,14 +337,7 @@ func runStart(cmd *cobra.Command, args []string) {
337
337
ssh .SetDefaultClient (ssh .External )
338
338
}
339
339
340
- var existingAddons map [string ]bool
341
- if viper .GetBool (installAddons ) {
342
- existingAddons = map [string ]bool {}
343
- if existing != nil && existing .Addons != nil {
344
- existingAddons = existing .Addons
345
- }
346
- }
347
- kubeconfig , err := node .Start (mc , n , true , existingAddons )
340
+ kubeconfig , err := startNode (existing , mc , n )
348
341
if err != nil {
349
342
exit .WithError ("Starting node" , err )
350
343
}
@@ -389,6 +382,17 @@ func displayEnviron(env []string) {
389
382
}
390
383
}
391
384
385
+ func startNode (existing * config.ClusterConfig , mc config.ClusterConfig , n config.Node ) (* kubeconfig.Settings , error ) {
386
+ var existingAddons map [string ]bool
387
+ if viper .GetBool (installAddons ) {
388
+ existingAddons = map [string ]bool {}
389
+ if existing != nil && existing .Addons != nil {
390
+ existingAddons = existing .Addons
391
+ }
392
+ }
393
+ return node .Start (mc , n , true , existingAddons )
394
+ }
395
+
392
396
func showKubectlInfo (kcs * kubeconfig.Settings , k8sVersion string , machineName string ) error {
393
397
if kcs .KeepContext {
394
398
out .T (out .Kubectl , "To connect to this cluster, use: kubectl --context={{.name}}" , out.V {"name" : kcs .ClusterName })
@@ -427,8 +431,11 @@ func showKubectlInfo(kcs *kubeconfig.Settings, k8sVersion string, machineName st
427
431
glog .Infof ("kubectl: %s, cluster: %s (minor skew: %d)" , client , cluster , minorSkew )
428
432
429
433
if client .Major != cluster .Major || minorSkew > 1 {
430
- out .WarningT ("{{.path}} is version {{.client_version}}, and is incompatible with Kubernetes {{.cluster_version}}. You will need to update {{.path}} or use 'minikube kubectl' to connect with this cluster" ,
434
+ out .Ln ("" )
435
+ out .T (out .Warning , "{{.path}} is v{{.client_version}}, which may be incompatible with Kubernetes v{{.cluster_version}}." ,
431
436
out.V {"path" : path , "client_version" : client , "cluster_version" : cluster })
437
+ out .T (out .Tip , "You can also use 'minikube kubectl -- get pods' to invoke a matching version" ,
438
+ out.V {"path" : path , "client_version" : client })
432
439
}
433
440
return nil
434
441
}
@@ -638,43 +645,62 @@ func validateUser(drvName string) {
638
645
}
639
646
}
640
647
641
- // defaultMemorySize calculates the default memory footprint in MB
642
- func defaultMemorySize (drvName string ) int {
643
- fallback := 2200
644
- maximum := 6000
645
-
648
+ // memoryLimits returns the amount of memory allocated to the system and hypervisor
649
+ func memoryLimits (drvName string ) (int , int , error ) {
646
650
v , err := mem .VirtualMemory ()
647
651
if err != nil {
648
- return fallback
652
+ return - 1 , - 1 , err
649
653
}
650
- available := v .Total / 1024 / 1024
654
+ sysLimit := int (v .Total / 1024 / 1024 )
655
+ containerLimit := 0
651
656
652
- // For KIC, do not allocate more memory than the container has available (+ some slack)
653
657
if driver .IsKIC (drvName ) {
654
658
s , err := oci .DaemonInfo (drvName )
655
659
if err != nil {
656
- return fallback
660
+ return - 1 , - 1 , err
661
+ }
662
+ containerLimit = int (s .TotalMemory / 1024 / 1024 )
663
+ }
664
+ return sysLimit , containerLimit , nil
665
+ }
666
+
667
+ // suggestMemoryAllocation calculates the default memory footprint in MB
668
+ func suggestMemoryAllocation (sysLimit int , containerLimit int ) int {
669
+ fallback := 2200
670
+ maximum := 6000
671
+
672
+ if sysLimit > 0 && fallback > sysLimit {
673
+ return sysLimit
674
+ }
675
+
676
+ // If there are container limits, add tiny bit of slack for non-minikube components
677
+ if containerLimit > 0 {
678
+ if fallback > containerLimit {
679
+ return containerLimit
657
680
}
658
- maximum = int ( s . TotalMemory / 1024 / 1024 ) - 128
681
+ maximum = containerLimit - 48
659
682
}
660
683
661
- suggested := int (available / 4 )
684
+ // Suggest 25% of RAM, rounded to nearest 100MB. Hyper-V requires an even number!
685
+ suggested := int (float32 (sysLimit )/ 400.0 ) * 100
662
686
663
687
if suggested > maximum {
664
- suggested = maximum
688
+ return maximum
665
689
}
666
690
667
691
if suggested < fallback {
668
- suggested = fallback
692
+ return fallback
669
693
}
670
694
671
- glog .Infof ("Selecting memory default of %dMB, given %dMB available and %dMB maximum" , suggested , available , maximum )
672
695
return suggested
673
696
}
674
697
675
698
// validateMemorySize validates the memory size matches the minimum recommended
676
699
func validateMemorySize () {
677
- req := pkgutil .CalculateSizeInMB (viper .GetString (memory ))
700
+ req , err := pkgutil .CalculateSizeInMB (viper .GetString (memory ))
701
+ if err != nil {
702
+ exit .WithCodeT (exit .Config , "Unable to parse memory '{{.memory}}': {{.error}}" , out.V {"memory" : viper .GetString (memory ), "error" : err })
703
+ }
678
704
if req < minUsableMem && ! viper .GetBool (force ) {
679
705
exit .WithCodeT (exit .Config , "Requested memory allocation {{.requested}}MB is less than the usable minimum of {{.minimum}}MB" ,
680
706
out.V {"requested" : req , "mininum" : minUsableMem })
@@ -707,9 +733,13 @@ func validateCPUCount(local bool) {
707
733
// validateFlags validates the supplied flags against known bad combinations
708
734
func validateFlags (cmd * cobra.Command , drvName string ) {
709
735
if cmd .Flags ().Changed (humanReadableDiskSize ) {
710
- diskSizeMB := pkgutil .CalculateSizeInMB (viper .GetString (humanReadableDiskSize ))
711
- if diskSizeMB < pkgutil .CalculateSizeInMB (minimumDiskSize ) && ! viper .GetBool (force ) {
712
- exit .WithCodeT (exit .Config , "Requested disk size {{.requested_size}} is less than minimum of {{.minimum_size}}" , out.V {"requested_size" : diskSizeMB , "minimum_size" : pkgutil .CalculateSizeInMB (minimumDiskSize )})
736
+ diskSizeMB , err := pkgutil .CalculateSizeInMB (viper .GetString (humanReadableDiskSize ))
737
+ if err != nil {
738
+ exit .WithCodeT (exit .Config , "Validation unable to parse disk size '{{.diskSize}}': {{.error}}" , out.V {"diskSize" : viper .GetString (humanReadableDiskSize ), "error" : err })
739
+ }
740
+
741
+ if diskSizeMB < minimumDiskSize && ! viper .GetBool (force ) {
742
+ exit .WithCodeT (exit .Config , "Requested disk size {{.requested_size}} is less than minimum of {{.minimum_size}}" , out.V {"requested_size" : diskSizeMB , "minimum_size" : minimumDiskSize })
713
743
}
714
744
}
715
745
@@ -817,9 +847,20 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string)
817
847
kubeNodeName = "m01"
818
848
}
819
849
820
- mem := defaultMemorySize (drvName )
821
- if viper .GetString (memory ) != "" {
822
- mem = pkgutil .CalculateSizeInMB (viper .GetString (memory ))
850
+ sysLimit , containerLimit , err := memoryLimits (drvName )
851
+ if err != nil {
852
+ glog .Warningf ("Unable to query memory limits: %v" , err )
853
+ }
854
+
855
+ mem := suggestMemoryAllocation (sysLimit , containerLimit )
856
+ if cmd .Flags ().Changed (memory ) {
857
+ mem , err = pkgutil .CalculateSizeInMB (viper .GetString (memory ))
858
+ if err != nil {
859
+ exit .WithCodeT (exit .Config , "Generate unable to parse memory '{{.memory}}': {{.error}}" , out.V {"memory" : viper .GetString (memory ), "error" : err })
860
+ }
861
+
862
+ } else {
863
+ glog .Infof ("Using suggested %dMB memory alloc based on sys=%dMB, container=%dMB" , mem , sysLimit , containerLimit )
823
864
}
824
865
825
866
// Create the initial node, which will necessarily be a control plane
@@ -831,14 +872,19 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string)
831
872
Worker : true ,
832
873
}
833
874
875
+ diskSize , err := pkgutil .CalculateSizeInMB (viper .GetString (humanReadableDiskSize ))
876
+ if err != nil {
877
+ exit .WithCodeT (exit .Config , "Generate unable to parse disk size '{{.diskSize}}': {{.error}}" , out.V {"diskSize" : viper .GetString (humanReadableDiskSize ), "error" : err })
878
+ }
879
+
834
880
cfg := config.ClusterConfig {
835
881
Name : viper .GetString (config .ProfileName ),
836
882
KeepContext : viper .GetBool (keepContext ),
837
883
EmbedCerts : viper .GetBool (embedCerts ),
838
884
MinikubeISO : viper .GetString (isoURL ),
839
885
Memory : mem ,
840
886
CPUs : viper .GetInt (cpus ),
841
- DiskSize : pkgutil . CalculateSizeInMB ( viper . GetString ( humanReadableDiskSize )) ,
887
+ DiskSize : diskSize ,
842
888
Driver : drvName ,
843
889
HyperkitVpnKitSock : viper .GetString (vpnkitSock ),
844
890
HyperkitVSockPorts : viper .GetStringSlice (vsockPorts ),
0 commit comments