diff --git a/pkg/minikube/detect/detect.go b/pkg/minikube/detect/detect.go index ca98a3781e01..2322ff2ea9da 100644 --- a/pkg/minikube/detect/detect.go +++ b/pkg/minikube/detect/detect.go @@ -83,15 +83,6 @@ func IsAmd64M1Emulation() bool { return runtime.GOARCH == "amd64" && strings.HasPrefix(cpuid.CPU.BrandName, "VirtualApple") } -// EffectiveArch return architecture to use in minikube VM/container -// may differ from host arch -func EffectiveArch() string { - if IsAmd64M1Emulation() { - return "arm64" - } - return runtime.GOARCH -} - // MinikubeInstalledViaSnap returns true if the minikube binary path includes "snap". func MinikubeInstalledViaSnap() bool { ex, err := os.Executable() diff --git a/pkg/minikube/download/binary.go b/pkg/minikube/download/binary.go index 21b3edd5dabb..6de9d9c42814 100644 --- a/pkg/minikube/download/binary.go +++ b/pkg/minikube/download/binary.go @@ -22,8 +22,6 @@ import ( "path" "runtime" - "k8s.io/minikube/pkg/minikube/detect" - "github.com/blang/semver/v4" "github.com/pkg/errors" "k8s.io/klog/v2" @@ -81,7 +79,7 @@ func Binary(binary, version, osName, archName, binaryURL string) (string, error) return "", errors.Wrapf(err, "download failed: %s", url) } - if osName == runtime.GOOS && archName == detect.EffectiveArch() { + if osName == runtime.GOOS && archName == runtime.GOARCH { if err = os.Chmod(targetFilepath, 0755); err != nil { return "", errors.Wrapf(err, "chmod +x %s", targetFilepath) } diff --git a/pkg/minikube/download/image.go b/pkg/minikube/download/image.go index d8a903d8cd86..b099e71834f4 100644 --- a/pkg/minikube/download/image.go +++ b/pkg/minikube/download/image.go @@ -78,14 +78,44 @@ func ImageExistsInDaemon(img string) bool { // Check if image exists locally klog.Infof("Checking for %s in local docker daemon", img) cmd := exec.Command("docker", "images", "--format", "{{.Repository}}:{{.Tag}}@{{.Digest}}") - if output, err := cmd.Output(); err == nil { - if strings.Contains(string(output), image.TrimDockerIO(img)) { - klog.Infof("Found %s in local docker daemon, skipping pull", img) - return true - } + output, err := cmd.Output() + if err != nil { + klog.Warningf("failed to list docker images: %v", err) + return false } - // Else, pull it - return false + if !strings.Contains(string(output), image.TrimDockerIO(img)) { + return false + } + correctArch, err := isImageCorrectArch(img) + if err != nil { + klog.Warning(err) + return false + } + if !correctArch { + klog.Warningf("image %s is of wrong architecture", img) + return false + } + klog.Infof("Found %s in local docker daemon, skipping pull", img) + return true +} + +// isImageCorrectArch returns true if the image arch is the same as the binary +// arch. This is needed to resolve +// https://github.com/kubernetes/minikube/pull/19205 +func isImageCorrectArch(img string) (bool, error) { + ref, err := name.ParseReference(img) + if err != nil { + return false, fmt.Errorf("failed to parse reference: %v", err) + } + dImg, err := daemon.Image(ref) + if err != nil { + return false, fmt.Errorf("failed to get image from daemon: %v", err) + } + cfg, err := dImg.ConfigFile() + if err != nil { + return false, fmt.Errorf("failed to get config for %s: %v", img, err) + } + return cfg.Architecture == runtime.GOOS, nil } // ImageToCache downloads img (if not present in cache) and writes it to the local cache directory @@ -245,7 +275,8 @@ func CacheToDaemon(img string) (string, error) { return "", err } - cmd := exec.Command("docker", "pull", "--quiet", img) + platform := fmt.Sprintf("linux/%s", runtime.GOARCH) + cmd := exec.Command("docker", "pull", "--platform", platform, "--quiet", img) if output, err := cmd.CombinedOutput(); err != nil { klog.Warningf("failed to pull image digest (expected if offline): %s: %v", output, err) img = image.Tag(img) diff --git a/pkg/minikube/download/preload.go b/pkg/minikube/download/preload.go index 861ed2e79138..970ad656e59d 100644 --- a/pkg/minikube/download/preload.go +++ b/pkg/minikube/download/preload.go @@ -25,11 +25,11 @@ import ( "os" "path" "path/filepath" + "runtime" "strings" "cloud.google.com/go/storage" "google.golang.org/api/option" - "k8s.io/minikube/pkg/minikube/detect" "github.com/pkg/errors" "github.com/spf13/viper" @@ -64,8 +64,7 @@ func TarballName(k8sVersion, containerRuntime string) string { } else { storageDriver = "overlay2" } - arch := detect.EffectiveArch() - return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, arch) + return fmt.Sprintf("preloaded-images-k8s-%s-%s-%s-%s-%s.tar.lz4", PreloadVersion, k8sVersion, containerRuntime, storageDriver, runtime.GOARCH) } // returns the name of the checksum file diff --git a/pkg/minikube/machine/cache_binaries.go b/pkg/minikube/machine/cache_binaries.go index 1962e58fe52e..25fc26e3d53e 100644 --- a/pkg/minikube/machine/cache_binaries.go +++ b/pkg/minikube/machine/cache_binaries.go @@ -18,6 +18,7 @@ package machine import ( "path" + "runtime" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -25,7 +26,6 @@ import ( "k8s.io/minikube/pkg/minikube/assets" "k8s.io/minikube/pkg/minikube/bootstrapper" "k8s.io/minikube/pkg/minikube/command" - "k8s.io/minikube/pkg/minikube/detect" "k8s.io/minikube/pkg/minikube/download" ) @@ -53,7 +53,7 @@ func CacheBinariesForBootstrapper(version string, excludeBinaries []string, bina } bin := bin // https://go.dev/doc/faq#closures_and_goroutines g.Go(func() error { - if _, err := download.Binary(bin, version, "linux", detect.EffectiveArch(), binariesURL); err != nil { + if _, err := download.Binary(bin, version, "linux", runtime.GOARCH, binariesURL); err != nil { return errors.Wrapf(err, "caching binary %s", bin) } return nil diff --git a/pkg/minikube/node/cache.go b/pkg/minikube/node/cache.go index 4050de1abfc2..6feffc855763 100644 --- a/pkg/minikube/node/cache.go +++ b/pkg/minikube/node/cache.go @@ -103,7 +103,7 @@ func CacheKubectlBinary(k8sVersion, binaryURL string) (string, error) { binary = "kubectl.exe" } - return download.Binary(binary, k8sVersion, runtime.GOOS, detect.EffectiveArch(), binaryURL) + return download.Binary(binary, k8sVersion, runtime.GOOS, runtime.GOARCH, binaryURL) } // doCacheBinaries caches Kubernetes binaries in the foreground diff --git a/pkg/minikube/registry/drvs/docker/docker.go b/pkg/minikube/registry/drvs/docker/docker.go index 5feeefb87c97..9d5b11424618 100644 --- a/pkg/minikube/registry/drvs/docker/docker.go +++ b/pkg/minikube/registry/drvs/docker/docker.go @@ -33,6 +33,7 @@ import ( "k8s.io/minikube/pkg/drivers/kic" "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/config" + "k8s.io/minikube/pkg/minikube/detect" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/registry" @@ -151,6 +152,17 @@ var dockerVersionOrState = func() (string, registry.State) { return "", registry.State{Error: err, Installed: false, Healthy: false, Fix: "Install Docker", Doc: docURL} } + if detect.IsAmd64M1Emulation() { + return "", registry.State{ + Reason: "PROVIDER_DOCKER_INCORRECT_ARCH", + Installed: true, + Running: true, + Error: errors.New("Cannot use amd64 minikube binary to start minikube cluster with Docker driver on arm64 machine"), + Fix: "Download and use arm64 version of the minikube binary", + Doc: "https://minikube.sigs.k8s.io/docs/start/", + } + } + ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second) defer cancel()