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 <justin.cormack@docker.com>
This commit is contained in:
Justin Cormack 2017-07-27 14:52:13 +01:00
parent 36217e5145
commit e388c0ff14
2 changed files with 38 additions and 20 deletions

View File

@ -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)
}

View File

@ -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