mirror of
https://github.com/docker/compose.git
synced 2025-05-25 17:00:21 +02:00
introduce ImageDigestLabel to track image built for service
Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
parent
9c615dc22e
commit
58bfbbb288
@ -47,6 +47,8 @@ const (
|
|||||||
OneoffLabel = "com.docker.compose.oneoff"
|
OneoffLabel = "com.docker.compose.oneoff"
|
||||||
// SlugLabel stores unique slug used for one-off container identity
|
// SlugLabel stores unique slug used for one-off container identity
|
||||||
SlugLabel = "com.docker.compose.slug"
|
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 stores the compose tool version used to run application
|
||||||
VersionLabel = "com.docker.compose.version"
|
VersionLabel = "com.docker.compose.version"
|
||||||
)
|
)
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
_ "github.com/docker/buildx/driver/docker" // required to get default driver registered
|
_ "github.com/docker/buildx/driver/docker" // required to get default driver registered
|
||||||
"github.com/docker/buildx/util/buildflags"
|
"github.com/docker/buildx/util/buildflags"
|
||||||
xprogress "github.com/docker/buildx/util/progress"
|
xprogress "github.com/docker/buildx/util/progress"
|
||||||
moby "github.com/docker/docker/api/types"
|
|
||||||
bclient "github.com/moby/buildkit/client"
|
bclient "github.com/moby/buildkit/client"
|
||||||
"github.com/moby/buildkit/session"
|
"github.com/moby/buildkit/session"
|
||||||
"github.com/moby/buildkit/session/auth/authprovider"
|
"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 err == nil {
|
||||||
if len(imagesToBuild) > 0 && !options.Quiet {
|
if len(imagesToBuild) > 0 && !options.Quiet {
|
||||||
utils.DisplayScanSuggestMsg()
|
utils.DisplayScanSuggestMsg()
|
||||||
@ -90,7 +89,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
|
|||||||
return err
|
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 {
|
for _, service := range project.Services {
|
||||||
if service.Image == "" && service.Build == nil {
|
if service.Image == "" && service.Build == nil {
|
||||||
return fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
|
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 {
|
if quietPull {
|
||||||
mode = xprogress.PrinterModeQuiet
|
mode = xprogress.PrinterModeQuiet
|
||||||
}
|
}
|
||||||
opts, imagesToBuild, err := s.getBuildOptions(project, images)
|
opts, err := s.getBuildOptions(project, images)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
builtImages, err := s.doBuild(ctx, project, opts, observedState, mode)
|
builtImages, err := s.doBuild(ctx, project, opts, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(imagesToBuild) > 0 {
|
if len(builtImages) > 0 {
|
||||||
utils.DisplayScanSuggestMsg()
|
utils.DisplayScanSuggestMsg()
|
||||||
}
|
}
|
||||||
for name, digest := range builtImages {
|
for name, digest := range builtImages {
|
||||||
images[name] = digest
|
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 {
|
for i, service := range project.Services {
|
||||||
digest, ok := images[getImageName(service, project.Name)]
|
image := getImageName(service, project.Name)
|
||||||
|
digest, ok := images[image]
|
||||||
if ok {
|
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
|
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{}
|
opts := map[string]build.Options{}
|
||||||
imagesToBuild := []string{}
|
|
||||||
for _, service := range project.Services {
|
for _, service := range project.Services {
|
||||||
if service.Image == "" && service.Build == nil {
|
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)
|
imageName := getImageName(service, project.Name)
|
||||||
_, localImagePresent := images[imageName]
|
_, localImagePresent := images[imageName]
|
||||||
@ -150,16 +153,15 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
|
|||||||
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
imagesToBuild = append(imagesToBuild, imageName)
|
|
||||||
opt, err := s.toBuildOptions(project, service, imageName)
|
opt, err := s.toBuildOptions(project, service, imageName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
opts[imageName] = opt
|
opts[imageName] = opt
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return opts, imagesToBuild, nil
|
return opts, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +184,7 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
|
|||||||
return images, nil
|
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)
|
info, err := s.apiClient.Info(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -227,18 +229,6 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
|
|||||||
return nil, WrapCategorisedComposeError(err, BuildFailure)
|
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{}
|
imagesBuilt := map[string]string{}
|
||||||
for name, img := range response {
|
for name, img := range response {
|
||||||
if img == nil || len(img.ExporterResponse) == 0 {
|
if img == nil || len(img.ExporterResponse) == 0 {
|
||||||
|
@ -60,7 +60,7 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.ensureImagesExists(ctx, project, observedState, options.QuietPull)
|
err = s.ensureImagesExists(ctx, project, options.QuietPull)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
|
func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
|
||||||
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
|
containerID, err := s.prepareRun(ctx, project, opts)
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
containerID, err := s.prepareRun(ctx, project, observedState, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
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)
|
service, err := project.GetService(opts.Service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
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.SlugLabel, slug)
|
||||||
service.Labels = service.Labels.Add(api.OneoffLabel, "True")
|
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
|
return "", err
|
||||||
}
|
}
|
||||||
if err := s.waitDependencies(ctx, project, service); err != nil {
|
if err := s.waitDependencies(ctx, project, service); err != nil {
|
||||||
|
@ -37,7 +37,10 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if options.Start.Attach == nil {
|
||||||
return s.start(ctx, project, options.Start, nil)
|
return s.start(ctx, project, options.Start, nil)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
x
Reference in New Issue
Block a user