Explorar o código

Merge pull request #40007 from arkodg/add-host-docker-internal

Support host.docker.internal in dockerd on Linux
Sebastiaan van Stijn %!s(int64=5) %!d(string=hai) anos
pai
achega
ca20bc4214

+ 1 - 0
cmd/dockerd/config.go

@@ -64,6 +64,7 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) error {
 	flags.Var(opts.NewListOptsRef(&conf.DNS, opts.ValidateIPAddress), "dns", "DNS server to use")
 	flags.Var(opts.NewNamedListOptsRef("dns-opts", &conf.DNSOptions, nil), "dns-opt", "DNS options to use")
 	flags.Var(opts.NewListOptsRef(&conf.DNSSearch, opts.ValidateDNSSearch), "dns-search", "DNS search domains to use")
+	flags.Var(opts.NewIPOpt(&conf.HostGatewayIP, ""), "host-gateway-ip", "IP address that the special 'host-gateway' string in --add-host resolves to. Defaults to the IP address of the default bridge")
 	flags.Var(opts.NewNamedListOptsRef("labels", &conf.Labels, opts.ValidateLabel), "label", "Set key=value labels to the daemon")
 	flags.StringVar(&conf.LogConfig.Type, "log-driver", "json-file", "Default driver for container logs")
 	flags.Var(opts.NewNamedMapOpts("log-opts", conf.LogConfig.Config, nil), "log-opt", "Default log driver options for containers")

+ 5 - 3
daemon/config/config.go

@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net"
 	"os"
 	"reflect"
 	"strings"
@@ -115,9 +116,10 @@ type CommonTLSOptions struct {
 
 // DNSConfig defines the DNS configurations.
 type DNSConfig struct {
-	DNS        []string `json:"dns,omitempty"`
-	DNSOptions []string `json:"dns-opts,omitempty"`
-	DNSSearch  []string `json:"dns-search,omitempty"`
+	DNS           []string `json:"dns,omitempty"`
+	DNSOptions    []string `json:"dns-opts,omitempty"`
+	DNSSearch     []string `json:"dns-search,omitempty"`
+	HostGatewayIP net.IP   `json:"host-gateway-ip,omitempty"`
 }
 
 // CommonConfig defines the configuration of a docker daemon which is

+ 10 - 0
daemon/container_operations.go

@@ -115,6 +115,16 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
 			return nil, err
 		}
 		parts := strings.SplitN(extraHost, ":", 2)
+		// If the IP Address is a string called "host-gateway", replace this
+		// value with the IP address stored in the daemon level HostGatewayIP
+		// config variable
+		if parts[1] == network.HostGatewayName {
+			gateway := daemon.configStore.HostGatewayIP.String()
+			if gateway == "" {
+				return nil, fmt.Errorf("unable to derive the IP value for host-gateway")
+			}
+			parts[1] = gateway
+		}
 		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
 	}
 

+ 13 - 0
daemon/daemon_unix.go

@@ -932,6 +932,19 @@ func (daemon *Daemon) initNetworkController(config *config.Config, activeSandbox
 		removeDefaultBridgeInterface()
 	}
 
+	// Set HostGatewayIP to the default bridge's IP  if it is empty
+	if daemon.configStore.HostGatewayIP == nil && controller != nil {
+		if n, err := controller.NetworkByName("bridge"); err == nil {
+			v4Info, v6Info := n.Info().IpamInfo()
+			var gateway net.IP
+			if len(v4Info) > 0 {
+				gateway = v4Info[0].Gateway.IP
+			} else if len(v6Info) > 0 {
+				gateway = v6Info[0].Gateway.IP
+			}
+			daemon.configStore.HostGatewayIP = gateway
+		}
+	}
 	return controller, nil
 }
 

+ 8 - 0
daemon/network/constants.go

@@ -0,0 +1,8 @@
+package network
+
+const (
+	// HostGatewayName is the string value that can be passed
+	// to the IPAddr section in --add-host that is replaced by
+	// the value of HostGatewayIP daemon config value
+	HostGatewayName = "host-gateway"
+)

+ 44 - 0
integration/container/daemon_linux_test.go

@@ -120,3 +120,47 @@ func TestDaemonRestartIpcMode(t *testing.T) {
 	assert.NilError(t, err)
 	assert.Check(t, is.Equal(string(inspect.HostConfig.IpcMode), "shareable"))
 }
+
+// TestDaemonHostGatewayIP verifies that when a magic string "host-gateway" is passed
+// to ExtraHosts (--add-host) instead of an IP address, its value is set to
+// 1. Daemon config flag value specified by host-gateway-ip or
+// 2. IP of the default bridge network
+// and is added to the /etc/hosts file
+func TestDaemonHostGatewayIP(t *testing.T) {
+	skip.If(t, testEnv.IsRemoteDaemon)
+	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
+	t.Parallel()
+
+	// Verify the IP in /etc/hosts is same as host-gateway-ip
+	d := daemon.New(t)
+	// Verify the IP in /etc/hosts is same as the default bridge's IP
+	d.StartWithBusybox(t)
+	c := d.NewClientT(t)
+	ctx := context.Background()
+	cID := container.Run(ctx, t, c,
+		container.WithExtraHost("host.docker.internal:host-gateway"),
+	)
+	res, err := container.Exec(ctx, c, cID, []string{"cat", "/etc/hosts"})
+	assert.NilError(t, err)
+	assert.Assert(t, is.Len(res.Stderr(), 0))
+	assert.Equal(t, 0, res.ExitCode)
+	inspect, err := c.NetworkInspect(ctx, "bridge", types.NetworkInspectOptions{})
+	assert.NilError(t, err)
+	assert.Check(t, is.Contains(res.Stdout(), inspect.IPAM.Config[0].Gateway))
+	c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
+	d.Stop(t)
+
+	// Verify the IP in /etc/hosts is same as host-gateway-ip
+	d.StartWithBusybox(t, "--host-gateway-ip=6.7.8.9")
+	cID = container.Run(ctx, t, c,
+		container.WithExtraHost("host.docker.internal:host-gateway"),
+	)
+	res, err = container.Exec(ctx, c, cID, []string{"cat", "/etc/hosts"})
+	assert.NilError(t, err)
+	assert.Assert(t, is.Len(res.Stderr(), 0))
+	assert.Equal(t, 0, res.ExitCode)
+	assert.Check(t, is.Contains(res.Stdout(), "6.7.8.9"))
+	c.ContainerRemove(ctx, cID, types.ContainerRemoveOptions{Force: true})
+	d.Stop(t)
+
+}

+ 8 - 0
integration/internal/container/ops.go

@@ -180,3 +180,11 @@ func WithCgroupnsMode(mode string) func(*TestContainerConfig) {
 		c.HostConfig.CgroupnsMode = containertypes.CgroupnsMode(mode)
 	}
 }
+
+// WithExtraHost sets the user defined IP:Host mappings in the container's
+// /etc/hosts file
+func WithExtraHost(extraHost string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.HostConfig.ExtraHosts = append(c.HostConfig.ExtraHosts, extraHost)
+	}
+}

+ 6 - 2
opts/hosts.go

@@ -8,6 +8,7 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/docker/docker/daemon/network"
 	"github.com/docker/docker/pkg/homedir"
 )
 
@@ -169,8 +170,11 @@ func ValidateExtraHost(val string) (string, error) {
 	if len(arr) != 2 || len(arr[0]) == 0 {
 		return "", fmt.Errorf("bad format for add-host: %q", val)
 	}
-	if _, err := ValidateIPAddress(arr[1]); err != nil {
-		return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
+	// Skip IPaddr validation for special "host-gateway" string
+	if arr[1] != network.HostGatewayName {
+		if _, err := ValidateIPAddress(arr[1]); err != nil {
+			return "", fmt.Errorf("invalid IP address in add-host: %q", arr[1])
+		}
 	}
 	return val, nil
 }