From 3045a80c851f0c1ade20f925f67520e47e90bb0a Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 6 Dec 2017 15:05:04 +0000 Subject: [PATCH] Stream `docker export` directly to consumer Rather than queueing up into a `bytes.Buffer`. In my test case (building kube master image) this reduces Maximum RSS (as measured by time(1)) compared with the previous patch from 2.8G to 110M. The tar output case goes from 2.1G to 110M also. Overall allocations are ~715M in both cases. Signed-off-by: Ian Campbell --- src/moby/docker.go | 16 ++++------------ src/moby/image.go | 5 +++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/moby/docker.go b/src/moby/docker.go index 640cf8119..296a61108 100644 --- a/src/moby/docker.go +++ b/src/moby/docker.go @@ -4,7 +4,6 @@ package moby // and also using the Docker API not shelling out import ( - "bytes" "errors" "fmt" "io" @@ -81,25 +80,18 @@ func dockerCreate(image string) (string, error) { return respBody.ID, nil } -func dockerExport(container string) ([]byte, error) { +func dockerExport(container string) (io.ReadCloser, error) { log.Debugf("docker export: %s", container) cli, err := dockerClient() if err != nil { - return []byte{}, errors.New("could not initialize Docker API client") + return nil, errors.New("could not initialize Docker API client") } responseBody, err := cli.ContainerExport(context.Background(), container) if err != nil { - return []byte{}, err - } - defer responseBody.Close() - - output := bytes.NewBuffer(nil) - _, err = io.Copy(output, responseBody) - if err != nil { - return []byte{}, err + return nil, err } - return output.Bytes(), nil + return responseBody, err } func dockerRm(container string) error { diff --git a/src/moby/image.go b/src/moby/image.go index 9f2a3504e..3b3426ebe 100644 --- a/src/moby/image.go +++ b/src/moby/image.go @@ -119,6 +119,8 @@ func ImageTar(ref *reference.Spec, prefix string, tw tarWriter, trust bool, pull if err != nil { return fmt.Errorf("Failed to docker export container from container %s: %v", container, err) } + defer contents.Close() + err = dockerRm(container) if err != nil { return fmt.Errorf("Failed to docker rm container %s: %v", container, err) @@ -126,8 +128,7 @@ func ImageTar(ref *reference.Spec, prefix string, tw tarWriter, trust bool, pull // now we need to filter out some files from the resulting tar archive - r := bytes.NewReader(contents) - tr := tar.NewReader(r) + tr := tar.NewReader(contents) for { hdr, err := tr.Next()