Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 58bfbbb

Browse files
committed
introduce ImageDigestLabel to track image built for service
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 9c615dc commit 58bfbbb

File tree

5 files changed

+28
-38
lines changed

5 files changed

+28
-38
lines changed

pkg/api/labels.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ const (
4747
OneoffLabel = "com.docker.compose.oneoff"
4848
// SlugLabel stores unique slug used for one-off container identity
4949
SlugLabel = "com.docker.compose.slug"
50+
// ImageDigestLabel stores digest of the container image used to run service
51+
ImageDigestLabel = "com.docker.compose.image"
5052
// VersionLabel stores the compose tool version used to run application
5153
VersionLabel = "com.docker.compose.version"
5254
)

pkg/compose/build.go

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
_ "github.com/docker/buildx/driver/docker" // required to get default driver registered
2929
"github.com/docker/buildx/util/buildflags"
3030
xprogress "github.com/docker/buildx/util/progress"
31-
moby "github.com/docker/docker/api/types"
3231
bclient "github.com/moby/buildkit/client"
3332
"github.com/moby/buildkit/session"
3433
"github.com/moby/buildkit/session/auth/authprovider"
@@ -80,7 +79,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
8079
}
8180
}
8281

83-
_, err := s.doBuild(ctx, project, opts, Containers{}, options.Progress)
82+
_, err := s.doBuild(ctx, project, opts, options.Progress)
8483
if err == nil {
8584
if len(imagesToBuild) > 0 && !options.Quiet {
8685
utils.DisplayScanSuggestMsg()
@@ -90,7 +89,7 @@ func (s *composeService) build(ctx context.Context, project *types.Project, opti
9089
return err
9190
}
9291

93-
func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, observedState Containers, quietPull bool) error {
92+
func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, quietPull bool) error {
9493
for _, service := range project.Services {
9594
if service.Image == "" && service.Build == nil {
9695
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.
111110
if quietPull {
112111
mode = xprogress.PrinterModeQuiet
113112
}
114-
opts, imagesToBuild, err := s.getBuildOptions(project, images)
113+
opts, err := s.getBuildOptions(project, images)
115114
if err != nil {
116115
return err
117116
}
118-
builtImages, err := s.doBuild(ctx, project, opts, observedState, mode)
117+
builtImages, err := s.doBuild(ctx, project, opts, mode)
119118
if err != nil {
120119
return err
121120
}
122121

123-
if len(imagesToBuild) > 0 {
122+
if len(builtImages) > 0 {
124123
utils.DisplayScanSuggestMsg()
125124
}
126125
for name, digest := range builtImages {
127126
images[name] = digest
128127
}
129-
// set digest as service.Image
128+
// set digest as com.docker.compose.image label so we can detect outdated containers
130129
for i, service := range project.Services {
131-
digest, ok := images[getImageName(service, project.Name)]
130+
image := getImageName(service, project.Name)
131+
digest, ok := images[image]
132132
if ok {
133-
project.Services[i].Image = digest
133+
if project.Services[i].Labels == nil {
134+
project.Services[i].Labels = types.Labels{}
135+
}
136+
project.Services[i].Labels[api.ImageDigestLabel] = digest
137+
project.Services[i].Image = image
134138
}
135139
}
136140
return nil
137141
}
138142

139-
func (s *composeService) getBuildOptions(project *types.Project, images map[string]string) (map[string]build.Options, []string, error) {
143+
func (s *composeService) getBuildOptions(project *types.Project, images map[string]string) (map[string]build.Options, error) {
140144
opts := map[string]build.Options{}
141-
imagesToBuild := []string{}
142145
for _, service := range project.Services {
143146
if service.Image == "" && service.Build == nil {
144-
return nil, nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
147+
return nil, fmt.Errorf("invalid service %q. Must specify either image or build", service.Name)
145148
}
146149
imageName := getImageName(service, project.Name)
147150
_, localImagePresent := images[imageName]
@@ -150,16 +153,15 @@ func (s *composeService) getBuildOptions(project *types.Project, images map[stri
150153
if localImagePresent && service.PullPolicy != types.PullPolicyBuild {
151154
continue
152155
}
153-
imagesToBuild = append(imagesToBuild, imageName)
154156
opt, err := s.toBuildOptions(project, service, imageName)
155157
if err != nil {
156-
return nil, nil, err
158+
return nil, err
157159
}
158160
opts[imageName] = opt
159161
continue
160162
}
161163
}
162-
return opts, imagesToBuild, nil
164+
return opts, nil
163165

164166
}
165167

@@ -182,7 +184,7 @@ func (s *composeService) getLocalImagesDigests(ctx context.Context, project *typ
182184
return images, nil
183185
}
184186

185-
func (s *composeService) doBuild(ctx context.Context, project *types.Project, opts map[string]build.Options, observedState Containers, mode string) (map[string]string, error) {
187+
func (s *composeService) doBuild(ctx context.Context, project *types.Project, opts map[string]build.Options, mode string) (map[string]string, error) {
186188
info, err := s.apiClient.Info(ctx)
187189
if err != nil {
188190
return nil, err
@@ -227,18 +229,6 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
227229
return nil, WrapCategorisedComposeError(err, BuildFailure)
228230
}
229231

230-
cw := progress.ContextWriter(ctx)
231-
for _, c := range observedState {
232-
for imageName := range opts {
233-
if c.Image == imageName {
234-
err = s.removeContainers(ctx, cw, []moby.Container{c}, nil, false)
235-
if err != nil {
236-
return nil, err
237-
}
238-
}
239-
}
240-
}
241-
242232
imagesBuilt := map[string]string{}
243233
for name, img := range response {
244234
if img == nil || len(img.ExporterResponse) == 0 {

pkg/compose/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func (s *composeService) create(ctx context.Context, project *types.Project, opt
6060
return err
6161
}
6262

63-
err = s.ensureImagesExists(ctx, project, observedState, options.QuietPull)
63+
err = s.ensureImagesExists(ctx, project, options.QuietPull)
6464
if err != nil {
6565
return err
6666
}

pkg/compose/run.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,7 @@ import (
3333
)
3434

3535
func (s *composeService) RunOneOffContainer(ctx context.Context, project *types.Project, opts api.RunOptions) (int, error) {
36-
observedState, err := s.getContainers(ctx, project.Name, oneOffInclude, true)
37-
if err != nil {
38-
return 0, err
39-
}
40-
41-
containerID, err := s.prepareRun(ctx, project, observedState, opts)
36+
containerID, err := s.prepareRun(ctx, project, opts)
4237
if err != nil {
4338
return 0, err
4439
}
@@ -131,7 +126,7 @@ func (s *composeService) runInteractive(ctx context.Context, containerID string,
131126
}
132127
}
133128

134-
func (s *composeService) prepareRun(ctx context.Context, project *types.Project, observedState Containers, opts api.RunOptions) (string, error) {
129+
func (s *composeService) prepareRun(ctx context.Context, project *types.Project, opts api.RunOptions) (string, error) {
135130
service, err := project.GetService(opts.Service)
136131
if err != nil {
137132
return "", err
@@ -152,7 +147,7 @@ func (s *composeService) prepareRun(ctx context.Context, project *types.Project,
152147
service.Labels = service.Labels.Add(api.SlugLabel, slug)
153148
service.Labels = service.Labels.Add(api.OneoffLabel, "True")
154149

155-
if err := s.ensureImagesExists(ctx, project, observedState, false); err != nil { // all dependencies already checked, but might miss service img
150+
if err := s.ensureImagesExists(ctx, project, false); err != nil { // all dependencies already checked, but might miss service img
156151
return "", err
157152
}
158153
if err := s.waitDependencies(ctx, project, service); err != nil {

pkg/compose/up.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
3737
if err != nil {
3838
return err
3939
}
40-
return s.start(ctx, project, options.Start, nil)
40+
if options.Start.Attach == nil {
41+
return s.start(ctx, project, options.Start, nil)
42+
}
43+
return nil
4144
})
4245
if err != nil {
4346
return err

0 commit comments

Comments
 (0)