diff --git a/src/cmd/linuxkit/cache/source.go b/src/cmd/linuxkit/cache/source.go index 9f5fca0f7..e75af50b0 100644 --- a/src/cmd/linuxkit/cache/source.go +++ b/src/cmd/linuxkit/cache/source.go @@ -6,8 +6,10 @@ import ( "io" "github.com/containerd/containerd/reference" + "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/tarball" lktspec "github.com/linuxkit/linuxkit/src/cmd/linuxkit/spec" imagespec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -70,6 +72,28 @@ func (c ImageSource) TarReader() (io.ReadCloser, error) { return mutate.Extract(image), nil } +// V1TarReader return an io.ReadCloser to read the image as a v1 tarball +func (c ImageSource) V1TarReader() (io.ReadCloser, error) { + imageName := c.ref.String() + + refName, err := name.ParseReference(imageName) + if err != nil { + return nil, fmt.Errorf("error parsing image name: %v", err) + } + // get a reference to the image + image, err := c.provider.findImage(imageName, c.architecture) + if err != nil { + return nil, err + } + // convert the writer to a reader + r, w := io.Pipe() + go func() { + defer w.Close() + tarball.Write(refName, image, w) + }() + return r, nil +} + // Descriptor return the descriptor of the image. func (c ImageSource) Descriptor() *v1.Descriptor { return c.descriptor diff --git a/src/cmd/linuxkit/docker/cmd.go b/src/cmd/linuxkit/docker/cmd.go index ce42fa05a..48c6a5622 100644 --- a/src/cmd/linuxkit/docker/cmd.go +++ b/src/cmd/linuxkit/docker/cmd.go @@ -88,6 +88,16 @@ func Export(container string) (io.ReadCloser, error) { return responseBody, err } +// Save save the provided image ref. +func Save(image string) (io.ReadCloser, error) { + log.Debugf("docker save: %s", image) + cli, err := Client() + if err != nil { + return nil, errors.New("could not initialize Docker API client") + } + return cli.ImageSave(context.Background(), []string{image}) +} + // Rm remove the given container from docker. func Rm(container string) error { log.Debugf("docker rm: %s", container) diff --git a/src/cmd/linuxkit/docker/source.go b/src/cmd/linuxkit/docker/source.go index f79f84933..a2194536d 100644 --- a/src/cmd/linuxkit/docker/source.go +++ b/src/cmd/linuxkit/docker/source.go @@ -77,6 +77,11 @@ func (d ImageSource) TarReader() (io.ReadCloser, error) { }, nil } +// V1TarReader return an io.ReadCloser to read the save of the image +func (d ImageSource) V1TarReader() (io.ReadCloser, error) { + return Save(d.ref.String()) +} + // Descriptor return the descriptor of the image. func (d ImageSource) Descriptor() *v1.Descriptor { return nil diff --git a/src/cmd/linuxkit/pkglib/build.go b/src/cmd/linuxkit/pkglib/build.go index 636245044..a4bd78b75 100644 --- a/src/cmd/linuxkit/pkglib/build.go +++ b/src/cmd/linuxkit/pkglib/build.go @@ -289,7 +289,7 @@ func (p Pkg) Build(bos ...BuildOpt) error { // if requested docker, load the image up if bo.targetDocker { cacheSource := c.NewSource(&ref, arch, desc) - reader, err := cacheSource.TarReader() + reader, err := cacheSource.V1TarReader() if err != nil { return fmt.Errorf("unable to get reader from cache: %v", err) } diff --git a/src/cmd/linuxkit/pkglib/build_test.go b/src/cmd/linuxkit/pkglib/build_test.go index bd35f5129..8fa6c8776 100644 --- a/src/cmd/linuxkit/pkglib/build_test.go +++ b/src/cmd/linuxkit/pkglib/build_test.go @@ -270,6 +270,9 @@ func (c cacheMockerSource) Config() (imagespec.ImageConfig, error) { func (c cacheMockerSource) TarReader() (io.ReadCloser, error) { return nil, errors.New("unsupported") } +func (c cacheMockerSource) V1TarReader() (io.ReadCloser, error) { + return nil, errors.New("unsupported") +} func (c cacheMockerSource) Descriptor() *registry.Descriptor { return c.descriptor } diff --git a/src/cmd/linuxkit/spec/image.go b/src/cmd/linuxkit/spec/image.go index 92565c6b4..55826b01d 100644 --- a/src/cmd/linuxkit/spec/image.go +++ b/src/cmd/linuxkit/spec/image.go @@ -10,7 +10,12 @@ import ( // ImageSource interface to an image. It can have its config read, and a its containers // can be read via an io.ReadCloser tar stream. type ImageSource interface { + // Config get the config for the image Config() (imagespec.ImageConfig, error) + // TarReader get the flattened filesystem of the image as a tar stream/ TarReader() (io.ReadCloser, error) + // Descriptor get the v1.Descriptor of the image Descriptor() *v1.Descriptor + // V1TarReader get the image as v1 tarball, also compatibel with `docker load` + V1TarReader() (io.ReadCloser, error) }