Skip to content

Commit 8c28ca4

Browse files
committed
Select an accessible image repository for some users
Now it's possible to fallback to a mirror site for those users who cannot access the main k8s.gcr.io repository. You may also set the --image-mirror-country to forcibly use a known local mirror in the specific location. Signed-off-by: Zhongcheng Lao <[email protected]>
1 parent 702d471 commit 8c28ca4

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

cmd/minikube/cmd/start.go

+84-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ import (
3434
"github.com/docker/machine/libmachine/host"
3535
"github.com/docker/machine/libmachine/state"
3636
"github.com/golang/glog"
37+
"github.com/google/go-containerregistry/pkg/authn"
38+
"github.com/google/go-containerregistry/pkg/name"
39+
"github.com/google/go-containerregistry/pkg/v1/remote"
3740
"github.com/spf13/cobra"
3841
"github.com/spf13/viper"
3942
"golang.org/x/sync/errgroup"
@@ -77,6 +80,7 @@ const (
7780
dnsDomain = "dns-domain"
7881
serviceCIDR = "service-cluster-ip-range"
7982
imageRepository = "image-repository"
83+
imageMirrorCountry = "image-mirror-country"
8084
mountString = "mount-string"
8185
disableDriverMounts = "disable-driver-mounts"
8286
cacheImages = "cache-images"
@@ -128,6 +132,7 @@ func init() {
128132
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.")
129133
startCmd.Flags().StringSliceVar(&registryMirror, "registry-mirror", nil, "Registry mirrors to pass to the Docker daemon")
130134
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")
135+
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")
131136
startCmd.Flags().String(containerRuntime, "docker", "The container runtime to be used (docker, crio, containerd)")
132137
startCmd.Flags().String(criSocket, "", "The cri socket path to be used")
133138
startCmd.Flags().String(kubernetesVersion, constants.DefaultKubernetesVersion, "The kubernetes version that the minikube VM will use (ex: v1.2.3)")
@@ -172,8 +177,30 @@ func runStart(cmd *cobra.Command, args []string) {
172177
exit.WithError("Failed to generate config", err)
173178
}
174179

180+
if config.KubernetesConfig.ImageRepository == "" {
181+
console.OutStyle("connectivity", "checking main repository and mirrors for images")
182+
found, repository, err := selectImageRepository(config)
183+
if err != nil {
184+
exit.WithError("Failed to check main repository and mirrors for images for images", err)
185+
}
186+
187+
if !found {
188+
if repository == "" {
189+
exit.WithCode(exit.Failure, "None of known repositories is accessible. Consider specifying an alternative image repository with --image-repository flag")
190+
} else {
191+
console.Warning("None of known repositories in your location is accessible. Use %s as fallback.", repository)
192+
}
193+
}
194+
195+
config.KubernetesConfig.ImageRepository = repository
196+
}
197+
198+
if config.KubernetesConfig.ImageRepository != "" {
199+
console.OutStyle("success", "using image repository %s", config.KubernetesConfig.ImageRepository)
200+
}
201+
175202
var cacheGroup errgroup.Group
176-
beginCacheImages(&cacheGroup, k8sVersion)
203+
beginCacheImages(&cacheGroup, config.KubernetesConfig.ImageRepository, k8sVersion)
177204

178205
// Abstraction leakage alert: startHost requires the config to be saved, to satistfy pkg/provision/buildroot.
179206
// Hence, saveConfig must be called before startHost, and again afterwards when we know the IP.
@@ -228,6 +255,60 @@ func runStart(cmd *cobra.Command, args []string) {
228255
console.OutStyle("ready", "Done! Thank you for using minikube!")
229256
}
230257

258+
func selectImageRepository(config cfg.Config) (bool, string, error) {
259+
mirrorCountry := strings.ToLower(viper.GetString(imageMirrorCountry))
260+
repos := constants.ImageRepositories
261+
var countries []string
262+
if mirrorCountry != "" {
263+
_, ok := repos[mirrorCountry]
264+
if !ok {
265+
return false, "", fmt.Errorf("invalid image mirror country code: %s", mirrorCountry)
266+
}
267+
countries = []string{mirrorCountry, ""}
268+
269+
} else {
270+
// make sure global is preferred
271+
countries = []string{""}
272+
for k := range repos {
273+
if k != "" {
274+
countries = append(countries, k)
275+
}
276+
}
277+
}
278+
279+
checkRepository := func(repo string) error {
280+
podInfraContainerImage, _ := constants.GetKubeadmCachedImages(repo, config.KubernetesConfig.KubernetesVersion)
281+
282+
ref, err := name.ParseReference(podInfraContainerImage, name.WeakValidation)
283+
if err != nil {
284+
return err
285+
}
286+
287+
_, err = remote.Image(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
288+
return err
289+
}
290+
291+
for _, code := range countries {
292+
localRepos := repos[code]
293+
for _, repo := range localRepos {
294+
err := checkRepository(repo)
295+
if err == nil {
296+
return true, repo, nil
297+
}
298+
}
299+
}
300+
301+
if mirrorCountry != "" {
302+
if localRepos, ok := constants.ImageRepositories[mirrorCountry]; ok && len(localRepos) > 0 {
303+
// none of the mirrors in the given location is available
304+
// use the first as fallback
305+
return false, localRepos[0], nil
306+
}
307+
}
308+
309+
return false, "", nil
310+
}
311+
231312
// validateConfig validates the supplied configuration against known bad combinations
232313
func validateConfig() {
233314
diskSizeMB := pkgutil.CalculateDiskSizeInMB(viper.GetString(humanReadableDiskSize))
@@ -241,13 +322,13 @@ func validateConfig() {
241322
}
242323

243324
// beginCacheImages caches Docker images in the background
244-
func beginCacheImages(g *errgroup.Group, k8sVersion string) {
325+
func beginCacheImages(g *errgroup.Group, imageRepository string, k8sVersion string) {
245326
if !viper.GetBool(cacheImages) {
246327
return
247328
}
248329
console.OutStyle("caching", "Downloading Kubernetes %s images in the background ...", k8sVersion)
249330
g.Go(func() error {
250-
return machine.CacheImagesForBootstrapper(viper.GetString(imageRepository), k8sVersion, viper.GetString(cmdcfg.Bootstrapper))
331+
return machine.CacheImagesForBootstrapper(imageRepository, k8sVersion, viper.GetString(cmdcfg.Bootstrapper))
251332
})
252333
}
253334

pkg/minikube/constants/constants.go

+6
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,12 @@ const (
205205
DefaultMountVersion = "9p2000.L"
206206
)
207207

208+
// ImageRepositories contains all known image repositories
209+
var ImageRepositories = map[string][]string{
210+
"": {""}, // global
211+
"cn": {"registry.cn-hangzhou.aliyuncs.com/google_containers"},
212+
}
213+
208214
// GetKubernetesReleaseURL gets the location of a kubernetes client
209215
func GetKubernetesReleaseURL(binaryName, version string) string {
210216
return fmt.Sprintf("https://storage.googleapis.com/kubernetes-release/release/%s/bin/linux/%s/%s", version, runtime.GOARCH, binaryName)

0 commit comments

Comments
 (0)