From e388c0ff145483af6d3e49d989988b98f897f552 Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Thu, 27 Jul 2017 14:52:13 +0100 Subject: [PATCH] Rework setup of container for read only/read write To work with truly immutable filesystems, rather than ones we sneakily remount `rw`, we are going to use overlay for writeable containers. To leave the final mount as `rootfs`, in the writeable case we make a new `lower` path for the read only filesystem, and leave `rootfs` as a mount point for an overlay, with the writable layer and workdir mounted as a tmpfs on `tmp`. See https://github.com/linuxkit/linuxkit/issues/2288 Signed-off-by: Justin Cormack --- src/moby/build.go | 9 ++++++--- src/moby/image.go | 49 +++++++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/moby/build.go b/src/moby/build.go index d71d9ad4e..aae38f308 100644 --- a/src/moby/build.go +++ b/src/moby/build.go @@ -186,7 +186,8 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { } so := fmt.Sprintf("%03d", i) path := "containers/onboot/" + so + "-" + image.Name - err = ImageBundle(path, image.Image, config, iw, useTrust, pull) + readonly := image.Readonly != nil && *image.Readonly + err = ImageBundle(path, image.Image, config, iw, useTrust, pull, readonly) if err != nil { return fmt.Errorf("Failed to extract root filesystem for %s: %v", image.Image, err) } @@ -204,7 +205,8 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { } so := fmt.Sprintf("%03d", i) path := "containers/onshutdown/" + so + "-" + image.Name - err = ImageBundle(path, image.Image, config, iw, useTrust, pull) + readonly := image.Readonly != nil && *image.Readonly + err = ImageBundle(path, image.Image, config, iw, useTrust, pull, readonly) if err != nil { return fmt.Errorf("Failed to extract root filesystem for %s: %v", image.Image, err) } @@ -221,7 +223,8 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { return fmt.Errorf("Failed to create config.json for %s: %v", image.Image, err) } path := "containers/services/" + image.Name - err = ImageBundle(path, image.Image, config, iw, useTrust, pull) + readonly := image.Readonly != nil && *image.Readonly + err = ImageBundle(path, image.Image, config, iw, useTrust, pull, readonly) if err != nil { return fmt.Errorf("Failed to extract root filesystem for %s: %v", image.Image, err) } diff --git a/src/moby/image.go b/src/moby/image.go index 98d841c31..6a5854962 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/ioutil" + "path/filepath" "strings" log "github.com/Sirupsen/logrus" @@ -184,35 +185,49 @@ func ImageTar(image, prefix string, tw tarWriter, trust bool, pull bool, resolv } // 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 { +func ImageBundle(path string, image string, config []byte, tw tarWriter, trust bool, pull bool, readonly bool) error { log.Debugf("image bundle: %s %s cfg: %s", path, image, string(config)) - err := ImageTar(image, path+"/rootfs/", tw, trust, pull, "") - if err != nil { + + // if read only, just unpack in rootfs/ but otherwise set up for overlay + rootfs := "rootfs" + if !readonly { + rootfs = "lower" + } + + if err := ImageTar(image, filepath.Join(path, rootfs)+"/", tw, trust, pull, ""); err != nil { return err } hdr := &tar.Header{ - Name: path + "/" + "config.json", + Name: filepath.Join(path, "config.json"), Mode: 0644, Size: int64(len(config)), } - err = tw.WriteHeader(hdr) - if err != nil { + if err := tw.WriteHeader(hdr); err != nil { return err } buf := bytes.NewBuffer(config) - _, err = io.Copy(tw, buf) - if err != nil { + if _, err := io.Copy(tw, buf); err != nil { return err } - // add a tmp directory to be used as a mount point if needed - hdr = &tar.Header{ - Name: path + "/" + "tmp", - Mode: 0755, - Typeflag: tar.TypeDir, - } - err = tw.WriteHeader(hdr) - if err != nil { - return err + if !readonly { + // add a tmp directory to be used as a mount point for tmpfs for upper, work + hdr = &tar.Header{ + Name: filepath.Join(path, "tmp"), + Mode: 0755, + Typeflag: tar.TypeDir, + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } + // add rootfs as merged mount point + hdr = &tar.Header{ + Name: filepath.Join(path, "rootfs"), + Mode: 0755, + Typeflag: tar.TypeDir, + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } } return nil