Generate intermediate image into a temp file

All of the `output*` functions took a `[]byte` and immediately wrapped it in a
`bytes.Buffer` to produce an `io.Reader`. Make them take an `io.Reader` instead
and satisfy this further up the call chain by directing `moby.Build` to output
to a temp file instead of another `bytes.Buffer`.

In my test case (building kube master image) this reduces Maximum RSS (as
measured by time(1)) from 6.7G to 2.8G and overall allocations from 9.7G to
5.3G. When building a tar (output to /dev/null) the Maximum RSS fell slightly
from 2.2G to 2.1G. Overall allocations remained stable at around 5.3G.

Signed-off-by: Ian Campbell <ijc@docker.com>
This commit is contained in:
Ian Campbell
2017-12-06 14:53:18 +00:00
parent 9558740c11
commit 9f44acf8e3
3 changed files with 54 additions and 31 deletions

View File

@@ -185,14 +185,18 @@ func build(args []string) {
m.Trust = moby.TrustConfig{}
}
var buf *bytes.Buffer
var tf *os.File
var w io.Writer
if outputFile != nil {
w = outputFile
} else {
buf = new(bytes.Buffer)
w = buf
if tf, err = ioutil.TempFile("", ""); err != nil {
log.Fatalf("Error creating tempfile: %v", err)
}
defer os.Remove(tf.Name())
w = tf
}
// this is a weird interface, but currently only streamable types can have additional files
// need to split up the base tarball outputs from the secondary stages
var tp string
@@ -205,7 +209,11 @@ func build(args []string) {
}
if outputFile == nil {
image := buf.Bytes()
image := tf.Name()
if err := tf.Close(); err != nil {
log.Fatalf("Error closing tempfile: %v", err)
}
log.Infof("Create outputs:")
err = moby.Formats(filepath.Join(*buildDir, name), image, buildFormats, size)
if err != nil {