Skip to content

Commit

Permalink
Merge pull request #3937 from laozc/check-gcr-access
Browse files Browse the repository at this point in the history
Select an accessible image repository for some users
  • Loading branch information
tstromberg authored May 7, 2019
2 parents 756cd0f + 144f651 commit a30bf66
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 5 deletions.
90 changes: 85 additions & 5 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 @@ -129,7 +133,8 @@ func init() {
startCmd.Flags().String(serviceCIDR, pkgutil.DefaultServiceCIDR, "The CIDR to be used for service cluster IPs.")
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(imageRepository, "", "Alternative image repository to pull docker images from. This can be used when you have limited access to gcr.io. Set it to \"auto\" to let minikube decide one for you. 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 @@ -188,7 +193,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 +271,57 @@ func showKubectlConnectInfo(kubeconfig *pkgutil.KubeConfigSetup) {
}
}

func selectImageRepository(mirrorCountry string, k8sVersion string) (bool, string, error) {
var tryCountries []string
var fallback string

if mirrorCountry != "" {
localRepos, ok := constants.ImageRepositories[mirrorCountry]
if !ok || len(localRepos) <= 0 {
return false, "", fmt.Errorf("invalid image mirror country code: %s", mirrorCountry)
}

tryCountries = append(tryCountries, mirrorCountry)

// we'll use the first repository as fallback
// when none of the mirrors in the given location is available
fallback = localRepos[0]

} else {
// always make sure global is preferred
tryCountries = append(tryCountries, "global")
for k := range constants.ImageRepositories {
if strings.ToLower(k) != "global" {
tryCountries = append(tryCountries, k)
}
}
}

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

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 tryCountries {
localRepos := constants.ImageRepositories[code]
for _, repo := range localRepos {
err := checkRepository(repo)
if err == nil {
return true, repo, nil
}
}
}

return false, fallback, nil
}

// validateConfig validates the supplied configuration against known bad combinations
func validateConfig() {
diskSizeMB := pkgutil.CalculateDiskSizeInMB(viper.GetString(humanReadableDiskSize))
Expand All @@ -287,13 +343,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
}

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 Expand Up @@ -335,6 +391,30 @@ func generateConfig(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) {
}
}

repository := viper.GetString(imageRepository)
mirrorCountry := strings.ToLower(viper.GetString(imageMirrorCountry))
if strings.ToLower(repository) == "auto" || mirrorCountry != "" {
console.OutStyle("connectivity", "checking main repository and mirrors for images")
found, autoSelectedRepository, err := selectImageRepository(mirrorCountry, k8sVersion)
if err != nil {
exit.WithError("Failed to check main repository and mirrors for images for images", err)
}

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

repository = autoSelectedRepository
}

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

cfg := cfg.Config{
MachineConfig: cfg.MachineConfig{
MinikubeISO: viper.GetString(isoURL),
Expand Down Expand Up @@ -375,7 +455,7 @@ func generateConfig(cmd *cobra.Command, k8sVersion string) (cfg.Config, error) {
CRISocket: viper.GetString(criSocket),
NetworkPlugin: selectedNetworkPlugin,
ServiceCIDR: viper.GetString(serviceCIDR),
ImageRepository: viper.GetString(imageRepository),
ImageRepository: repository,
ExtraOptions: extraOptions,
ShouldLoadCachedImages: viper.GetBool(cacheImages),
EnableDefaultCNI: selectedEnableDefaultCNI,
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 @@ -220,6 +220,12 @@ const (
DefaultMountVersion = "9p2000.L"
)

// ImageRepositories contains all known image repositories
var ImageRepositories = map[string][]string{
"global": {""},
"cn": {"registry.cn-hangzhou.aliyuncs.com/google_containers"},
}

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

0 comments on commit a30bf66

Please sign in to comment.