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

Select an accessible image repository for some users #3937

Merged
merged 4 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
87 changes: 84 additions & 3 deletions cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ import (
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -77,6 +80,7 @@ const (
dnsDomain = "dns-domain"
serviceCIDR = "service-cluster-ip-range"
imageRepository = "image-repository"
imageMirrorCountry = "image-mirror-country"
mountString = "mount-string"
disableDriverMounts = "disable-driver-mounts"
cacheImages = "cache-images"
Expand Down Expand Up @@ -130,6 +134,7 @@ func init() {
startCmd.Flags().StringSliceVar(&insecureRegistry, "insecure-registry", nil, "Insecure Docker registries to pass to the Docker daemon. The default service CIDR range will automatically be added.")
startCmd.Flags().StringSliceVar(&registryMirror, "registry-mirror", nil, "Registry mirrors to pass to the Docker daemon")
startCmd.Flags().String(imageRepository, "", "Alternative image repository to pull docker images from. This can be used when you have limited access to gcr.io. For Chinese mainland users, you may use local gcr.io mirrors such as registry.cn-hangzhou.aliyuncs.com/google_containers")
startCmd.Flags().String(imageMirrorCountry, "", "Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users, set it to cn")
startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd)")
startCmd.Flags().String(criSocket, "", "The cri socket path to be used")
startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
Expand Down Expand Up @@ -176,6 +181,28 @@ func runStart(cmd *cobra.Command, args []string) {
exit.WithError("Failed to generate config", err)
}

if config.KubernetesConfig.ImageRepository == "" {
laozc marked this conversation as resolved.
Show resolved Hide resolved
console.OutStyle("connectivity", "checking main repository and mirrors for images")
found, repository, err := selectImageRepository(config)
if err != nil {
exit.WithError("Failed to check main repository and mirrors for images for images", err)
}

if !found {
if repository == "" {
exit.WithCode(exit.Failure, "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag")
laozc marked this conversation as resolved.
Show resolved Hide resolved
} else {
console.Warning("None of known repositories in your location is accessible. Use %s as fallback.", repository)
}
}

config.KubernetesConfig.ImageRepository = repository
}

if config.KubernetesConfig.ImageRepository != "" {
console.OutStyle("success", "using image repository %s", config.KubernetesConfig.ImageRepository)
}

// For non-"none", the ISO is required to boot, so block until it is downloaded
if viper.GetString(vmDriver) != constants.DriverNone {
if err := cluster.CacheISO(config.MachineConfig); err != nil {
Expand All @@ -188,7 +215,7 @@ func runStart(cmd *cobra.Command, args []string) {

// Now that the ISO is downloaded, pull images in the background while the VM boots.
var cacheGroup errgroup.Group
beginCacheImages(&cacheGroup, k8sVersion)
beginCacheImages(&cacheGroup, config.KubernetesConfig.ImageRepository, k8sVersion)

// Abstraction leakage alert: startHost requires the config to be saved, to satistfy pkg/provision/buildroot.
// Hence, saveConfig must be called before startHost, and again afterwards when we know the IP.
Expand Down Expand Up @@ -266,6 +293,60 @@ func showKubectlConnectInfo(kubeconfig *pkgutil.KubeConfigSetup) {
}
}

func selectImageRepository(config cfg.Config) (bool, string, error) {
mirrorCountry := strings.ToLower(viper.GetString(imageMirrorCountry))
repos := constants.ImageRepositories
var countries []string
laozc marked this conversation as resolved.
Show resolved Hide resolved
if mirrorCountry != "" {
_, ok := repos[mirrorCountry]
if !ok {
return false, "", fmt.Errorf("invalid image mirror country code: %s", mirrorCountry)
}
countries = []string{mirrorCountry, ""}
laozc marked this conversation as resolved.
Show resolved Hide resolved

} else {
// make sure global is preferred
countries = []string{""}
for k := range repos {
laozc marked this conversation as resolved.
Show resolved Hide resolved
if k != "" {
countries = append(countries, k)
}
}
}

checkRepository := func(repo string) error {
podInfraContainerImage, _ := constants.GetKubeadmCachedImages(repo, config.KubernetesConfig.KubernetesVersion)

ref, err := name.ParseReference(podInfraContainerImage, name.WeakValidation)
if err != nil {
return err
}

_, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
return err
}

for _, code := range countries {
localRepos := repos[code]
for _, repo := range localRepos {
err := checkRepository(repo)
if err == nil {
return true, repo, nil
}
}
}

if mirrorCountry != "" {
if localRepos, ok := constants.ImageRepositories[mirrorCountry]; ok && len(localRepos) > 0 {
// none of the mirrors in the given location is available
// use the first as fallback
return false, localRepos[0], nil
}
}

return false, "", nil
}

// validateConfig validates the supplied configuration against known bad combinations
func validateConfig() {
diskSizeMB := pkgutil.CalculateDiskSizeInMB(viper.GetString(humanReadableDiskSize))
Expand All @@ -287,13 +368,13 @@ func doCacheBinaries(k8sVersion string) error {
}

// beginCacheImages caches Docker images in the background
func beginCacheImages(g *errgroup.Group, k8sVersion string) {
func beginCacheImages(g *errgroup.Group, imageRepository string, k8sVersion string) {
if !viper.GetBool(cacheImages) {
return
}
console.OutStyle("caching", "Downloading Kubernetes %s images in the background ...", k8sVersion)
g.Go(func() error {
return machine.CacheImagesForBootstrapper(viper.GetString(imageRepository), k8sVersion, viper.GetString(cmdcfg.Bootstrapper))
return machine.CacheImagesForBootstrapper(imageRepository, k8sVersion, viper.GetString(cmdcfg.Bootstrapper))
})
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/minikube/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ const (
DefaultMountVersion = "9p2000.L"
)

// ImageRepositories contains all known image repositories
var ImageRepositories = map[string][]string{
"": {""}, // global
laozc marked this conversation as resolved.
Show resolved Hide resolved
"cn": {"registry.cn-hangzhou.aliyuncs.com/google_containers"},
}

// GetKubernetesReleaseURL gets the location of a kubernetes client
func GetKubernetesReleaseURL(binaryName, version string) string {
return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/linux/%s/%s", version, runtime.GOARCH, binaryName)
Expand Down