소스 검색

Do not update etc/hosts for every container

- Only user named containers will be published into
  other containers' etc/hosts file.
- Also block linking to containers which are not
  connected to the default network

Signed-off-by: Alessandro Boch <aboch@docker.com>
Alessandro Boch 9 년 전
부모
커밋
4f6f00e191
4개의 변경된 파일102개의 추가작업 그리고 6개의 파일을 삭제
  1. 14 1
      daemon/container_unix.go
  2. 4 3
      daemon/daemon.go
  3. 1 0
      daemon/network/settings.go
  4. 83 2
      integration-cli/docker_cli_network_unix_test.go

+ 14 - 1
daemon/container_unix.go

@@ -532,6 +532,9 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
 	}
 
 	for linkAlias, child := range children {
+		if !isLinkable(child) {
+			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
+		}
 		_, alias := path.Split(linkAlias)
 		// allow access to the linked container via the alias, real name, and container hostname
 		aliasList := alias + " " + child.Config.Hostname
@@ -578,6 +581,16 @@ func (container *Container) buildSandboxOptions(n libnetwork.Network) ([]libnetw
 	return sboxOptions, nil
 }
 
+func isLinkable(child *Container) bool {
+	// A container is linkable only if it belongs to the default network
+	for _, nw := range child.NetworkSettings.Networks {
+		if nw == "bridge" {
+			return true
+		}
+	}
+	return false
+}
+
 func (container *Container) getEndpointInNetwork(n libnetwork.Network) (libnetwork.Endpoint, error) {
 	endpointName := strings.TrimPrefix(container.Name, "/")
 	return n.EndpointByName(endpointName)
@@ -862,7 +875,7 @@ func (container *Container) buildCreateEndpointOptions(n libnetwork.Network) ([]
 		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
 	}
 
-	if n.Name() == "bridge" {
+	if n.Name() == "bridge" || container.NetworkSettings.IsAnonymousEndpoint {
 		createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
 	}
 

+ 4 - 3
daemon/daemon.go

@@ -477,8 +477,9 @@ func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint *stringutils.StrSlic
 
 func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID string) (*Container, error) {
 	var (
-		id  string
-		err error
+		id             string
+		err            error
+		noExplicitName = name == ""
 	)
 	id, name, err = daemon.generateIDAndName(name)
 	if err != nil {
@@ -495,7 +496,7 @@ func (daemon *Daemon) newContainer(name string, config *runconfig.Config, imgID
 	base.Config = config
 	base.hostConfig = &runconfig.HostConfig{}
 	base.ImageID = imgID
-	base.NetworkSettings = &network.Settings{}
+	base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
 	base.Name = name
 	base.Driver = daemon.driver.String()
 	base.ExecDriver = daemon.execDriver.Name()

+ 1 - 0
daemon/network/settings.go

@@ -43,4 +43,5 @@ type Settings struct {
 	SandboxKey             string
 	SecondaryIPAddresses   []Address
 	SecondaryIPv6Addresses []Address
+	IsAnonymousEndpoint    bool
 }

+ 83 - 2
integration-cli/docker_cli_network_unix_test.go

@@ -431,11 +431,11 @@ func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *
 	hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
 	c.Assert(err, checker.IsNil)
 
-	out, err = s.d.Cmd("run", "-d", "busybox", "top")
+	out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
 	c.Assert(err, check.IsNil)
 	cid2 := strings.TrimSpace(out)
 
-	// verify first container's etc/hosts file has not changed after spawning second container
+	// verify first container's etc/hosts file has not changed after spawning the second named container
 	hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
 	c.Assert(err, checker.IsNil)
 	c.Assert(string(hosts), checker.Equals, string(hostsPost),
@@ -485,3 +485,84 @@ func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *
 	c.Assert(string(hosts), checker.Equals, string(hostsPost),
 		check.Commentf("Unexpected %s content after disconnecting from second network", hostsFile))
 }
+
+func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) {
+	hostsFile := "/etc/hosts"
+	cstmBridgeNw := "custom-bridge-nw"
+
+	dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
+	assertNwIsAvailable(c, cstmBridgeNw)
+
+	// run two anonymous containers and store their etc/hosts content
+	out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
+	cid1 := strings.TrimSpace(out)
+
+	hosts1, err := readContainerFileWithExec(cid1, hostsFile)
+	c.Assert(err, checker.IsNil)
+
+	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
+	cid2 := strings.TrimSpace(out)
+
+	hosts2, err := readContainerFileWithExec(cid2, hostsFile)
+	c.Assert(err, checker.IsNil)
+
+	// verify first container etc/hosts file has not changed
+	hosts1post, err := readContainerFileWithExec(cid1, hostsFile)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
+		check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
+
+	// start a named container
+	cName := "AnyName"
+	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top")
+	cid3 := strings.TrimSpace(out)
+
+	// verify etc/hosts file for first two containers contains the named container entry
+	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(hosts1post), checker.Contains, cName,
+		check.Commentf("Container 1  %s file does not contain entries for named container %q: %s", hostsFile, cName, string(hosts1post)))
+
+	hosts2post, err := readContainerFileWithExec(cid2, hostsFile)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(hosts2post), checker.Contains, cName,
+		check.Commentf("Container 2  %s file does not contain entries for named container %q: %s", hostsFile, cName, string(hosts2post)))
+
+	// Stop named container and verify first two containers' etc/hosts entries are back to original
+	dockerCmd(c, "stop", cid3)
+	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
+		check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
+
+	hosts2post, err = readContainerFileWithExec(cid2, hostsFile)
+	c.Assert(err, checker.IsNil)
+	c.Assert(string(hosts2), checker.Equals, string(hosts2post),
+		check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
+}
+
+func (s *DockerNetworkSuite) TestDockerNetworkLinkOndefaultNetworkOnly(c *check.C) {
+	// Link feature must work only on default network, and not across networks
+	cnt1 := "container1"
+	cnt2 := "container2"
+	network := "anotherbridge"
+
+	// Run first container on default network
+	dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
+
+	// Create another network and run the second container on it
+	dockerCmd(c, "network", "create", network)
+	assertNwIsAvailable(c, network)
+	dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
+
+	// Try launching a container on default network, linking to the first container. Must succeed
+	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
+
+	// Try launching a container on default network, linking to the second container. Must fail
+	_, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
+	c.Assert(err, checker.NotNil)
+
+	// Connect second container to default network. Now a container on default network can link to it
+	dockerCmd(c, "network", "connect", "bridge", cnt2)
+	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
+}