backend.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package build // import "github.com/docker/docker/api/server/backend/build"
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "github.com/distribution/reference"
  7. "github.com/docker/docker/api/types"
  8. "github.com/docker/docker/api/types/backend"
  9. "github.com/docker/docker/api/types/events"
  10. "github.com/docker/docker/builder"
  11. buildkit "github.com/docker/docker/builder/builder-next"
  12. daemonevents "github.com/docker/docker/daemon/events"
  13. "github.com/docker/docker/image"
  14. "github.com/docker/docker/pkg/stringid"
  15. "github.com/pkg/errors"
  16. "google.golang.org/grpc"
  17. )
  18. // ImageComponent provides an interface for working with images
  19. type ImageComponent interface {
  20. SquashImage(from string, to string) (string, error)
  21. TagImage(context.Context, image.ID, reference.Named) error
  22. }
  23. // Builder defines interface for running a build
  24. type Builder interface {
  25. Build(context.Context, backend.BuildConfig) (*builder.Result, error)
  26. }
  27. // Backend provides build functionality to the API router
  28. type Backend struct {
  29. builder Builder
  30. imageComponent ImageComponent
  31. buildkit *buildkit.Builder
  32. eventsService *daemonevents.Events
  33. }
  34. // NewBackend creates a new build backend from components
  35. func NewBackend(components ImageComponent, builder Builder, buildkit *buildkit.Builder, es *daemonevents.Events) (*Backend, error) {
  36. return &Backend{imageComponent: components, builder: builder, buildkit: buildkit, eventsService: es}, nil
  37. }
  38. // RegisterGRPC registers buildkit controller to the grpc server.
  39. func (b *Backend) RegisterGRPC(s *grpc.Server) {
  40. if b.buildkit != nil {
  41. b.buildkit.RegisterGRPC(s)
  42. }
  43. }
  44. // Build builds an image from a Source
  45. func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string, error) {
  46. options := config.Options
  47. useBuildKit := options.Version == types.BuilderBuildKit
  48. tags, err := sanitizeRepoAndTags(options.Tags)
  49. if err != nil {
  50. return "", err
  51. }
  52. var build *builder.Result
  53. if useBuildKit {
  54. build, err = b.buildkit.Build(ctx, config)
  55. if err != nil {
  56. return "", err
  57. }
  58. } else {
  59. build, err = b.builder.Build(ctx, config)
  60. if err != nil {
  61. return "", err
  62. }
  63. }
  64. if build == nil {
  65. return "", nil
  66. }
  67. imageID := build.ImageID
  68. if options.Squash {
  69. if imageID, err = squashBuild(build, b.imageComponent); err != nil {
  70. return "", err
  71. }
  72. if config.ProgressWriter.AuxFormatter != nil {
  73. if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
  74. return "", err
  75. }
  76. }
  77. }
  78. if !useBuildKit {
  79. stdout := config.ProgressWriter.StdoutFormatter
  80. fmt.Fprintf(stdout, "Successfully built %s\n", stringid.TruncateID(imageID))
  81. }
  82. if imageID != "" && !useBuildKit {
  83. err = tagImages(ctx, b.imageComponent, config.ProgressWriter.StdoutFormatter, image.ID(imageID), tags)
  84. }
  85. return imageID, err
  86. }
  87. // PruneCache removes all cached build sources
  88. func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
  89. buildCacheSize, cacheIDs, err := b.buildkit.Prune(ctx, opts)
  90. if err != nil {
  91. return nil, errors.Wrap(err, "failed to prune build cache")
  92. }
  93. b.eventsService.Log(events.ActionPrune, events.BuilderEventType, events.Actor{
  94. Attributes: map[string]string{
  95. "reclaimed": strconv.FormatInt(buildCacheSize, 10),
  96. },
  97. })
  98. return &types.BuildCachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
  99. }
  100. // Cancel cancels the build by ID
  101. func (b *Backend) Cancel(ctx context.Context, id string) error {
  102. return b.buildkit.Cancel(ctx, id)
  103. }
  104. func squashBuild(build *builder.Result, imageComponent ImageComponent) (string, error) {
  105. var fromID string
  106. if build.FromImage != nil {
  107. fromID = build.FromImage.ImageID()
  108. }
  109. imageID, err := imageComponent.SquashImage(build.ImageID, fromID)
  110. if err != nil {
  111. return "", errors.Wrap(err, "error squashing image")
  112. }
  113. return imageID, nil
  114. }