Browse Source

Network scoped alias support

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal 9 years ago
parent
commit
dda513ef65

+ 4 - 1
api/client/network.go

@@ -118,6 +118,8 @@ func (cli *DockerCli) CmdNetworkConnect(args ...string) error {
 	flIPv6Address := cmd.String([]string{"-ip6"}, "", "IPv6 Address")
 	flLinks := opts.NewListOpts(runconfigopts.ValidateLink)
 	cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
+	flAliases := opts.NewListOpts(nil)
+	cmd.Var(&flAliases, []string{"-alias"}, "Add network-scoped alias for the container")
 	cmd.Require(flag.Min, 2)
 	if err := cmd.ParseFlags(args, true); err != nil {
 		return err
@@ -127,7 +129,8 @@ func (cli *DockerCli) CmdNetworkConnect(args ...string) error {
 			IPv4Address: *flIPAddress,
 			IPv6Address: *flIPv6Address,
 		},
-		Links: flLinks.GetAll(),
+		Links:   flLinks.GetAll(),
+		Aliases: flAliases.GetAll(),
 	}
 	return cli.client.NetworkConnect(cmd.Arg(0), cmd.Arg(1), epConfig)
 }

+ 4 - 0
container/container_unix.go

@@ -283,6 +283,10 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]
 			createOptions = append(createOptions,
 				libnetwork.CreateOptionIpam(net.ParseIP(ipam.IPv4Address), net.ParseIP(ipam.IPv6Address), nil))
 		}
+
+		for _, alias := range epConfig.Aliases {
+			createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
+		}
 	}
 
 	if !container.HostConfig.NetworkMode.IsUserDefined() {

+ 4 - 0
daemon/container_operations_unix.go

@@ -761,6 +761,10 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
 		return runconfig.ErrUnsupportedNetworkAndIP
 	}
 
+	if !containertypes.NetworkMode(idOrName).IsUserDefined() && len(endpointConfig.Aliases) > 0 {
+		return runconfig.ErrUnsupportedNetworkAndAlias
+	}
+
 	controller := daemon.netController
 
 	if err := validateNetworkingConfig(n, endpointConfig); err != nil {

+ 1 - 0
docs/reference/commandline/create.md

@@ -68,6 +68,7 @@ Creates a new container.
                                     'container:<name|id>': reuse another container's network stack
                                     'host': use the Docker host network stack
                                     '<network-name>|<network-id>': connect to a user-defined network
+      --net-alias=[]                Add network-scoped alias for the container
       --oom-kill-disable            Whether to disable OOM Killer for the container or not
       --oom-score-adj=0             Tune the host's OOM preferences for containers (accepts -1000 to 1000)
       -P, --publish-all             Publish all exposed ports to random ports

+ 8 - 0
docs/reference/commandline/network_connect.md

@@ -14,6 +14,7 @@ parent = "smn_cli"
 
     Connects a container to a network
 
+      --alias=[]         Add network-scoped alias for the container
       --help             Print usage
       --ip               IPv4 Address
       --ip6              IPv6 Address
@@ -45,6 +46,13 @@ You can use `--link` option to link another container with a prefered alias
 $ docker network connect --link container1:c1 multi-host-network container2
 ```
 
+`--alias` option can be used to resolve the container by another name in the network
+being connected to.
+
+```bash
+$ docker network connect --alias db --alias mysql multi-host-network container2
+```
+
 You can pause, restart, and stop containers that are connected to a network.
 Paused containers remain connected and can be revealed by a `network inspect`.
 When the container is stopped, it does not appear on the network until you restart

+ 1 - 0
docs/reference/commandline/run.md

@@ -68,6 +68,7 @@ parent = "smn_cli"
                                     'container:<name|id>': reuse another container's network stack
                                     'host': use the Docker host network stack
                                     '<network-name>|<network-id>': connect to a user-defined network
+      --net-alias=[]                Add network-scoped alias for the container
       --oom-kill-disable            Whether to disable OOM Killer for the container or not
       --oom-score-adj=0             Tune the host's OOM preferences for containers (accepts -1000 to 1000)
       -P, --publish-all             Publish all exposed ports to random ports

+ 1 - 0
docs/reference/run.md

@@ -273,6 +273,7 @@ of the containers.
                         'container:<name|id>': reuse another container's network stack
                         'host': use the Docker host network stack
                         '<network-name>|<network-id>': connect to a user-defined network
+    --net-alias=[]   : Add network-scoped alias for the container
     --add-host=""    : Add a line to /etc/hosts (host:IP)
     --mac-address="" : Sets the container's Ethernet device's MAC address
     --ip=""          : Sets the container's Ethernet device's IPv4 address

+ 124 - 0
docs/userguide/networking/work-with-networks.md

@@ -499,6 +499,130 @@ environment variables into a running container without significant effort and he
 it is not compatible with `docker network` which provides a dynamic way to connect/
 disconnect containers to/from a network.
 
+### Network-scoped alias
+
+While `links` provide private name resolution that is localized within a container,
+the network-scoped alias provides a way for a container to be discovered by an
+alternate name by any other container within the scope of a particular network.
+Unlike the `link` alias, which is defined by the consumer of a service, the
+network-scoped alias is defined by the container that is offering the service
+to the network.
+
+Continuing with the above example, create another container in `isolated_nw` with a
+network alias.
+
+```bash
+$ docker run --net=isolated_nw -itd --name=container6 --net-alias app busybox
+8ebe6767c1e0361f27433090060b33200aac054a68476c3be87ef4005eb1df17
+```
+
+```bash
+$ docker attach container4
+/ # ping -w 4 app
+PING app (172.25.0.6): 56 data bytes
+64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
+64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
+
+--- app ping statistics ---
+4 packets transmitted, 4 packets received, 0% packet loss
+round-trip min/avg/max = 0.070/0.081/0.097 ms
+
+/ # ping -w 4 container6
+PING container5 (172.25.0.6): 56 data bytes
+64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
+64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
+
+--- container6 ping statistics ---
+4 packets transmitted, 4 packets received, 0% packet loss
+round-trip min/avg/max = 0.070/0.081/0.097 ms
+```
+
+Now let us connect `container6` to the `local_alias` network with a different network-scoped
+alias.
+
+```
+$ docker network connect --alias scoped-app local_alias container6
+```
+
+`container6` in this example now is aliased as `app` in network `isolated_nw` and
+as `scoped-app` in network `local_alias`.
+
+Let's try to reach these aliases from `container4` (which is connected to both these networks)
+and `container5` (which is connected only to `isolated_nw`).
+
+```bash
+$ docker attach container4
+
+/ # ping -w 4 scoped-app
+PING foo (172.26.0.5): 56 data bytes
+64 bytes from 172.26.0.5: seq=0 ttl=64 time=0.070 ms
+64 bytes from 172.26.0.5: seq=1 ttl=64 time=0.080 ms
+64 bytes from 172.26.0.5: seq=2 ttl=64 time=0.080 ms
+64 bytes from 172.26.0.5: seq=3 ttl=64 time=0.097 ms
+
+--- foo ping statistics ---
+4 packets transmitted, 4 packets received, 0% packet loss
+round-trip min/avg/max = 0.070/0.081/0.097 ms
+
+$ docker attach container5
+
+/ # ping -w 4 scoped-app
+ping: bad address 'scoped-app'
+
+```
+
+As you can see, the alias is scoped to the network it is defined on and hence only
+those containers that are connected to that network can access the alias.
+
+In addition to the above features, multiple containers can share the same network-scoped
+alias within the same network. For example, let's launch `container7` in `isolated_nw` with
+the same alias as `container6`
+
+```bash
+$ docker run --net=isolated_nw -itd --name=container7 --net-alias app busybox
+3138c678c123b8799f4c7cc6a0cecc595acbdfa8bf81f621834103cd4f504554
+```
+
+When multiple containers share the same alias, name resolution to that alias will happen
+to one of the containers (typically the first container that is aliased). When the container
+that backs the alias goes down or disconnected from the network, the next container that
+backs the alias will be resolved.
+
+Let us ping the alias `app` from `container4` and bring down `container6` to verify that
+`container7` is resolving the `app` alias.
+
+```bash
+$ docker attach container4
+/ # ping -w 4 app
+PING app (172.25.0.6): 56 data bytes
+64 bytes from 172.25.0.6: seq=0 ttl=64 time=0.070 ms
+64 bytes from 172.25.0.6: seq=1 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=2 ttl=64 time=0.080 ms
+64 bytes from 172.25.0.6: seq=3 ttl=64 time=0.097 ms
+
+--- app ping statistics ---
+4 packets transmitted, 4 packets received, 0% packet loss
+round-trip min/avg/max = 0.070/0.081/0.097 ms
+
+$ docker stop container6
+
+$ docker attach container4
+/ # ping -w 4 app
+PING app (172.25.0.7): 56 data bytes
+64 bytes from 172.25.0.7: seq=0 ttl=64 time=0.095 ms
+64 bytes from 172.25.0.7: seq=1 ttl=64 time=0.075 ms
+64 bytes from 172.25.0.7: seq=2 ttl=64 time=0.072 ms
+64 bytes from 172.25.0.7: seq=3 ttl=64 time=0.101 ms
+
+--- app ping statistics ---
+4 packets transmitted, 4 packets received, 0% packet loss
+round-trip min/avg/max = 0.072/0.085/0.101 ms
+
+```
 
 ## Disconnecting containers
 

+ 37 - 0
integration-cli/docker_cli_network_unix_test.go

@@ -1138,5 +1138,42 @@ func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) {
 	c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1)))
 	c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2)))
 	c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network"))
+}
+
+func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
+	testRequires(c, DaemonIsLinux, NotUserNamespace)
+	dockerCmd(c, "network", "create", "-d", "bridge", "net1")
+	dockerCmd(c, "network", "create", "-d", "bridge", "net2")
+
+	dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top")
+	c.Assert(waitRun("first"), check.IsNil)
+
+	dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
+	c.Assert(waitRun("second"), check.IsNil)
+
+	// ping first container and its alias
+	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
+	c.Assert(err, check.IsNil)
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
+	c.Assert(err, check.IsNil)
+
+	// connect first container to net2 network
+	dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
+	// connect second container to foo2 network with a different alias for first container
+	dockerCmd(c, "network", "connect", "net2", "second")
+
+	// ping the new alias in network foo2
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
+	c.Assert(err, check.IsNil)
+
+	// disconnect first container from net1 network
+	dockerCmd(c, "network", "disconnect", "net1", "first")
 
+	// ping to net1 scoped alias "foo" must fail
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
+	c.Assert(err, check.NotNil)
+
+	// ping to net2 scoped alias "bar" must still succeed
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
+	c.Assert(err, check.IsNil)
 }

+ 31 - 0
integration-cli/docker_cli_run_test.go

@@ -273,6 +273,37 @@ func (s *DockerSuite) TestUserDefinedNetworkLinksWithRestart(c *check.C) {
 	c.Assert(err, check.IsNil)
 }
 
+func (s *DockerSuite) TestUserDefinedNetworkAlias(c *check.C) {
+	testRequires(c, DaemonIsLinux, NotUserNamespace)
+	dockerCmd(c, "network", "create", "-d", "bridge", "net1")
+
+	dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo1", "--net-alias=foo2", "busybox", "top")
+	c.Assert(waitRun("first"), check.IsNil)
+
+	dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
+	c.Assert(waitRun("second"), check.IsNil)
+
+	// ping to first and its network-scoped aliases
+	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
+	c.Assert(err, check.IsNil)
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1")
+	c.Assert(err, check.IsNil)
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2")
+	c.Assert(err, check.IsNil)
+
+	// Restart first container
+	dockerCmd(c, "restart", "first")
+	c.Assert(waitRun("first"), check.IsNil)
+
+	// ping to first and its network-scoped aliases must succeed
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
+	c.Assert(err, check.IsNil)
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo1")
+	c.Assert(err, check.IsNil)
+	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo2")
+	c.Assert(err, check.IsNil)
+}
+
 // Issue 9677.
 func (s *DockerSuite) TestRunWithDaemonFlags(c *check.C) {
 	out, _, err := dockerCmdWithError("--exec-opt", "foo=bar", "run", "-i", "busybox", "true")

+ 4 - 0
man/docker-create.1.md

@@ -52,6 +52,7 @@ docker-create - Create a new container
 [**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
 [**--name**[=*NAME*]]
 [**--net**[=*"bridge"*]]
+[**--net-alias**[=*[]*]]
 [**--oom-kill-disable**]
 [**--oom-score-adj**[=*0*]]
 [**-P**|**--publish-all**]
@@ -265,6 +266,9 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
                                'host': use the Docker host network stack.  Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.
                                '<network-name>|<network-id>': connect to a user-defined network
 
+**--net-alias**=[]
+   Add network-scoped alias for the container
+
 **--oom-kill-disable**=*true*|*false*
 	Whether to disable OOM Killer for the container or not.
 

+ 4 - 0
man/docker-run.1.md

@@ -54,6 +54,7 @@ docker-run - Run a command in a new container
 [**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
 [**--name**[=*NAME*]]
 [**--net**[=*"bridge"*]]
+[**--net-alias**[=*[]*]]
 [**--oom-kill-disable**]
 [**--oom-score-adj**[=*0*]]
 [**-P**|**--publish-all**]
@@ -383,6 +384,9 @@ and foreground Docker containers.
                                'host': use the Docker host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.
                                '<network-name>|<network-id>': connect to a user-defined network
 
+**--net-alias**=[]
+   Add network-scoped alias for the container
+
 **--oom-kill-disable**=*true*|*false*
    Whether to disable OOM Killer for the container or not.
 

+ 2 - 0
runconfig/errors.go

@@ -33,4 +33,6 @@ var (
 	ErrUnsupportedNetworkAndIP = fmt.Errorf("User specified IP address is supported on user defined networks only")
 	// ErrUnsupportedNetworkNoSubnetAndIP conflict between network with no configured subnet and preferred ip address
 	ErrUnsupportedNetworkNoSubnetAndIP = fmt.Errorf("User specified IP address is supported only when connecting to networks with user configured subnets")
+	// ErrUnsupportedNetworkAndAlias conflict between network mode and alias
+	ErrUnsupportedNetworkAndAlias = fmt.Errorf("Network-scoped alias is supported only for containers in user defined networks")
 )

+ 12 - 0
runconfig/opts/parse.go

@@ -33,6 +33,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
 		flDeviceReadBps     = NewThrottledeviceOpt(ValidateThrottleBpsDevice)
 		flDeviceWriteBps    = NewThrottledeviceOpt(ValidateThrottleBpsDevice)
 		flLinks             = opts.NewListOpts(ValidateLink)
+		flAliases           = opts.NewListOpts(nil)
 		flDeviceReadIOps    = NewThrottledeviceOpt(ValidateThrottleIOpsDevice)
 		flDeviceWriteIOps   = NewThrottledeviceOpt(ValidateThrottleIOpsDevice)
 		flEnv               = opts.NewListOpts(ValidateEnv)
@@ -103,6 +104,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
 	cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
 	cmd.Var(&flTmpfs, []string{"-tmpfs"}, "Mount a tmpfs directory")
 	cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
+	cmd.Var(&flAliases, []string{"-net-alias"}, "Add network-scoped alias for the container")
 	cmd.Var(&flDevices, []string{"-device"}, "Add a host device to the container")
 	cmd.Var(&flLabels, []string{"l", "-label"}, "Set meta data on a container")
 	cmd.Var(&flLabelsFile, []string{"-label-file"}, "Read in a line delimited file of labels")
@@ -440,6 +442,16 @@ func Parse(cmd *flag.FlagSet, args []string) (*container.Config, *container.Host
 		networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
 	}
 
+	if hostConfig.NetworkMode.IsUserDefined() && flAliases.Len() > 0 {
+		epConfig := networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)]
+		if epConfig == nil {
+			epConfig = &networktypes.EndpointSettings{}
+		}
+		epConfig.Aliases = make([]string, flAliases.Len())
+		copy(epConfig.Aliases, flAliases.GetAll())
+		networkingConfig.EndpointsConfig[string(hostConfig.NetworkMode)] = epConfig
+	}
+
 	return config, hostConfig, networkingConfig, cmd, nil
 }