Docker-DCO-1.1-Signed-off-by: Bryan Murphy <bmurphy1976@gmail.com> (github: bmurphy1976)
Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)
Tested-by: Solomon Hykes <solomon@docker.com> (github: shykes)
| ... | ... |
@@ -357,7 +357,20 @@ func (container *Container) buildHostnameAndHostsFiles(IP string) error {
|
| 357 | 357 |
} |
| 358 | 358 |
|
| 359 | 359 |
container.HostsPath = path.Join(container.root, "hosts") |
| 360 |
- return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname) |
|
| 360 |
+ |
|
| 361 |
+ extraContent := make(map[string]string) |
|
| 362 |
+ |
|
| 363 |
+ children, err := container.daemon.Children(container.Name) |
|
| 364 |
+ if err != nil {
|
|
| 365 |
+ return err |
|
| 366 |
+ } |
|
| 367 |
+ |
|
| 368 |
+ for linkAlias, child := range children {
|
|
| 369 |
+ _, alias := path.Split(linkAlias) |
|
| 370 |
+ extraContent[alias] = child.NetworkSettings.IPAddress |
|
| 371 |
+ } |
|
| 372 |
+ |
|
| 373 |
+ return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, &extraContent) |
|
| 361 | 374 |
} |
| 362 | 375 |
|
| 363 | 376 |
func (container *Container) allocateNetwork() error {
|
| ... | ... |
@@ -1,4 +1,4 @@ |
| 1 |
-page_title: Docker Run Reference |
|
| 1 |
+page_title: Docker Run Reference |
|
| 2 | 2 |
page_description: Configure containers at runtime |
| 3 | 3 |
page_keywords: docker, run, configure, runtime |
| 4 | 4 |
|
| ... | ... |
@@ -407,6 +407,13 @@ And we can use that information to connect from another container as a client: |
| 407 | 407 |
$ docker run -i -t --rm --link redis-name:redis_alias --entrypoint /bin/bash dockerfiles/redis -c '/redis-stable/src/redis-cli -h $REDIS_ALIAS_PORT_6379_TCP_ADDR -p $REDIS_ALIAS_PORT_6379_TCP_PORT' |
| 408 | 408 |
172.17.0.32:6379> |
| 409 | 409 |
|
| 410 |
+Docker will also map the private IP address to the alias of a linked |
|
| 411 |
+container by inserting an entry into `/etc/hosts`. You can use this |
|
| 412 |
+mechanism to communicate with a linked container by its alias: |
|
| 413 |
+ |
|
| 414 |
+ $ docker run -d --name servicename busybox sleep 30 |
|
| 415 |
+ $ docker run -i -t --link servicename:servicealias busybox ping -c 1 servicealias |
|
| 416 |
+ |
|
| 410 | 417 |
## VOLUME (Shared Filesystems) |
| 411 | 418 |
|
| 412 | 419 |
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. |
| ... | ... |
@@ -109,3 +109,32 @@ the Redis container. |
| 109 | 109 |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES |
| 110 | 110 |
4c01db0b339c ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp |
| 111 | 111 |
d7886598dbe2 crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db |
| 112 |
+ |
|
| 113 |
+## Resolving Links by Name |
|
| 114 |
+ |
|
| 115 |
+New in version v0.11. |
|
| 116 |
+ |
|
| 117 |
+Linked containers can be accessed by hostname. Hostnames are mapped by |
|
| 118 |
+appending entries to '/etc/hosts' using the linked container's alias. |
|
| 119 |
+ |
|
| 120 |
+For example, linking a container using '--link redis:db' will generate the |
|
| 121 |
+following '/etc/hosts' file: |
|
| 122 |
+ |
|
| 123 |
+ root@6541a75d44a0:/# cat /etc/hosts |
|
| 124 |
+ 172.17.0.3 6541a75d44a0 |
|
| 125 |
+ 172.17.0.2 db |
|
| 126 |
+ |
|
| 127 |
+ 127.0.0.1 localhost |
|
| 128 |
+ ::1 localhost ip6-localhost ip6-loopback |
|
| 129 |
+ fe00::0 ip6-localnet |
|
| 130 |
+ ff00::0 ip6-mcastprefix |
|
| 131 |
+ ff02::1 ip6-allnodes |
|
| 132 |
+ ff02::2 ip6-allrouters |
|
| 133 |
+ root@6541a75d44a0:/# |
|
| 134 |
+ |
|
| 135 |
+Using this mechanism, you can communicate with the linked container by |
|
| 136 |
+name: |
|
| 137 |
+ |
|
| 138 |
+ root@6541a75d44a0:/# echo PING | redis-cli -h db |
|
| 139 |
+ PONG |
|
| 140 |
+ root@6541a75d44a0:/# |
| 112 | 141 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,45 @@ |
| 0 |
+package main |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ "os/exec" |
|
| 5 |
+ "testing" |
|
| 6 |
+) |
|
| 7 |
+ |
|
| 8 |
+func TestPingUnlinkedContainers(t *testing.T) {
|
|
| 9 |
+ runCmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1") |
|
| 10 |
+ exitCode, err := runCommand(runCmd) |
|
| 11 |
+ |
|
| 12 |
+ if exitCode == 0 {
|
|
| 13 |
+ t.Fatal("run ping did not fail")
|
|
| 14 |
+ } else if exitCode != 1 {
|
|
| 15 |
+ errorOut(err, t, fmt.Sprintf("run ping failed with errors: %v", err))
|
|
| 16 |
+ } |
|
| 17 |
+} |
|
| 18 |
+ |
|
| 19 |
+func TestPingLinkedContainers(t *testing.T) {
|
|
| 20 |
+ cmd := exec.Command(dockerBinary, "run", "-d", "--name", "container1", "busybox", "sleep", "10") |
|
| 21 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 22 |
+ errorOut(err, t, fmt.Sprintf("run container1 failed with errors: %v", err))
|
|
| 23 |
+ idA := stripTrailingCharacters(out) |
|
| 24 |
+ |
|
| 25 |
+ cmd = exec.Command(dockerBinary, "run", "-d", "--name", "container2", "busybox", "sleep", "10") |
|
| 26 |
+ out, _, err = runCommandWithOutput(cmd) |
|
| 27 |
+ errorOut(err, t, fmt.Sprintf("run container2 failed with errors: %v", err))
|
|
| 28 |
+ idB := stripTrailingCharacters(out) |
|
| 29 |
+ |
|
| 30 |
+ cmd = exec.Command(dockerBinary, "run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1") |
|
| 31 |
+ out, _, err = runCommandWithOutput(cmd) |
|
| 32 |
+ fmt.Printf("OUT: %s", out)
|
|
| 33 |
+ errorOut(err, t, fmt.Sprintf("run ping failed with errors: %v", err))
|
|
| 34 |
+ |
|
| 35 |
+ cmd = exec.Command(dockerBinary, "kill", idA) |
|
| 36 |
+ _, err = runCommand(cmd) |
|
| 37 |
+ errorOut(err, t, fmt.Sprintf("failed to kill container1: %v", err))
|
|
| 38 |
+ |
|
| 39 |
+ cmd = exec.Command(dockerBinary, "kill", idB) |
|
| 40 |
+ _, err = runCommand(cmd) |
|
| 41 |
+ errorOut(err, t, fmt.Sprintf("failed to kill container2: %v", err))
|
|
| 42 |
+ |
|
| 43 |
+ deleteAllContainers() |
|
| 44 |
+} |
| ... | ... |
@@ -15,7 +15,7 @@ var defaultContent = map[string]string{
|
| 15 | 15 |
"ip6-allrouters": "ff02::2", |
| 16 | 16 |
} |
| 17 | 17 |
|
| 18 |
-func Build(path, IP, hostname, domainname string) error {
|
|
| 18 |
+func Build(path, IP, hostname, domainname string, extraContent *map[string]string) error {
|
|
| 19 | 19 |
content := bytes.NewBuffer(nil) |
| 20 | 20 |
if IP != "" {
|
| 21 | 21 |
if domainname != "" {
|
| ... | ... |
@@ -30,5 +30,14 @@ func Build(path, IP, hostname, domainname string) error {
|
| 30 | 30 |
return err |
| 31 | 31 |
} |
| 32 | 32 |
} |
| 33 |
+ |
|
| 34 |
+ if extraContent != nil {
|
|
| 35 |
+ for hosts, ip := range *extraContent {
|
|
| 36 |
+ if _, err := content.WriteString(fmt.Sprintf("%s\t%s\n", ip, hosts)); err != nil {
|
|
| 37 |
+ return err |
|
| 38 |
+ } |
|
| 39 |
+ } |
|
| 40 |
+ } |
|
| 41 |
+ |
|
| 33 | 42 |
return ioutil.WriteFile(path, content.Bytes(), 0644) |
| 34 | 43 |
} |