From 586b1c7eae5df4da86f5bbce32a37b68ef649f2c Mon Sep 17 00:00:00 2001 From: Thorsten Klein Date: Wed, 4 Nov 2020 15:44:46 +0100 Subject: [PATCH] clusterCreate: use docker VM IP for API connection (#399) Try - `docker-machine ip` - host lookup for `host.docker.internal` Fixes #388 --- pkg/cluster/cluster.go | 18 +++++++++ pkg/runtimes/docker/machine.go | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 pkg/runtimes/docker/machine.go diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 6be6fa5c..55bb45ad 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -31,8 +31,11 @@ import ( "strings" "time" + gort "runtime" + "github.com/imdario/mergo" k3drt "github.com/rancher/k3d/v3/pkg/runtimes" + "github.com/rancher/k3d/v3/pkg/runtimes/docker" "github.com/rancher/k3d/v3/pkg/types" k3d "github.com/rancher/k3d/v3/pkg/types" "github.com/rancher/k3d/v3/pkg/util" @@ -60,6 +63,21 @@ func ClusterCreate(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Clus * Network */ + if cluster.ExposeAPI.Host == k3d.DefaultAPIHost && runtime == k3drt.Docker { + if gort.GOOS == "windows" || gort.GOOS == "darwin" { + log.Tracef("Running on %s -> Trying to get IP of the docker machine", gort.GOOS) + machineIP, err := runtime.(docker.Docker).GetDockerMachineIP() + if err != nil { + log.Warnf("Failed to get Docker Machine IP: %+v", err) + } else if machineIP != "" { + log.Infof("Using the docker machine IP %s to connect to the Kubernetes API", machineIP) + cluster.ExposeAPI.Host = machineIP + cluster.ExposeAPI.HostIP = machineIP + } + } + + } + // error out if external cluster network should be used but no name was set if cluster.Network.Name == "" && cluster.Network.External { return fmt.Errorf("Failed to use external network because no name was specified") diff --git a/pkg/runtimes/docker/machine.go b/pkg/runtimes/docker/machine.go new file mode 100644 index 00000000..4161c9e4 --- /dev/null +++ b/pkg/runtimes/docker/machine.go @@ -0,0 +1,74 @@ +/* +Copyright © 2020 The k3d Author(s) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +package docker + +import ( + "fmt" + "net" + "os" + "os/exec" + "strings" + + log "github.com/sirupsen/logrus" +) + +func (d Docker) GetDockerMachineIP() (string, error) { + machine := os.ExpandEnv("$DOCKER_MACHINE_NAME") + dockerHostName := "host.docker.internal" + + // Option 1: use the docker-machine executable + if machine != "" { + dockerMachinePath, err := exec.LookPath("docker-machine") + if err != nil { + return "", err + } + + out, err := exec.Command(dockerMachinePath, "ip", machine).Output() + if err != nil { + log.Printf("Error executing 'docker-machine ip'") + + if exitError, ok := err.(*exec.ExitError); ok { + log.Printf("%s", string(exitError.Stderr)) + } + return "", err + } + ipStr := strings.TrimSuffix(string(out), "\n") + ipStr = strings.TrimSuffix(ipStr, "\r") + + return ipStr, nil + } + + // Option 2: Try to lookup "host.docker.internal" + log.Debugf("Docker Machine not found, trying to lookup '%s' instead...", dockerHostName) + addrs, err := net.LookupHost(dockerHostName) + if err != nil { + log.Debugf("Lookup of Host %s failed: %+v", dockerHostName, err) + return "", fmt.Errorf("Failed to get IP of Docker VM") + } + if len(addrs) == 0 { + log.Debugf("Lookup of Host %s didn't return any addresses", dockerHostName) + return "", fmt.Errorf("Failed to get IP of Docker VM") + } + log.Debugf("Addresses returned for %s: %+v", dockerHostName, addrs) + return addrs[0], nil +}