// runStart handles the executes the flow of "minikube start"
func runStart(cmd *cobra.Command, _ []string) {
// 设置环境变量
register.SetEventLogPath(localpath.EventLog(ClusterFlagValue()))
// 设置上下文
ctx := context.Background()
// 设置为 json 格式
out.SetJSON(outputFormat == "json")
// 设置追踪
if err := pkgtrace.Initialize(viper.GetString(trace)); err != nil {
exit.Message(reason.Usage, "error initializing tracing: {{.Error}}", out.V{"Error": err.Error()})
}
defer pkgtrace.Cleanup()
// 打印版本信息
displayVersion(version.GetVersion())
// 开启线程,清理旧版本的预加载文件
go download.CleanUpOlderPreloads()
// Avoid blocking execution on optional HTTP fetches
go notify.MaybePrintUpdateTextFromGithub()
// 打印环境变量
displayEnviron(os.Environ())
if viper.GetBool(force) {
out.WarningT("minikube skips various validations when --force is supplied; this may lead to unexpected behavior")
}
// if --registry-mirror specified when run minikube start,
// take arg precedence over MINIKUBE_REGISTRY_MIRROR
// actually this is a hack, because viper 1.0.0 can assign env to variable if StringSliceVar
// and i can't update it to 1.4.0, it affects too much code
// other types (like String, Bool) of flag works, so imageRepository, imageMirrorCountry
// can be configured as MINIKUBE_IMAGE_REPOSITORY and IMAGE_MIRROR_COUNTRY
// this should be updated to documentation
if len(registryMirror) == 0 {
registryMirror = viper.GetStringSlice("registry-mirror")
}
// 配置文件名称校验
if !config.ProfileNameValid(ClusterFlagValue()) {
out.WarningT("Profile name '{{.name}}' is not valid", out.V{"name": ClusterFlagValue()})
exit.Message(reason.Usage, "Only alphanumeric and dashes '-' are permitted. Minimum 2 characters, starting with alphanumeric.")
}
// 加载配置文件(第一次加载时,路径不存在会返回 nil )
existing, err := config.Load(ClusterFlagValue())
if err != nil && !config.IsNotExist(err) {
kind := reason.HostConfigLoad
if config.IsPermissionDenied(err) {
kind = reason.HostHomePermission
}
exit.Message(kind, "Unable to load config: {{.error}}", out.V{"error": err})
}
// 更新配置文件内容
if existing != nil {
upgradeExistingConfig(cmd, existing)
} else {
validateProfileName()
}
// 检验出入的驱动
validateSpecifiedDriver(existing)
// 版本校验
validateKubernetesVersion(existing)
// 检验运行时是否为{“docker”,"crio","cri-o","containerd"}的其中一种, 如果没有设置,直接跳过
validateContainerRuntime(existing)
ds, alts, specified := selectDriver(existing)
if cmd.Flag(kicBaseImage).Changed {
if !isBaseImageApplicable(ds.Name) {
exit.Message(reason.Usage,
"flag --{{.imgFlag}} is not available for driver '{{.driver}}'. Did you mean to use '{{.docker}}' or '{{.podman}}' driver instead?\n"+
"Please use --{{.isoFlag}} flag to configure VM based drivers",
out.V{
"imgFlag": kicBaseImage,
"driver": ds.Name,
"docker": registry.Docker,
"podman": registry.Podman,
"isoFlag": isoURL,
},
)
}
}
useForce := viper.GetBool(force)
starter, err := provisionWithDriver(cmd, ds, existing)
if err != nil {
node.ExitIfFatal(err, useForce)
machine.MaybeDisplayAdvice(err, ds.Name)
if specified {
// If the user specified a driver, don't fallback to anything else
exitGuestProvision(err)
} else {
success := false
// Walk down the rest of the options
for _, alt := range alts {
// Skip non-default drivers
if !alt.Default {
continue
}
out.WarningT("Startup with {{.old_driver}} driver failed, trying with alternate driver {{.new_driver}}: {{.error}}", out.V{"old_driver": ds.Name, "new_driver": alt.Name, "error": err})
ds = alt
// Delete the existing cluster and try again with the next driver on the list
profile, err := config.LoadProfile(ClusterFlagValue())
if err != nil {
klog.Warningf("%s profile does not exist, trying anyways.", ClusterFlagValue())
}
err = deleteProfile(ctx, profile)
if err != nil {
out.WarningT("Failed to delete cluster {{.name}}, proceeding with retry anyway.", out.V{"name": ClusterFlagValue()})
}
starter, err = provisionWithDriver(cmd, ds, existing)
if err != nil {
continue
}
// Success!
success = true
break
}
if !success {
exitGuestProvision(err)
}
}
}
validateBuiltImageVersion(starter.Runner, ds.Name)
if existing != nil && driver.IsKIC(existing.Driver) {
if viper.GetBool(createMount) {
old := ""
if len(existing.ContainerVolumeMounts) > 0 {
old = existing.ContainerVolumeMounts[0]
}
if mount := viper.GetString(mountString); old != mount {
exit.Message(reason.GuestMountConflict, "Sorry, {{.driver}} does not allow mounts to be changed after container creation (previous mount: '{{.old}}', new mount: '{{.new}})'", out.V{
"driver": existing.Driver,
"new": mount,
"old": old,
})
}
}
}
kubeconfig, err := startWithDriver(cmd, starter, existing)
if err != nil {
node.ExitIfFatal(err, useForce)
exit.Error(reason.GuestStart, "failed to start node", err)
}
if err := showKubectlInfo(kubeconfig, starter.Node.KubernetesVersion, starter.Node.ContainerRuntime, starter.Cfg.Name); err != nil {
klog.Errorf("kubectl info: %v", err)
}
}
// returns (current_driver, suggested_drivers, "true, if the driver is set by command line arg or in the config file")
// 选择驱动
func selectDriver(existing *config.ClusterConfig) (registry.DriverState, []registry.DriverState, bool) {
// Technically unrelated, but important to perform before detection
driver.SetLibvirtURI(viper.GetString(kvmQemuURI))
register.Reg.SetStep(register.SelectingDriver)
// By default, the driver is whatever we used last time
if existing != nil {
old := hostDriver(existing)
ds := driver.Status(old)
out.Step(style.Sparkle, `Using the {{.driver}} driver based on existing profile`, out.V{"driver": ds.String()})
return ds, nil, true
}
// Default to looking at the new driver parameter
if d := viper.GetString("driver"); d != "" {
if vmd := viper.GetString("vm-driver"); vmd != "" {
// Output a warning
warning := `Both driver={{.driver}} and vm-driver={{.vmd}} have been set.
Since vm-driver is deprecated, minikube will default to driver={{.driver}}.
If vm-driver is set in the global config, please run "minikube config unset vm-driver" to resolve this warning.
`
out.WarningT(warning, out.V{"driver": d, "vmd": vmd})
}
ds := driver.Status(d)
if ds.Name == "" {
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}", out.V{"driver": d, "os": runtime.GOOS, "arch": runtime.GOARCH})
}
out.Step(style.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds, nil, true
}
// Fallback to old driver parameter
if d := viper.GetString("vm-driver"); d != "" {
ds := driver.Status(viper.GetString("vm-driver"))
if ds.Name == "" {
exit.Message(reason.DrvUnsupportedOS, "The driver '{{.driver}}' is not supported on {{.os}}/{{.arch}}", out.V{"driver": d, "os": runtime.GOOS, "arch": runtime.GOARCH})
}
out.Step(style.Sparkle, `Using the {{.driver}} driver based on user configuration`, out.V{"driver": ds.String()})
return ds, nil, true
}
// 返回本机所有的驱动
choices := driver.Choices(viper.GetBool("vm"))
// 推荐出,可使用的驱动(根据是否安装、是否健康、是否是默认、优先级是否大于4 进行推荐),分别返回: 首选、可用列表、不可用列表
pick, alts, rejects := driver.Suggest(choices)
if pick.Name == "" {
out.Step(style.ThumbsDown, "Unable to pick a default driver. Here is what was considered, in preference order:")
sort.Slice(rejects, func(i, j int) bool {
if rejects[i].Priority == rejects[j].Priority {
return rejects[i].Preference > rejects[j].Preference
}
return rejects[i].Priority > rejects[j].Priority
})
// Display the issue for installed drivers
for _, r := range rejects {
if r.Default && r.State.Installed {
out.Infof("{{ .name }}: {{ .rejection }}", out.V{"name": r.Name, "rejection": r.Rejection})
if r.Suggestion != "" {
out.Infof("{{ .name }}: Suggestion: {{ .suggestion}}", out.V{"name": r.Name, "suggestion": r.Suggestion})
}
}
}
// Display the other drivers users can install
out.Step(style.Tip, "Alternatively you could install one of these drivers:")
for _, r := range rejects {
if !r.Default || r.State.Installed {
continue
}
out.Infof("{{ .name }}: {{ .rejection }}", out.V{"name": r.Name, "rejection": r.Rejection})
if r.Suggestion != "" {
out.Infof("{{ .name }}: Suggestion: {{ .suggestion}}", out.V{"name": r.Name, "suggestion": r.Suggestion})
}
}
foundStoppedDocker := false
foundUnhealthy := false
for _, reject := range rejects {
if reject.Name == driver.Docker && reject.State.Installed && !reject.State.Running {
foundStoppedDocker = true
break
} else if reject.State.Installed && !reject.State.Healthy {
foundUnhealthy = true
break
}
}
if foundStoppedDocker {
exit.Message(reason.DrvDockerNotRunning, "Found docker, but the docker service isn't running. Try restarting the docker service.")
} else if foundUnhealthy {
exit.Message(reason.DrvNotHealthy, "Found driver(s) but none were healthy. See above for suggestions how to fix installed drivers.")
} else {
exit.Message(reason.DrvNotDetected, "No possible driver was detected. Try specifying --driver, or see https://minikube.sigs.k8s.io/docs/start/")
}
}
if len(alts) > 1 {
altNames := []string{}
for _, a := range alts {
altNames = append(altNames, a.String())
}
out.Step(style.Sparkle, `Automatically selected the {{.driver}} driver. Other choices: {{.alternates}}`, out.V{"driver": pick.Name, "alternates": strings.Join(altNames, ", ")})
} else {
out.Step(style.Sparkle, `Automatically selected the {{.driver}} driver`, out.V{"driver": pick.String()})
}
return pick, alts, false
}