Prechádzať zdrojové kódy

introduce ImageDigestLabel to track image built for service

Signed-off-by: Nicolas De Loof <[email protected]>
Nicolas De Loof 4 rokov pred
rodič
commit
58bfbbb288
5 zmenil súbory, kde vykonal 28 pridanie a 38 odobranie
  1. 2 0
      pkg/api/labels.go
  2. 18 28
      pkg/compose/build.go
  3. 1 1
      pkg/compose/create.go
  4. 3 8
      pkg/compose/run.go
  5. 4 1
      pkg/compose/up.go

+ 2 - 0
pkg/api/labels.go

@@ -47,6 +47,8 @@ const (
 	OneoffLabel = "com.docker.compose.oneoff"
 	// SlugLabel stores unique slug used for one-off container identity
 	SlugLabel = "com.docker.compose.slug"
+	// ImageDigestLabel stores digest of the container image used to run service
+	ImageDigestLabel = "com.docker.compose.image"
 	// VersionLabel stores the compose tool version used to run application
 	VersionLabel = "com.docker.compose.version"
 )

+ 18 - 28
pkg/compose/build.go

@@ -28,7 +28,6 @@ import (
 	_ "github.com/docker/buildx/driver/docker" // required to get default driver registered
 	"github.com/docker/buildx/util/buildflags"
 	xprogress "github.com/docker/buildx/util/progress"
-	moby "github.com/docker/docker/api/types"
 	bclient "github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/session/auth/authprovider"
@@ -80,7 +79,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
 		}
 	}
 
-	_, err := s.doBuild(ctx, project, opts, Containers{}, options.Progress)
+	_, err := s.doBuild(ctx, project, opts, options.Progress)
 	if err == nil {
 		if len(imagesToBuild) > 0 && !options.Quiet {
 			utils.DisplayScanSuggestMsg()
@@ -90,7 +89,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
 	return err
 }
 
-func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, observedState Containers, quietPull bool) error {
+func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, quietPull bool) error {
 	for _, service := range project.Services {
 		if service.Image == "" && service.Build == nil {
 			return fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
@@ -111,37 +110,41 @@ func (s *composeService) ensureImagesExists(ctx context.Context, project *types.
 	if quietPull {
 		mode = xprogress.PrinterModeQuiet
 	}
-	opts, imagesToBuild, err := s.getBuildOptions(project, images)
+	opts, err := s.getBuildOptions(project, images)
 	if err != nil {
 		return err
 	}
-	builtImages, err := s.doBuild(ctx, project, opts, observedState, mode)
+	builtImages, err := s.doBuild(ctx, project, opts, mode)
 	if err != nil {
 		return err
 	}
 
-	if len(imagesToBuild) > 0 {
+	if len(builtImages) > 0 {
 		utils.DisplayScanSuggestMsg()
 	}
 	for name, digest := range builtImages {
 		images[name] = digest
 	}
-	// set digest as service.Image
+	// set digest as com.docker.compose.image label so we can detect outdated containers
 	for i, service := range project.Services {
-		digest, ok := images[getImageName(service, project.Name)]
+		image := getImageName(service, project.Name)
+		digest, ok := images[image]
 		if ok {
-			project.Services[i].Image = digest
+			if project.Services[i].Labels == nil {
+				project.Services[i].Labels = types.Labels{}
+			}
+			project.Services[i].Labels[api.ImageDigestLabel] = digest
+			project.Services[i].Image = image
 		}
 	}
 	return nil
 }
 
-func (s *composeService) getBuildOptions(project *types.Project, images map[string]string) (map[string]build.Options, []string, error) {
+func (s *composeService) getBuildOptions(project *types.Project, images map[string]string) (map[string]build.Options, error) {
 	opts := map[string]build.Options{}
-	imagesToBuild := []string{}
 	for _, service := range project.Services {
 		if service.Image == "" && service.Build == nil {
-			return nil, nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
+			return nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
 		}
 		imageName := getImageName(service, project.Name)
 		_, localImagePresent := images[imageName]
@@ -150,16 +153,15 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
 			if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
 				continue
 			}
-			imagesToBuild = append(imagesToBuild, imageName)
 			opt, err := s.toBuildOptions(project, service, imageName)
 			if err != nil {
-				return nil, nil, err
+				return nil, err
 			}
 			opts[imageName] = opt
 			continue
 		}
 	}
-	return opts, imagesToBuild, nil
+	return opts, nil
 
 }
 
@@ -182,7 +184,7 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
 	return images, nil
 }
 
-func (s *composeService) doBuild(ctx context.Context, project *types.Project, opts map[string]build.Options, observedState Containers, mode string) (map[string]string, error) {
+func (s *composeService) doBuild(ctx context.Context, project *types.Project, opts map[string]build.Options, mode string) (map[string]string, error) {
 	info, err := s.apiClient.Info(ctx)
 	if err != nil {
 		return nil, err
@@ -227,18 +229,6 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
 		return nil, WrapCategorisedComposeError(err, BuildFailure)
 	}
 
-	cw := progress.ContextWriter(ctx)
-	for _, c := range observedState {
-		for imageName := range opts {
-			if c.Image == imageName {
-				err = s.removeContainers(ctx, cw, []moby.Container{c}, nil, false)
-				if err != nil {
-					return nil, err
-				}
-			}
-		}
-	}
-
 	imagesBuilt := map[string]string{}
 	for name, img := range response {
 		if img == nil || len(img.ExporterResponse) == 0 {

+ 1 - 1
pkg/compose/create.go

@@ -60,7 +60,7 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
 		return err
 	}
 
-	err = s.ensureImagesExists(ctx, project, observedState, options.QuietPull)
+	err = s.ensureImagesExists(ctx, project, options.QuietPull)
 	if err != nil {
 		return err
 	}

+ 3 - 8
pkg/compose/run.go

@@ -33,12 +33,7 @@ import (
 )
 
 func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
-	observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
-	if err != nil {
-		return 0, err
-	}
-
-	containerID, err := s.prepareRun(ctx, project, observedState, opts)
+	containerID, err := s.prepareRun(ctx, project, opts)
 	if err != nil {
 		return 0, err
 	}
@@ -131,7 +126,7 @@ func (s *composeService) runInteractive(ctx context.Context, containerID string,
 	}
 }
 
-func (s *composeService) prepareRun(ctx context.Context, project *types.Project, observedState Containers, opts api.RunOptions) (string, error) {
+func (s *composeService) prepareRun(ctx context.Context, project *types.Project, opts api.RunOptions) (string, error) {
 	service, err := project.GetService(opts.Service)
 	if err != nil {
 		return "", err
@@ -152,7 +147,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
 	service.Labels = service.Labels.Add(api.SlugLabel, slug)
 	service.Labels = service.Labels.Add(api.OneoffLabel, "True")
 
-	if err := s.ensureImagesExists(ctx, project, observedState, false); err != nil { // all dependencies already checked, but might miss service img
+	if err := s.ensureImagesExists(ctx, project, false); err != nil { // all dependencies already checked, but might miss service img
 		return "", err
 	}
 	if err := s.waitDependencies(ctx, project, service); err != nil {

+ 4 - 1
pkg/compose/up.go

@@ -37,7 +37,10 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 		if err != nil {
 			return err
 		}
-		return s.start(ctx, project, options.Start, nil)
+		if options.Start.Attach == nil {
+			return s.start(ctx, project, options.Start, nil)
+		}
+		return nil
 	})
 	if err != nil {
 		return err