diff --git a/pkg/minikube/tunnel/kic/service_tunnel.go b/pkg/minikube/tunnel/kic/service_tunnel.go index 5cc6bff7ac..6f4222f1b0 100644 --- a/pkg/minikube/tunnel/kic/service_tunnel.go +++ b/pkg/minikube/tunnel/kic/service_tunnel.go @@ -49,7 +49,11 @@ func (t *ServiceTunnel) Start(svcName, namespace string) ([]string, error) { return nil, err } - t.sshConn = createSSHConn(svcName, t.sshPort, t.sshKey, svc) + t.sshConn, err = createSSHConnWithRandomPorts(svcName, t.sshPort, t.sshKey, svc) + if err != nil { + glog.Errorf("error creating ssh conn: %v", err) + return nil, err + } go func() { err = t.sshConn.startAndWait() @@ -59,8 +63,8 @@ func (t *ServiceTunnel) Start(svcName, namespace string) ([]string, error) { }() urls := make([]string, 0, len(svc.Spec.Ports)) - for _, port := range svc.Spec.Ports { - urls = append(urls, fmt.Sprintf("http://127.0.0.1:%d", port.Port)) + for _, port := range t.sshConn.ports { + urls = append(urls, fmt.Sprintf("http://127.0.0.1:%d", port)) } return urls, nil diff --git a/pkg/minikube/tunnel/kic/ssh_conn.go b/pkg/minikube/tunnel/kic/ssh_conn.go index 4c98f0836f..d619a44bc5 100644 --- a/pkg/minikube/tunnel/kic/ssh_conn.go +++ b/pkg/minikube/tunnel/kic/ssh_conn.go @@ -20,6 +20,8 @@ import ( "fmt" "os/exec" + "github.com/phayes/freeport" + v1 "k8s.io/api/core/v1" ) @@ -27,6 +29,7 @@ type sshConn struct { name string service string cmd *exec.Cmd + ports []int } func createSSHConn(name, sshPort, sshKey string, svc *v1.Service) *sshConn { @@ -61,6 +64,47 @@ func createSSHConn(name, sshPort, sshKey string, svc *v1.Service) *sshConn { } } +func createSSHConnWithRandomPorts(name, sshPort, sshKey string, svc *v1.Service) (*sshConn, error) { + // extract sshArgs + sshArgs := []string{ + // TODO: document the options here + "-o", "UserKnownHostsFile=/dev/null", + "-o", "StrictHostKeyChecking no", + "-N", + "docker@127.0.0.1", + "-p", sshPort, + "-i", sshKey, + } + + usedPorts := make([]int, 0, len(svc.Spec.Ports)) + + for _, port := range svc.Spec.Ports { + freeport, err := freeport.GetFreePort() + if err != nil { + return nil, err + } + + arg := fmt.Sprintf( + "-L %d:%s:%d", + freeport, + svc.Spec.ClusterIP, + port.Port, + ) + + sshArgs = append(sshArgs, arg) + usedPorts = append(usedPorts, freeport) + } + + cmd := exec.Command("ssh", sshArgs...) + + return &sshConn{ + name: name, + service: svc.Name, + cmd: cmd, + ports: usedPorts, + }, nil +} + func (c *sshConn) startAndWait() error { fmt.Printf("starting tunnel for %s\n", c.service) err := c.cmd.Start()