Skip to content

Commit 24acd52

Browse files
committed
fix: improve detection of minikube clusters
Signed-off-by: Russell Centanni <russell.centanni@gmail.com>
1 parent 45a50ae commit 24acd52

12 files changed

Lines changed: 89 additions & 58 deletions

File tree

cmd/cleanup/images.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package cleanup
22

33
import (
44
"context"
5+
"github.com/loft-sh/devspace/pkg/devspace/docker"
56

67
"github.com/loft-sh/devspace/cmd/flags"
7-
"github.com/loft-sh/devspace/pkg/devspace/docker"
88
"github.com/loft-sh/devspace/pkg/util/factory"
99
"github.com/loft-sh/devspace/pkg/util/message"
1010

@@ -48,31 +48,23 @@ func (cmd *imagesCmd) RunCleanupImages(f factory.Factory, cobraCmd *cobra.Comman
4848
if err != nil {
4949
return err
5050
}
51-
kubeConfigLoader := f.NewKubeConfigLoader()
51+
5252
configExists, err := configLoader.SetDevSpaceRoot(log)
5353
if err != nil {
5454
return err
5555
}
56+
5657
if !configExists {
5758
return errors.New(message.ConfigNotFound)
5859
}
5960

60-
// Get active context
61-
kubeContext, err := kubeConfigLoader.GetCurrentContext()
62-
if err != nil {
63-
return err
64-
}
65-
if cmd.KubeContext != "" {
66-
kubeContext = cmd.KubeContext
67-
}
68-
69-
kubeClient, err := f.NewKubeDefaultClient()
61+
kubeClient, err := f.NewKubeClientFromContext(cmd.KubeContext, cmd.Namespace)
7062
if err != nil {
7163
return errors.Wrap(err, "new kube client")
7264
}
7365

7466
// Create docker client
75-
client, err := docker.NewClientWithMinikube(ctx, kubeContext, true, log)
67+
client, err := docker.NewClientWithMinikube(ctx, kubeClient, true, log)
7668
if err != nil {
7769
return err
7870
}

pkg/devspace/build/builder/buildkit/buildkit.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ func (b *Builder) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bool)
7171

7272
// Check if image is present in local docker daemon
7373
if !rebuild && err == nil && b.helper.ImageConf.BuildKit.InCluster == nil {
74-
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient().CurrentContext()) {
75-
dockerClient, err := dockerpkg.NewClientWithMinikube(ctx.Context(), ctx.KubeClient().CurrentContext(), b.helper.ImageConf.BuildKit.PreferMinikube == nil || *b.helper.ImageConf.BuildKit.PreferMinikube, ctx.Log())
74+
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient()) {
75+
dockerClient, err := dockerpkg.NewClientWithMinikube(ctx.Context(), ctx.KubeClient(), b.helper.ImageConf.BuildKit.PreferMinikube == nil || *b.helper.ImageConf.BuildKit.PreferMinikube, ctx.Log())
7676
if err != nil {
7777
return false, err
7878
}
@@ -108,14 +108,14 @@ func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfil
108108
}
109109

110110
// We skip pushing when it is the minikube client
111-
usingLocalKubernetes := ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient().CurrentContext())
111+
usingLocalKubernetes := ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient())
112112
if b.skipPushOnLocalKubernetes && usingLocalKubernetes {
113113
b.skipPush = true
114114
}
115115

116116
// Should we use the minikube docker daemon?
117117
useMinikubeDocker := false
118-
if ctx.KubeClient() != nil && kubectl.IsMinikubeKubernetes(ctx.KubeClient().CurrentContext()) && (buildKitConfig.PreferMinikube == nil || *buildKitConfig.PreferMinikube) {
118+
if ctx.KubeClient() != nil && kubectl.IsMinikubeKubernetes(ctx.KubeClient()) && (buildKitConfig.PreferMinikube == nil || *buildKitConfig.PreferMinikube) {
119119
useMinikubeDocker = true
120120
}
121121

@@ -191,7 +191,7 @@ func buildWithCLI(ctx context.Context, dir string, environ expand.Environ, conte
191191
err error
192192
)
193193
if useMinikubeDocker {
194-
minikubeEnv, err = dockerpkg.GetMinikubeEnvironment(ctx)
194+
minikubeEnv, err = dockerpkg.GetMinikubeEnvironment(ctx, kubeClient.CurrentContext())
195195
if err != nil {
196196
return fmt.Errorf("error retrieving minikube environment with 'minikube docker-env --shell none'. Try setting the option preferMinikube to false: %v", err)
197197
}

pkg/devspace/build/builder/docker/docker.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (b *Builder) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bool)
5858

5959
// Check if image is present in local docker daemon
6060
if !rebuild && err == nil {
61-
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient().CurrentContext()) {
61+
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient()) {
6262
found, err := b.helper.IsImageAvailableLocally(ctx, b.client)
6363
if !found && err == nil {
6464
ctx.Log().Infof("Rebuild image %s because it was not found in local docker daemon", imageName)
@@ -88,7 +88,7 @@ func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfil
8888
}
8989

9090
// We skip pushing when it is the minikube client
91-
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient().CurrentContext()) {
91+
if b.skipPushOnLocalKubernetes && ctx.KubeClient() != nil && kubectl.IsLocalKubernetes(ctx.KubeClient()) {
9292
b.skipPush = true
9393
}
9494

pkg/devspace/build/builder/helper/helper.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/docker/docker/pkg/progress"
77
"github.com/docker/docker/pkg/streamformatter"
88
"github.com/loft-sh/devspace/pkg/devspace/build/builder/restart"
9+
"github.com/loft-sh/devspace/pkg/util/kubeconfig"
910
logpkg "github.com/loft-sh/devspace/pkg/util/log"
1011
dockerterm "github.com/moby/term"
1112
"github.com/sirupsen/logrus"
@@ -156,9 +157,26 @@ func (b *BuildHelper) ShouldRebuild(ctx devspacecontext.Context, forceRebuild bo
156157
ctx.Log().Infof("Rebuild image %s because entrypoint has changed", imageCache.ImageName)
157158
}
158159

160+
var lastContextClient kubectl.Client
161+
if ctx.Config().LocalCache().GetLastContext() != nil {
162+
lastContextClient, err = kubectl.NewClientFromContext(
163+
ctx.Config().LocalCache().GetLastContext().Context,
164+
ctx.Config().LocalCache().GetLastContext().Namespace,
165+
false,
166+
kubeconfig.NewLoader(),
167+
)
168+
if err != nil {
169+
return false, err
170+
}
171+
}
172+
159173
// Okay this check verifies if the previous deploy context was local kubernetes context where we didn't push the image and now have a kubernetes context where we probably push
160174
// or use another docker client (e.g. minikube <-> docker-desktop)
161-
if !mustRebuild && ctx.KubeClient() != nil && ctx.Config().LocalCache().GetLastContext() != nil && ctx.Config().LocalCache().GetLastContext().Context != ctx.KubeClient().CurrentContext() && kubectl.IsLocalKubernetes(ctx.Config().LocalCache().GetLastContext().Context) {
175+
if !mustRebuild &&
176+
ctx.KubeClient() != nil &&
177+
ctx.Config().LocalCache().GetLastContext() != nil &&
178+
ctx.Config().LocalCache().GetLastContext().Context != ctx.KubeClient().CurrentContext() &&
179+
kubectl.IsLocalKubernetes(lastContextClient) {
162180
mustRebuild = true
163181
ctx.Log().Infof("Rebuild image %s because previous build was local kubernetes", imageCache.ImageName)
164182
ctx.Config().LocalCache().SetLastContext(&localcache.LastContextConfig{

pkg/devspace/build/create_builder.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
devspacecontext "github.com/loft-sh/devspace/pkg/devspace/context"
1414
dockerclient "github.com/loft-sh/devspace/pkg/devspace/docker"
1515
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
16-
"github.com/loft-sh/devspace/pkg/util/kubeconfig"
1716
"github.com/pkg/errors"
1817
)
1918

@@ -61,17 +60,7 @@ func (c *controller) createBuilder(ctx devspacecontext.Context, imageConf *lates
6160
preferMinikube = *imageConf.Docker.PreferMinikube
6261
}
6362

64-
kubeContext := ""
65-
if ctx.KubeClient() == nil {
66-
kubeContext, err = kubeconfig.NewLoader().GetCurrentContext()
67-
if err != nil {
68-
return nil, errors.Wrap(err, "get current context")
69-
}
70-
} else {
71-
kubeContext = ctx.KubeClient().CurrentContext()
72-
}
73-
74-
dockerClient, err := dockerclient.NewClientWithMinikube(ctx.Context(), kubeContext, preferMinikube, ctx.Log())
63+
dockerClient, err := dockerclient.NewClientWithMinikube(ctx.Context(), ctx.KubeClient(), preferMinikube, ctx.Log())
7564
if err != nil {
7665
return nil, errors.Errorf("Error creating docker client: %v", err)
7766
}

pkg/devspace/build/localregistry/util.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func UseLocalRegistry(client kubectl.Client, config *latest.Config, imageConfig
8282
isVClusterContext := strings.Contains(context, "vcluster_")
8383

8484
// Determine if this is a local kubernetes cluster
85-
isLocalKubernetes := kubectl.IsLocalKubernetes(context)
85+
isLocalKubernetes := kubectl.IsLocalKubernetes(client)
8686
return !isLocalKubernetes && !(isVClusterContext && isLocalKubernetes)
8787
}
8888

pkg/devspace/configure/image.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package configure
33
import (
44
"context"
55
"fmt"
6+
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
67
"github.com/loft-sh/devspace/pkg/util/dockerfile"
78
"mvdan.cc/sh/v3/expand"
89
"os"
@@ -115,14 +116,13 @@ func (m *manager) AddImage(imageName, image, projectNamespace, dockerfile string
115116
}
116117

117118
if image == "" && buildMethod != skip {
118-
// Ignore error as context may not be a Space
119-
kubeContext, err := m.factory.NewKubeConfigLoader().GetCurrentContext()
119+
kubeClient, err := kubectl.NewDefaultClient()
120120
if err != nil {
121121
return err
122122
}
123123

124124
// Get docker client
125-
dockerClient, err := m.factory.NewDockerClientWithMinikube(context.TODO(), kubeContext, true, m.log)
125+
dockerClient, err := m.factory.NewDockerClientWithMinikube(context.TODO(), kubeClient, true, m.log)
126126
if err != nil {
127127
return errors.Errorf("Cannot create docker client: %v", err)
128128
}

pkg/devspace/configure/manager.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package configure
22

33
import (
44
"context"
5+
"github.com/loft-sh/devspace/pkg/devspace/kubectl"
56

67
"github.com/loft-sh/devspace/pkg/devspace/config/localcache"
78
"github.com/loft-sh/devspace/pkg/devspace/config/versions/latest"
@@ -21,7 +22,7 @@ type Manager interface {
2122

2223
// Factory defines the factory methods needed by the configure manager to create new configuration
2324
type Factory interface {
24-
NewDockerClientWithMinikube(ctx context.Context, currentKubeContext string, preferMinikube bool, log log.Logger) (docker.Client, error)
25+
NewDockerClientWithMinikube(ctx context.Context, client kubectl.Client, preferMinikube bool, log log.Logger) (docker.Client, error)
2526
NewKubeConfigLoader() kubeconfig.Loader
2627
}
2728

pkg/devspace/docker/client.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ type client struct {
5353

5454
// NewClient retrieves a new docker client
5555
func NewClient(ctx context.Context, log log.Logger) (Client, error) {
56-
return NewClientWithMinikube(ctx, "", false, log)
56+
return NewClientWithMinikube(ctx, nil, false, log)
5757
}
5858

5959
// NewClientWithMinikube creates a new docker client with optionally from the minikube vm
60-
func NewClientWithMinikube(ctx context.Context, currentKubeContext string, preferMinikube bool, log log.Logger) (Client, error) {
60+
func NewClientWithMinikube(ctx context.Context, kubectlClient kubectl.Client, preferMinikube bool, log log.Logger) (Client, error) {
6161
var cli Client
6262
var err error
6363

6464
if preferMinikube {
65-
cli, err = newDockerClientFromMinikube(ctx, currentKubeContext)
65+
cli, err = newDockerClientFromMinikube(ctx, kubectlClient)
6666
if err != nil && err != errNotMinikube {
6767
log.Warnf("Error creating minikube docker client: %v", err)
6868
}
@@ -108,12 +108,12 @@ func newDockerClientFromEnvironment() (Client, error) {
108108
}, nil
109109
}
110110

111-
func newDockerClientFromMinikube(ctx context.Context, currentKubeContext string) (Client, error) {
112-
if !kubectl.IsMinikubeKubernetes(currentKubeContext) {
111+
func newDockerClientFromMinikube(ctx context.Context, kubectlClient kubectl.Client) (Client, error) {
112+
if !kubectl.IsMinikubeKubernetes(kubectlClient) {
113113
return nil, errNotMinikube
114114
}
115115

116-
env, err := GetMinikubeEnvironment(ctx)
116+
env, err := GetMinikubeEnvironment(ctx, kubectlClient.CurrentContext())
117117
if err != nil {
118118
return nil, errors.Errorf("can't retrieve minikube docker environment due to error: %v", err)
119119
}
@@ -155,8 +155,8 @@ func newDockerClientFromMinikube(ctx context.Context, currentKubeContext string)
155155
}, nil
156156
}
157157

158-
func GetMinikubeEnvironment(ctx context.Context) (map[string]string, error) {
159-
out, err := command.Output(ctx, "", expand.ListEnviron(os.Environ()...), "minikube", "docker-env", "--shell", "none")
158+
func GetMinikubeEnvironment(ctx context.Context, kubeContext string) (map[string]string, error) {
159+
out, err := command.Output(ctx, "", expand.ListEnviron(os.Environ()...), "minikube", "docker-env", "--shell", "none", "--profile", kubeContext)
160160
if err != nil {
161161
if ee, ok := err.(*exec.ExitError); ok {
162162
out = ee.Stderr

pkg/devspace/kubectl/util.go

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kubectl
33
import (
44
"context"
55
"fmt"
6+
"k8s.io/apimachinery/pkg/runtime"
67
"net"
78
"net/http"
89
"strings"
@@ -19,6 +20,7 @@ import (
1920

2021
const (
2122
minikubeContext = "minikube"
23+
minikubeProvider = "minikube.sigs.k8s.io"
2224
dockerDesktopContext = "docker-desktop"
2325
dockerForDesktopContext = "docker-for-desktop"
2426
)
@@ -203,15 +205,22 @@ func NewPortForwarder(client Client, pod *corev1.Pod, ports []string, addresses
203205
}
204206

205207
// IsLocalKubernetes returns true if the context belongs to a local Kubernetes cluster
206-
func IsLocalKubernetes(context string) bool {
207-
if context == minikubeContext ||
208-
strings.HasPrefix(context, "kind-") ||
208+
func IsLocalKubernetes(kubeClient Client) bool {
209+
if kubeClient == nil {
210+
return false
211+
}
212+
213+
if IsMinikubeKubernetes(kubeClient) {
214+
return true
215+
}
216+
217+
context := kubeClient.CurrentContext()
218+
if strings.HasPrefix(context, "kind-") ||
209219
context == dockerDesktopContext ||
210220
context == dockerForDesktopContext {
211221
return true
212222
} else if strings.Contains(context, "vcluster_") &&
213-
(strings.HasSuffix(context, minikubeContext) ||
214-
strings.HasSuffix(context, dockerDesktopContext) ||
223+
(strings.HasSuffix(context, dockerDesktopContext) ||
215224
strings.HasSuffix(context, dockerForDesktopContext) ||
216225
strings.Contains(context, "kind-")) {
217226
return true
@@ -220,15 +229,37 @@ func IsLocalKubernetes(context string) bool {
220229
return false
221230
}
222231

223-
func IsMinikubeKubernetes(context string) bool {
224-
if context == minikubeContext {
232+
func IsMinikubeKubernetes(kubeClient Client) bool {
233+
if kubeClient == nil {
234+
return false
235+
}
236+
237+
if kubeClient.CurrentContext() == minikubeContext {
225238
return true
226239
}
227240

228-
if strings.HasPrefix(context, "vcluster_") && strings.HasSuffix(context, minikubeContext) {
241+
if strings.Contains(kubeClient.CurrentContext(), "vcluster_") && strings.HasSuffix(kubeClient.CurrentContext(), minikubeContext) {
229242
return true
230243
}
231244

245+
if kubeClient.ClientConfig() == nil {
246+
return false
247+
}
248+
249+
if rawConfig, err := kubeClient.ClientConfig().RawConfig(); err == nil {
250+
clusters := rawConfig.Clusters[rawConfig.Contexts[rawConfig.CurrentContext].Cluster]
251+
for _, extension := range clusters.Extensions {
252+
ext, err := runtime.DefaultUnstructuredConverter.ToUnstructured(extension)
253+
if err == nil {
254+
if provider, ok := ext["provider"].(string); ok {
255+
if provider == minikubeProvider {
256+
return true
257+
}
258+
}
259+
}
260+
}
261+
}
262+
232263
return false
233264
}
234265

0 commit comments

Comments
 (0)