In the init section use a symlink for /etc/resolv.conf

Unfortunately there are a lot of issues with resolv.conf as we
cannot actually write it into the image from any docker image, as docker will
always have something bind mounted in.

In addition, normally we expect the filesystem to br read only for images
that moby generates, so the actual etc/resolv.conf is likely not to be writeable.

Previously we were adding in a default resolv.conf into every image pointing at
Google's name servers but that is really a bad idea.

Instead, normal images now get an empty default, while images in the `init`
section will get a symlink, currently hard coded to `/run/resolvconf/resolv.conf`
but you can override this with the `files` section to be static or a different
link.

In future, if we have an easy way to build and extract images with user control
of this, we can drop this.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
Justin Cormack 2017-07-25 14:40:40 +01:00
parent 2c4d567781
commit 6403215635
2 changed files with 40 additions and 19 deletions

View File

@ -40,6 +40,12 @@ RUN rm -f Dockerfile
ENTRYPOINT ["/sbin/tini", "--", "/bin/rc.init"]
`
// For now this is a constant that we use in init section only to make
// resolv.conf point at somewhere writeable. In future whe we are not using
// Docker to extract images we can read this directly from image, but now Docker
// will overwrite anything we put in the image.
const resolvconfSymlink = "/run/resolvconf/resolv.conf"
var additions = map[string]addFun{
"docker": func(tw *tar.Writer) error {
log.Infof(" Adding Dockerfile")
@ -146,7 +152,7 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error {
// get kernel and initrd tarball from container
log.Infof("Extract kernel image: %s", m.Kernel.Image)
kf := newKernelFilter(iw, m.Kernel.Cmdline, m.Kernel.Binary, m.Kernel.Tar)
err := ImageTar(m.Kernel.Image, "", kf, enforceContentTrust(m.Kernel.Image, &m.Trust), pull)
err := ImageTar(m.Kernel.Image, "", kf, enforceContentTrust(m.Kernel.Image, &m.Trust), pull, "")
if err != nil {
return fmt.Errorf("Failed to extract kernel image and tarball: %v", err)
}
@ -162,7 +168,7 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error {
}
for _, ii := range m.Init {
log.Infof("Process init image: %s", ii)
err := ImageTar(ii, "", iw, enforceContentTrust(ii, &m.Trust), pull)
err := ImageTar(ii, "", iw, enforceContentTrust(ii, &m.Trust), pull, resolvconfSymlink)
if err != nil {
return fmt.Errorf("Failed to build init tarball from %s: %v", ii, err)
}

View File

@ -22,6 +22,11 @@ type tarWriter interface {
// used the containerd libraries to do this instead locally direct from a local image
// cache as it would be much simpler.
// Unfortunately there are some files that Docker always makes appear in a running image and
// export shows them. In particular we have no way for a user to specify their own resolv.conf.
// Even if we were not using docker export to get the image, users of docker build cannot override
// the resolv.conf either, as it is not writeable and bind mounted in.
var exclude = map[string]bool{
".dockerenv": true,
"Dockerfile": true,
@ -39,10 +44,8 @@ ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
`,
"etc/resolv.conf": `nameserver 8.8.8.8
nameserver 8.8.4.4
nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844
"etc/resolv.conf": `
# no resolv.conf configured
`,
}
@ -75,7 +78,7 @@ func tarPrefix(path string, tw tarWriter) error {
}
// ImageTar takes a Docker image and outputs it to a tar stream
func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool) error {
func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv string) error {
log.Debugf("image tar: %s %s", image, prefix)
if prefix != "" && prefix[len(prefix)-1] != byte('/') {
return fmt.Errorf("prefix does not end with /: %s", prefix)
@ -137,6 +140,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool) error {
return err
}
} else if replace[hdr.Name] != "" {
if hdr.Name != "etc/resolv.conf" || resolv == "" {
contents := replace[hdr.Name]
hdr.Size = int64(len(contents))
hdr.Name = prefix + hdr.Name
@ -149,6 +153,17 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool) error {
if err != nil {
return err
}
} else {
// replace resolv.conf with specified symlink
hdr.Name = prefix + hdr.Name
hdr.Size = 0
hdr.Typeflag = tar.TypeSymlink
hdr.Linkname = resolv
log.Debugf("image tar: %s %s add resolv symlink /etc/resolv.conf -> %s", image, prefix, resolv)
if err := tw.WriteHeader(hdr); err != nil {
return err
}
}
_, err = io.Copy(ioutil.Discard, tr)
if err != nil {
return err
@ -171,7 +186,7 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool) error {
// ImageBundle produces an OCI bundle at the given path in a tarball, given an image and a config.json
func ImageBundle(path string, image string, config []byte, tw tarWriter, trust bool, pull bool) error {
log.Debugf("image bundle: %s %s cfg: %s", path, image, string(config))
err := ImageTar(image, path+"/rootfs/", tw, trust, pull)
err := ImageTar(image, path+"/rootfs/", tw, trust, pull, "")
if err != nil {
return err
}