Skip to content

Commit

Permalink
Propagate compression options to the inline cache export
Browse files Browse the repository at this point in the history
Co-authored-by: Tonis Tiigi <[email protected]>
Signed-off-by: Kohei Tokunaga <[email protected]>
  • Loading branch information
ktock and tonistiigi committed Oct 12, 2021
1 parent b2ff444 commit f6549c4
Show file tree
Hide file tree
Showing 20 changed files with 201 additions and 42 deletions.
7 changes: 6 additions & 1 deletion cache/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/snapshot"
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/leaseutil"
Expand Down Expand Up @@ -1257,8 +1258,12 @@ func TestGetRemote(t *testing.T) {
ir := ir.(*immutableRef)
for _, compressionType := range []compression.Type{compression.Uncompressed, compression.Gzip, compression.EStargz, compression.Zstd} {
compressionType := compressionType
compressionopt := solver.CompressionOpt{
Type: compressionType,
Force: true,
}
eg.Go(func() error {
remote, err := ir.GetRemote(egctx, true, compressionType, true, nil)
remote, err := ir.GetRemote(egctx, true, compressionopt, nil)
require.NoError(t, err)
refChain := ir.parentRefChain()
for i, desc := range remote.Descriptors {
Expand Down
2 changes: 1 addition & 1 deletion cache/refs.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type ImmutableRef interface {
Clone() ImmutableRef

Extract(ctx context.Context, s session.Group) error // +progress
GetRemote(ctx context.Context, createIfNeeded bool, compressionType compression.Type, forceCompression bool, s session.Group) (*solver.Remote, error)
GetRemote(ctx context.Context, createIfNeeded bool, compressionopt solver.CompressionOpt, s session.Group) (*solver.Remote, error)
}

type MutableRef interface {
Expand Down
4 changes: 3 additions & 1 deletion cache/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ type Unlazier interface {

// GetRemote gets a *solver.Remote from content store for this ref (potentially pulling lazily).
// Note: Use WorkerRef.GetRemote instead as moby integration requires custom GetRemote implementation.
func (sr *immutableRef) GetRemote(ctx context.Context, createIfNeeded bool, compressionType compression.Type, forceCompression bool, s session.Group) (*solver.Remote, error) {
func (sr *immutableRef) GetRemote(ctx context.Context, createIfNeeded bool, compressionopt solver.CompressionOpt, s session.Group) (*solver.Remote, error) {
compressionType := compressionopt.Type
forceCompression := compressionopt.Force
ctx, done, err := leaseutil.WithLease(ctx, sr.cm.LeaseManager, leaseutil.MakeTemporary)
if err != nil {
return nil, err
Expand Down
20 changes: 18 additions & 2 deletions cache/remotecache/v1/cachestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,25 @@ func (cs *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult)
return worker.NewWorkerRefResult(ref, cs.w), nil
}

func (cs *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheResult, _ session.Group) (*solver.Remote, error) {
func (cs *cacheResultStorage) LoadRemote(ctx context.Context, res solver.CacheResult, compressionopts *solver.CompressionOpt, _ session.Group) (*solver.Remote, error) {
if r := cs.byResultID(res.ID); r != nil && r.result != nil {
return r.result, nil
if compressionopts == nil {
return r.result, nil
}
// Any of blobs in the remote must meet the specified compression option.
match := false
for _, desc := range r.result.Descriptors {
m := compressionopts.Type.IsMediaType(desc.MediaType)
match = match || m
if compressionopts.Force && !m {
match = false
break
}
}
if match {
return r.result, nil
}
return nil, nil // return nil as it's best effort.
}
return nil, errors.WithStack(solver.ErrNotFound)
}
Expand Down
50 changes: 50 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2231,6 +2231,12 @@ func testBuildExportZstd(t *testing.T, sb integration.Sandbox) {
},
},
},
// compression option should work even with inline cache exports
CacheExports: []CacheOptionsEntry{
{
Type: "inline",
},
},
}, nil)
require.NoError(t, err)

Expand Down Expand Up @@ -3034,6 +3040,50 @@ func testBasicInlineCacheImportExport(t *testing.T, sb integration.Sandbox) {

checkAllRemoved(t, c, sb)

// Export the cache again with compression
resp, err = c.Solve(sb.Context(), def, SolveOpt{
// specifying inline cache exporter is needed for reproducing containerimage.digest
// (not needed for reproducing rootfs/unique)
Exports: []ExportEntry{
{
Type: ExporterImage,
Attrs: map[string]string{
"name": target,
"push": "true",
"compression": "uncompressed", // inline cache should work with compression
"force-compression": "true",
},
},
},
CacheExports: []CacheOptionsEntry{
{
Type: "inline",
},
},
CacheImports: []CacheOptionsEntry{
{
Type: "registry",
Attrs: map[string]string{
"ref": target,
},
},
},
}, nil)
require.NoError(t, err)

dgst2uncompress, ok := resp.ExporterResponse[exptypes.ExporterImageDigestKey]
require.Equal(t, ok, true)

// dgst2uncompress != dgst, because the compression type is different
unique2uncompress, err := readFileInImage(sb.Context(), c, target+"@"+dgst2uncompress, "/unique")
require.NoError(t, err)
require.EqualValues(t, unique, unique2uncompress)

err = c.Prune(sb.Context(), nil, PruneAll)
require.NoError(t, err)

checkAllRemoved(t, c, sb)

resp, err = c.Solve(sb.Context(), def, SolveOpt{
Exports: []ExportEntry{
{
Expand Down
24 changes: 21 additions & 3 deletions exporter/containerimage/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/snapshot"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/util/buildinfo"
"github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/contentutil"
Expand Down Expand Up @@ -207,6 +208,15 @@ func (e *imageExporterInstance) Name() string {
return "exporting to image"
}

func (e *imageExporterInstance) Config() exporter.Config {
return exporter.Config{
Compression: solver.CompressionOpt{
Type: e.layerCompression,
Force: e.forceCompression,
},
}
}

func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source, sessionID string) (map[string]string, error) {
if src.Metadata == nil {
src.Metadata = make(map[string][]byte)
Expand Down Expand Up @@ -287,8 +297,12 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
if e.push {
annotations := map[digest.Digest]map[string]string{}
mprovider := contentutil.NewMultiProvider(e.opt.ImageWriter.ContentStore())
compressionopt := solver.CompressionOpt{
Type: e.layerCompression,
Force: e.forceCompression,
}
if src.Ref != nil {
remote, err := src.Ref.GetRemote(ctx, false, e.layerCompression, e.forceCompression, session.NewGroup(sessionID))
remote, err := src.Ref.GetRemote(ctx, false, compressionopt, session.NewGroup(sessionID))
if err != nil {
return nil, err
}
Expand All @@ -299,7 +313,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
}
if len(src.Refs) > 0 {
for _, r := range src.Refs {
remote, err := r.GetRemote(ctx, false, e.layerCompression, e.forceCompression, session.NewGroup(sessionID))
remote, err := r.GetRemote(ctx, false, compressionopt, session.NewGroup(sessionID))
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -352,7 +366,11 @@ func (e *imageExporterInstance) unpackImage(ctx context.Context, img images.Imag
}
}

remote, err := topLayerRef.GetRemote(ctx, true, e.layerCompression, e.forceCompression, s)
compressionopt := solver.CompressionOpt{
Type: e.layerCompression,
Force: e.forceCompression,
}
remote, err := topLayerRef.GetRemote(ctx, true, compressionopt, s)
if err != nil {
return err
}
Expand Down
6 changes: 5 additions & 1 deletion exporter/containerimage/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,18 @@ func (ic *ImageWriter) exportLayers(ctx context.Context, compressionType compres
layersDone := oneOffProgress(ctx, "exporting layers")

out := make([]solver.Remote, len(refs))
compressionopt := solver.CompressionOpt{
Type: compressionType,
Force: forceCompression,
}

for i, ref := range refs {
func(i int, ref cache.ImmutableRef) {
if ref == nil {
return
}
eg.Go(func() error {
remote, err := ref.GetRemote(ctx, true, compressionType, forceCompression, s)
remote, err := ref.GetRemote(ctx, true, compressionopt, s)
if err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"

"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/solver"
)

type Exporter interface {
Expand All @@ -12,6 +13,7 @@ type Exporter interface {

type ExporterInstance interface {
Name() string
Config() Config
Export(ctx context.Context, src Source, sessionID string) (map[string]string, error)
}

Expand All @@ -20,3 +22,7 @@ type Source struct {
Refs map[string]cache.ImmutableRef
Metadata map[string][]byte
}

type Config struct {
Compression solver.CompressionOpt
}
4 changes: 4 additions & 0 deletions exporter/local/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ func (e *localExporterInstance) Name() string {
return "exporting to client"
}

func (e *localExporter) Config() exporter.Config {
return exporter.Config{}
}

func (e *localExporterInstance) Export(ctx context.Context, inp exporter.Source, sessionID string) (map[string]string, error) {

timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
Expand Down
18 changes: 16 additions & 2 deletions exporter/oci/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/moby/buildkit/exporter/containerimage/exptypes"
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/session/filesync"
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/util/buildinfo"
"github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/contentutil"
Expand Down Expand Up @@ -144,6 +145,15 @@ func (e *imageExporterInstance) Name() string {
return "exporting to oci image format"
}

func (e *imageExporterInstance) Config() exporter.Config {
return exporter.Config{
Compression: solver.CompressionOpt{
Type: e.layerCompression,
Force: e.forceCompression,
},
}
}

func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source, sessionID string) (map[string]string, error) {
if e.opt.Variant == VariantDocker && len(src.Refs) > 0 {
return nil, errors.Errorf("docker exporter does not currently support exporting manifest lists")
Expand Down Expand Up @@ -227,8 +237,12 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
}

mprovider := contentutil.NewMultiProvider(e.opt.ImageWriter.ContentStore())
compressionopt := solver.CompressionOpt{
Type: e.layerCompression,
Force: e.forceCompression,
}
if src.Ref != nil {
remote, err := src.Ref.GetRemote(ctx, false, e.layerCompression, e.forceCompression, session.NewGroup(sessionID))
remote, err := src.Ref.GetRemote(ctx, false, compressionopt, session.NewGroup(sessionID))
if err != nil {
return nil, err
}
Expand All @@ -245,7 +259,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src exporter.Source,
}
if len(src.Refs) > 0 {
for _, r := range src.Refs {
remote, err := r.GetRemote(ctx, false, e.layerCompression, e.forceCompression, session.NewGroup(sessionID))
remote, err := r.GetRemote(ctx, false, compressionopt, session.NewGroup(sessionID))
if err != nil {
return nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions exporter/tar/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (e *localExporterInstance) Name() string {
return "exporting to client"
}

func (e *localExporterInstance) Config() exporter.Config {
return exporter.Config{}
}

func (e *localExporterInstance) Export(ctx context.Context, inp exporter.Source, sessionID string) (map[string]string, error) {
var defers []func()

Expand Down
2 changes: 1 addition & 1 deletion solver/cachestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ type CacheInfoLink struct {
type CacheResultStorage interface {
Save(Result, time.Time) (CacheResult, error)
Load(ctx context.Context, res CacheResult) (Result, error)
LoadRemote(ctx context.Context, res CacheResult, s session.Group) (*Remote, error)
LoadRemote(ctx context.Context, res CacheResult, compression *CompressionOpt, s session.Group) (*Remote, error)
Exists(id string) bool
}
36 changes: 25 additions & 11 deletions solver/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
selector digest.Digest
}

rec := t.Add(rootKey(e.k.Digest(), e.k.Output()))
recKey := rootKey(e.k.Digest(), e.k.Output())
rec := t.Add(recKey)
allRec := []CacheExporterRecord{rec}

addRecord := true
Expand All @@ -93,35 +94,46 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach

var remote *Remote
if v := e.record; v != nil && len(e.k.Deps()) > 0 && addRecord {
var variants []CacheExporterRecord

cm := v.cacheManager
key := cm.getID(v.key)
res, err := cm.backend.Load(key, v.ID)
if err != nil {
return nil, err
}

remote, err = cm.results.LoadRemote(ctx, res, opt.Session)
remote, err := cm.results.LoadRemote(ctx, res, opt.CompressionOpt, opt.Session)
if err != nil {
return nil, err
}

if remote == nil && opt.Mode != CacheExportModeRemoteOnly {
if (remote == nil || opt.CompressionOpt != nil) && opt.Mode != CacheExportModeRemoteOnly {
res, err := cm.results.Load(ctx, res)
if err != nil {
return nil, err
}
remote, err = opt.Convert(ctx, res)
remoteConverted, err := opt.Convert(ctx, res)
if err != nil {
return nil, err
}
res.Release(context.TODO())
if remote == nil {
remote = remoteConverted
} else if opt.CompressionOpt != nil {
// record the variant as well if compression option is specified
rec := t.Add(recKey)
rec.AddResult(v.CreatedAt, remoteConverted)
variants = append(variants, rec)
}
}

if remote != nil {
for _, rec := range allRec {
rec.AddResult(v.CreatedAt, remote)
}
}
allRec = append(allRec, variants...)
}

if remote != nil && opt.Mode == CacheExportModeMin {
Expand Down Expand Up @@ -154,15 +166,17 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
}
}

for i, srcs := range srcs {
for _, src := range srcs {
rec.LinkFrom(src.r, i, src.selector.String())
for _, rec := range allRec {
for i, srcs := range srcs {
for _, src := range srcs {
rec.LinkFrom(src.r, i, src.selector.String())
}
}
}

for cm, id := range e.k.ids {
if _, err := addBacklinks(t, rec, cm, id, bkm); err != nil {
return nil, err
for cm, id := range e.k.ids {
if _, err := addBacklinks(t, rec, cm, id, bkm); err != nil {
return nil, err
}
}
}

Expand Down
Loading

0 comments on commit f6549c4

Please sign in to comment.