1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Update /etc/hosts when linked container is restarted

Docker-DCO-1.1-Signed-off-by: Victor Vieux <vieux@docker.com> (github: vieux)
This commit is contained in:
Victor Vieux 2014-07-14 23:19:37 +00:00 committed by Erik Hollensbe
parent 345e3811fe
commit 450740c891
8 changed files with 149 additions and 5 deletions

View file

@ -297,6 +297,9 @@ func (container *Container) Start() (err error) {
if err := container.initializeNetworking(); err != nil { if err := container.initializeNetworking(); err != nil {
return err return err
} }
if err := container.updateParentsHosts(); err != nil {
return err
}
container.verifyDaemonSettings() container.verifyDaemonSettings()
if err := prepareVolumesForContainer(container); err != nil { if err := prepareVolumesForContainer(container); err != nil {
return err return err
@ -390,10 +393,7 @@ func (container *Container) buildHostnameFile() error {
return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644) return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
} }
func (container *Container) buildHostnameAndHostsFiles(IP string) error { func (container *Container) buildHostsFiles(IP string) error {
if err := container.buildHostnameFile(); err != nil {
return err
}
hostsPath, err := container.getRootResourcePath("hosts") hostsPath, err := container.getRootResourcePath("hosts")
if err != nil { if err != nil {
@ -416,6 +416,14 @@ func (container *Container) buildHostnameAndHostsFiles(IP string) error {
return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, &extraContent) return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname, &extraContent)
} }
func (container *Container) buildHostnameAndHostsFiles(IP string) error {
if err := container.buildHostnameFile(); err != nil {
return err
}
return container.buildHostsFiles(IP)
}
func (container *Container) allocateNetwork() error { func (container *Container) allocateNetwork() error {
mode := container.hostConfig.NetworkMode mode := container.hostConfig.NetworkMode
if container.Config.NetworkDisabled || mode.IsContainer() || mode.IsHost() { if container.Config.NetworkDisabled || mode.IsContainer() || mode.IsHost() {
@ -878,6 +886,26 @@ func (container *Container) setupContainerDns() error {
return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644) return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644)
} }
func (container *Container) updateParentsHosts() error {
parents, err := container.daemon.Parents(container.Name)
if err != nil {
return err
}
for _, cid := range parents {
if cid == "0" {
continue
}
c := container.daemon.Get(cid)
if c != nil && !container.daemon.config.DisableNetwork && !container.hostConfig.NetworkMode.IsContainer() && !container.hostConfig.NetworkMode.IsHost() {
if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, container.Name[1:]); err != nil {
return fmt.Errorf("Failed to update /etc/hosts in parent container: %v", err)
}
}
}
return nil
}
func (container *Container) initializeNetworking() error { func (container *Container) initializeNetworking() error {
var err error var err error
if container.hostConfig.NetworkMode.IsHost() { if container.hostConfig.NetworkMode.IsHost() {

View file

@ -621,6 +621,15 @@ func (daemon *Daemon) Children(name string) (map[string]*Container, error) {
return children, nil return children, nil
} }
func (daemon *Daemon) Parents(name string) ([]string, error) {
name, err := GetFullContainerName(name)
if err != nil {
return nil, err
}
return daemon.containerGraph.Parents(name)
}
func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error { func (daemon *Daemon) RegisterLink(parent, child *Container, alias string) error {
fullName := path.Join(parent.Name, alias) fullName := path.Join(parent.Name, alias)
if !daemon.containerGraph.Exists(fullName) { if !daemon.containerGraph.Exists(fullName) {

View file

@ -150,7 +150,10 @@ Four different options affect container domain name services.
`CONTAINER_NAME`. This lets processes inside the new container `CONTAINER_NAME`. This lets processes inside the new container
connect to the hostname `ALIAS` without having to know its IP. The connect to the hostname `ALIAS` without having to know its IP. The
`--link=` option is discussed in more detail below, in the section `--link=` option is discussed in more detail below, in the section
[Communication between containers](#between-containers). [Communication between containers](#between-containers). Docker updates
the ALIAS entry in the /etc/hosts file of the recipient containers
in order to keep the link since Docker may assign a different IP
address to the linked containers on restart.
* `--dns=IP_ADDRESS...` — sets the IP addresses added as `server` * `--dns=IP_ADDRESS...` — sets the IP addresses added as `server`
lines to the container's `/etc/resolv.conf` file. Processes in the lines to the container's `/etc/resolv.conf` file. Processes in the

View file

@ -432,6 +432,9 @@ mechanism to communicate with a linked container by its alias:
$ docker run -d --name servicename busybox sleep 30 $ docker run -d --name servicename busybox sleep 30
$ docker run -i -t --link servicename:servicealias busybox ping -c 1 servicealias $ docker run -i -t --link servicename:servicealias busybox ping -c 1 servicealias
If you restart the source container (`servicename` in this case), the recipient
container's `/etc/hosts` entry will be automatically updated.
## VOLUME (Shared Filesystems) ## VOLUME (Shared Filesystems)
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. -v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro].

View file

@ -241,6 +241,16 @@ to make use of your `db` container.
> example, you could have multiple (differently named) web containers attached to your > example, you could have multiple (differently named) web containers attached to your
>`db` container. >`db` container.
If you restart the source container, the linked containers `/etc/hosts` files
will be automatically updated with the source container's new IP address,
allowing linked communication to continue.
$ sudo docker restart db
root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7 aed84ee21bde
. . .
172.17.0.9 db
# Next step # Next step
Now that you know how to link Docker containers together, the next step is Now that you know how to link Docker containers together, the next step is

View file

@ -1706,3 +1706,50 @@ func TestBindMounts(t *testing.T) {
t.Fatalf("Output should be %q, actual out: %q", expected, content) t.Fatalf("Output should be %q, actual out: %q", expected, content)
} }
} }
func TestHostsLinkedContainerUpdate(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-integration")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sleep", "5"))
if err != nil {
t.Fatal(err, out)
}
// TODO fix docker cp and /etc/hosts
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--link", "c1:c1", "--name", "c2", "busybox", "sh", "-c", "while true;do cp /etc/hosts /hosts; done"))
if err != nil {
t.Fatal(err, out)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "cp", "c2:/hosts", tmpdir+"/1"))
if err != nil {
t.Fatal(err, out)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "restart", "-t", "0", "c1"))
if err != nil {
t.Fatal(err, out)
}
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "cp", "c2:/hosts", tmpdir+"/2"))
if err != nil {
t.Fatal(err, out)
}
out, _, _, err = runCommandWithStdoutStderr(exec.Command("diff", tmpdir+"/1", tmpdir+"/2"))
if err == nil {
t.Fatalf("Expecting error, got none")
}
out = stripTrailingCharacters(out)
if out == "" {
t.Fatalf("expected /etc/hosts to be updated, but wasn't")
}
deleteAllContainers()
logDone("run - /etc/hosts updated in parent when restart")
}

View file

@ -281,6 +281,18 @@ func (db *Database) Children(name string, depth int) ([]WalkMeta, error) {
return db.children(e, name, depth, nil) return db.children(e, name, depth, nil)
} }
// Return the parents of a specified entity
func (db *Database) Parents(name string) ([]string, error) {
db.mux.RLock()
defer db.mux.RUnlock()
e, err := db.get(name)
if err != nil {
return nil, err
}
return db.parents(e)
}
// Return the refrence count for a specified id // Return the refrence count for a specified id
func (db *Database) Refs(id string) int { func (db *Database) Refs(id string) int {
db.mux.RLock() db.mux.RLock()
@ -466,6 +478,28 @@ func (db *Database) children(e *Entity, name string, depth int, entities []WalkM
return entities, nil return entities, nil
} }
func (db *Database) parents(e *Entity) (parents []string, err error) {
if e == nil {
return parents, nil
}
rows, err := db.conn.Query("SELECT parent_id FROM edge where entity_id = ?;", e.id)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var parentId string
if err := rows.Scan(&parentId); err != nil {
return nil, err
}
parents = append(parents, parentId)
}
return parents, nil
}
// Return the entity based on the parent path and name // Return the entity based on the parent path and name
func (db *Database) child(parent *Entity, name string) *Entity { func (db *Database) child(parent *Entity, name string) *Entity {
var id string var id string

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"regexp"
) )
var defaultContent = map[string]string{ var defaultContent = map[string]string{
@ -41,3 +42,12 @@ func Build(path, IP, hostname, domainname string, extraContent *map[string]strin
return ioutil.WriteFile(path, content.Bytes(), 0644) return ioutil.WriteFile(path, content.Bytes(), 0644)
} }
func Update(path, IP, hostname string) error {
old, err := ioutil.ReadFile(path)
if err != nil {
return err
}
var re = regexp.MustCompile(fmt.Sprintf("(\\S*)(\\t%s)", regexp.QuoteMeta(hostname)))
return ioutil.WriteFile(path, re.ReplaceAll(old, []byte(IP+"$2")), 0644)
}