From 59eb8b713b8600af0e04a69546af678bb82ed74e Mon Sep 17 00:00:00 2001 From: iwilltry42 Date: Thu, 2 Dec 2021 21:44:10 +0100 Subject: [PATCH] GetDockerHost to return host.docker.internal if DfD and local connection (and it's resolvable) --- pkg/client/host.go | 8 ++------ pkg/runtimes/docker/docker.go | 28 +++++++++++++++++++++++++++- pkg/runtimes/docker/util.go | 18 ++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/pkg/client/host.go b/pkg/client/host.go index b038241863..36d4160ff3 100644 --- a/pkg/client/host.go +++ b/pkg/client/host.go @@ -28,10 +28,10 @@ import ( "net" "regexp" goruntime "runtime" - "strings" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/rancher/k3d/v5/pkg/runtimes" + "github.com/rancher/k3d/v5/pkg/runtimes/docker" k3d "github.com/rancher/k3d/v5/pkg/types" "github.com/rancher/k3d/v5/pkg/util" ) @@ -64,15 +64,11 @@ func GetHostIP(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.Clust l.Log().Tracef("GOOS: %s / Runtime OS: %s (%s)", goruntime.GOOS, rtimeInfo.OSType, rtimeInfo.OS) - isDockerDesktop := func(os string) bool { - return strings.ToLower(os) == "docker desktop" - } - // Docker Runtime if runtime == runtimes.Docker { // Docker (for Desktop) on MacOS or Windows - if isDockerDesktop(rtimeInfo.OS) { + if docker.IsDockerDesktop(rtimeInfo.OS) { toolsNode, err := EnsureToolsNode(ctx, runtime, cluster) if err != nil { diff --git a/pkg/runtimes/docker/docker.go b/pkg/runtimes/docker/docker.go index cf242f9970..a46820ca9a 100644 --- a/pkg/runtimes/docker/docker.go +++ b/pkg/runtimes/docker/docker.go @@ -23,6 +23,7 @@ THE SOFTWARE. package docker import ( + "net" "net/url" "os" @@ -42,12 +43,37 @@ func (d Docker) ID() string { // GetHost returns the docker daemon host func (d Docker) GetHost() string { + // a) DOCKER_HOST env var dockerHost := os.Getenv("DOCKER_HOST") + if dockerHost == "" { + l.Log().Traceln("[Docker] GetHost: DOCKER_HOST empty/unset") + info, err := d.Info() + if err != nil { + l.Log().Errorf("error getting runtime information: %v", err) + return "" + } + // b) Docker for Desktop (Win/Mac) and it's a local connection + if IsDockerDesktop(info.OS) && IsLocalConnection(info.Endpoint) { + // b.1) local DfD connection, but inside WSL, where host.docker.internal resolves to an IP, but it's not reachable + if _, ok := os.LookupEnv("WSL_DISTRO_NAME"); ok { + l.Log().Debugln("wanted to use 'host.docker.internal' as docker host, but it's not reachable in WSL2") + return "" + } + l.Log().Debugln("[Docker] Local DfD: using 'host.docker.internal'") + dockerHost = "host.docker.internal" + if _, err := net.LookupHost(dockerHost); err != nil { + l.Log().Debugf("wanted to use 'host.docker.internal' as docker host, but it's not resolvable locally") + return "" + } + } + } url, err := url.Parse(dockerHost) if err != nil { + l.Log().Debugf("[Docker] GetHost: error parsing '%s' as URL: %v", dockerHost, url) return "" } - l.Log().Debugf("DockerHost: %s", url.Host) + l.Log().Debugf("DockerHost: '%s'", url.Host) + return url.Host } diff --git a/pkg/runtimes/docker/util.go b/pkg/runtimes/docker/util.go index f9d34bd96b..42eea95ed6 100644 --- a/pkg/runtimes/docker/util.go +++ b/pkg/runtimes/docker/util.go @@ -28,6 +28,8 @@ import ( "fmt" "io" "os" + "regexp" + "strings" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/flags" @@ -42,6 +44,22 @@ import ( "github.com/spf13/pflag" ) +func IsDockerDesktop(os string) bool { + return strings.ToLower(os) == "docker desktop" +} + +/* + * Simple Matching to detect local connection: + * - file (socket): starts with / (absolute path) + * - tcp://(localhost|127.0.0.1) + * - ssh://(localhost|127.0.0.1) + */ +var LocalConnectionRegexp = regexp.MustCompile(`^(/|((tcp|ssh)://(localhost|127\.0\.0\.1))).*`) + +func IsLocalConnection(endpoint string) bool { + return LocalConnectionRegexp.Match([]byte(endpoint)) +} + // GetDefaultObjectLabelsFilter returns docker type filters created from k3d labels func GetDefaultObjectLabelsFilter(clusterName string) filters.Args { filters := filters.NewArgs()