github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/api/server/backend/build/backend.go (about)

     1  package build // import "github.com/docker/docker/api/server/backend/build"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/docker/distribution/reference"
     8  	"github.com/docker/docker/api/types"
     9  	"github.com/docker/docker/api/types/backend"
    10  	"github.com/docker/docker/builder"
    11  	buildkit "github.com/docker/docker/builder/builder-next"
    12  	"github.com/docker/docker/builder/fscache"
    13  	"github.com/docker/docker/image"
    14  	"github.com/docker/docker/pkg/stringid"
    15  	"github.com/pkg/errors"
    16  	"golang.org/x/sync/errgroup"
    17  )
    18  
    19  // ImageComponent provides an interface for working with images
    20  type ImageComponent interface {
    21  	SquashImage(from string, to string) (string, error)
    22  	TagImageWithReference(image.ID, reference.Named) error
    23  }
    24  
    25  // Builder defines interface for running a build
    26  type Builder interface {
    27  	Build(context.Context, backend.BuildConfig) (*builder.Result, error)
    28  }
    29  
    30  // Backend provides build functionality to the API router
    31  type Backend struct {
    32  	builder        Builder
    33  	fsCache        *fscache.FSCache
    34  	imageComponent ImageComponent
    35  	buildkit       *buildkit.Builder
    36  }
    37  
    38  // NewBackend creates a new build backend from components
    39  func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSCache, buildkit *buildkit.Builder) (*Backend, error) {
    40  	return &Backend{imageComponent: components, builder: builder, fsCache: fsCache, buildkit: buildkit}, nil
    41  }
    42  
    43  // Build builds an image from a Source
    44  func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
    45  	options := config.Options
    46  	useBuildKit := options.Version == types.BuilderBuildKit
    47  
    48  	tagger, err := NewTagger(b.imageComponent, config.ProgressWriter.StdoutFormatter, options.Tags)
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  
    53  	var build *builder.Result
    54  	if useBuildKit {
    55  		build, err = b.buildkit.Build(ctx, config)
    56  		if err != nil {
    57  			return "", err
    58  		}
    59  	} else {
    60  		build, err = b.builder.Build(ctx, config)
    61  		if err != nil {
    62  			return "", err
    63  		}
    64  	}
    65  
    66  	if build == nil {
    67  		return "", nil
    68  	}
    69  
    70  	var imageID = build.ImageID
    71  	if options.Squash {
    72  		if imageID, err = squashBuild(build, b.imageComponent); err != nil {
    73  			return "", err
    74  		}
    75  		if config.ProgressWriter.AuxFormatter != nil {
    76  			if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
    77  				return "", err
    78  			}
    79  		}
    80  	}
    81  
    82  	if !useBuildKit {
    83  		stdout := config.ProgressWriter.StdoutFormatter
    84  		fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
    85  	}
    86  	err = tagger.TagImages(image.ID(imageID))
    87  	return imageID, err
    88  }
    89  
    90  // PruneCache removes all cached build sources
    91  func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
    92  	eg, ctx := errgroup.WithContext(ctx)
    93  
    94  	var fsCacheSize uint64
    95  	eg.Go(func() error {
    96  		var err error
    97  		fsCacheSize, err = b.fsCache.Prune(ctx)
    98  		if err != nil {
    99  			return errors.Wrap(err, "failed to prune fscache")
   100  		}
   101  		return nil
   102  	})
   103  
   104  	var buildCacheSize int64
   105  	var cacheIDs []string
   106  	eg.Go(func() error {
   107  		var err error
   108  		buildCacheSize, cacheIDs, err = b.buildkit.Prune(ctx, opts)
   109  		if err != nil {
   110  			return errors.Wrap(err, "failed to prune build cache")
   111  		}
   112  		return nil
   113  	})
   114  
   115  	if err := eg.Wait(); err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
   120  }
   121  
   122  // Cancel cancels the build by ID
   123  func (b *Backend) Cancel(ctx context.Context, id string) error {
   124  	return b.buildkit.Cancel(ctx, id)
   125  }
   126  
   127  func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
   128  	var fromID string
   129  	if build.FromImage != nil {
   130  		fromID = build.FromImage.ImageID()
   131  	}
   132  	imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
   133  	if err != nil {
   134  		return "", errors.Wrap(err, "error squashing image")
   135  	}
   136  	return imageID, nil
   137  }