From 6b98aff58ba43d5c668a335d54e8b3fcbda85d82 Mon Sep 17 00:00:00 2001 From: Justin Cormack Date: Tue, 22 Aug 2017 16:21:56 +0100 Subject: [PATCH] Use the runtime config to specify how overlay should be created This puts the build side in charge of the runtime layout, which enables additional optimisations later, like sharing the rootfs if it is used multiple times. Signed-off-by: Justin Cormack --- src/moby/build.go | 6 +----- src/moby/image.go | 54 +++++++++++++++++++++++++++++------------------ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/moby/build.go b/src/moby/build.go index f98d01e75..9ce628bd3 100644 --- a/src/moby/build.go +++ b/src/moby/build.go @@ -131,13 +131,9 @@ func outputImage(image Image, section string, prefix string, m Moby, idMap map[s if err != nil { return fmt.Errorf("Failed to create config for %s: %v", image.Image, err) } - runtimeConfig, err := json.MarshalIndent(runtime, "", " ") - if err != nil { - return fmt.Errorf("Failed to create runtime config for %s: %v", image.Image, err) - } path := path.Join("containers", section, prefix+image.Name) readonly := oci.Root.Readonly - err = ImageBundle(path, image.Image, config, runtimeConfig, iw, useTrust, pull, readonly) + err = ImageBundle(path, image.Image, config, runtime, 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 ce5706c8e..4d7fb3e8c 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -3,6 +3,7 @@ package moby import ( "archive/tar" "bytes" + "encoding/json" "fmt" "io" "io/ioutil" @@ -10,6 +11,7 @@ import ( "strings" log "github.com/Sirupsen/logrus" + "github.com/opencontainers/runtime-spec/specs-go" ) type tarWriter interface { @@ -189,9 +191,7 @@ 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(prefix string, image string, config []byte, runtimeConfig []byte, tw tarWriter, trust bool, pull bool, readonly bool) error { - log.Debugf("image bundle: %s %s cfg: %s runtime: %s", prefix, image, string(config), string(runtimeConfig)) - +func ImageBundle(prefix string, image string, config []byte, runtime Runtime, tw tarWriter, trust bool, pull bool, readonly bool) error { // if read only, just unpack in rootfs/ but otherwise set up for overlay rootfs := "rootfs" if !readonly { @@ -214,26 +214,11 @@ func ImageBundle(prefix string, image string, config []byte, runtimeConfig []byt return err } - // do not write an empty runtime config - if string(runtimeConfig) != "{}" { - hdr = &tar.Header{ - Name: path.Join(prefix, "runtime.json"), - Mode: 0644, - Size: int64(len(runtimeConfig)), - } - if err := tw.WriteHeader(hdr); err != nil { - return err - } - buf = bytes.NewBuffer(runtimeConfig) - if _, err := io.Copy(tw, buf); err != nil { - return err - } - } - if !readonly { // add a tmp directory to be used as a mount point for tmpfs for upper, work + tmp := path.Join(prefix, "tmp") hdr = &tar.Header{ - Name: path.Join(prefix, "tmp"), + Name: tmp, Mode: 0755, Typeflag: tar.TypeDir, } @@ -249,7 +234,36 @@ func ImageBundle(prefix string, image string, config []byte, runtimeConfig []byt if err := tw.WriteHeader(hdr); err != nil { return err } + runtime.Mounts = append(runtime.Mounts, specs.Mount{Source: "tmpfs", Type: "tmpfs", Destination: "/" + tmp}) + // remount private as nothing else should see the temporary layers + runtime.Mounts = append(runtime.Mounts, specs.Mount{Destination: "/" + tmp, Options: []string{"remount", "private"}}) + overlayOptions := []string{"lowerdir=/" + path.Join(prefix, "lower"), "upperdir=/" + path.Join(tmp, "upper"), "workdir=/" + path.Join(tmp, "work")} + runtime.Mounts = append(runtime.Mounts, specs.Mount{Source: "overlay", Type: "overlay", Destination: "/" + path.Join(prefix, "rootfs"), Options: overlayOptions}) + } else { + // make rootfs a mountpoint as runc can be picky about this + runtime.Mounts = append(runtime.Mounts, specs.Mount{Source: path.Join(prefix, rootfs), Destination: "/" + path.Join(prefix, "rootfs"), Options: []string{"bind"}}) } + // write the runtime config + runtimeConfig, err := json.MarshalIndent(runtime, "", " ") + if err != nil { + return fmt.Errorf("Failed to create runtime config for %s: %v", image, err) + } + + hdr = &tar.Header{ + Name: path.Join(prefix, "runtime.json"), + Mode: 0644, + Size: int64(len(runtimeConfig)), + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } + buf = bytes.NewBuffer(runtimeConfig) + if _, err := io.Copy(tw, buf); err != nil { + return err + } + + log.Debugf("image bundle: %s %s cfg: %s runtime: %s", prefix, image, string(config), string(runtimeConfig)) + return nil }