Skip to content

Commit b2cd089

Browse files
committed
build: respect dependency order for classic builder
When using the "classic" (non-BuildKit) builder, ensure that services are iterated in dependency order for a build so that it's possible to guarantee the presence of a base image that's been added as a dependency with `depends_on`. This is a very common pattern when using base images with Compose. A fix for BuildKit is blocked currently until we can rely on a newer version of the engine (see docker#9324)[^1]. [^1]: docker#9232 (comment) Signed-off-by: Milas Bowman <[email protected]>
1 parent e5dcb8a commit b2cd089

File tree

7 files changed

+74
-4
lines changed

7 files changed

+74
-4
lines changed

pkg/compose/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func (s *composeService) doBuild(ctx context.Context, project *types.Project, op
205205
return nil, nil
206206
}
207207
if buildkitEnabled, err := s.dockerCli.BuildKitEnabled(); err != nil || !buildkitEnabled {
208-
return s.doBuildClassic(ctx, opts)
208+
return s.doBuildClassic(ctx, project, opts)
209209
}
210210
return s.doBuildBuildkit(ctx, project, opts, mode)
211211
}

pkg/compose/build_classic.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"runtime"
2828
"strings"
2929

30+
"github.com/compose-spec/compose-go/types"
3031
buildx "github.com/docker/buildx/build"
3132
"github.com/docker/cli/cli/command/image/build"
3233
dockertypes "github.com/docker/docker/api/types"
@@ -41,15 +42,24 @@ import (
4142
"github.com/pkg/errors"
4243
)
4344

44-
func (s *composeService) doBuildClassic(ctx context.Context, opts map[string]buildx.Options) (map[string]string, error) {
45+
func (s *composeService) doBuildClassic(ctx context.Context, project *types.Project, opts map[string]buildx.Options) (map[string]string, error) {
4546
var nameDigests = make(map[string]string)
4647
var errs error
47-
for name, o := range opts {
48+
err := project.WithServices(nil, func(service types.ServiceConfig) error {
49+
imageName := getImageName(service, project.Name)
50+
o, ok := opts[imageName]
51+
if !ok {
52+
return nil
53+
}
4854
digest, err := s.doBuildClassicSimpleImage(ctx, o)
4955
if err != nil {
5056
errs = multierror.Append(errs, err).ErrorOrNil()
5157
}
52-
nameDigests[name] = digest
58+
nameDigests[imageName] = digest
59+
return nil
60+
})
61+
if err != nil {
62+
return nil, err
5363
}
5464

5565
return nameDigests, errs

pkg/e2e/compose_build_test.go renamed to pkg/e2e/build_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,40 @@ func TestBuildTags(t *testing.T) {
201201
res.Assert(t, icmd.Expected{Out: expectedOutput})
202202
})
203203
}
204+
205+
func TestBuildImageDependencies(t *testing.T) {
206+
doTest := func(t *testing.T, cli *CLI) {
207+
resetState := func() {
208+
cli.RunDockerComposeCmd(t, "down", "--rmi=all", "-t=0")
209+
}
210+
resetState()
211+
t.Cleanup(resetState)
212+
213+
// the image should NOT exist now
214+
res := cli.RunDockerOrExitError(t, "image", "inspect", "build-dependencies_service")
215+
res.Assert(t, icmd.Expected{
216+
ExitCode: 1,
217+
Err: "Error: No such image: build-dependencies_service",
218+
})
219+
220+
res = cli.RunDockerComposeCmd(t, "build")
221+
t.Log(res.Combined())
222+
223+
res = cli.RunDockerCmd(t,
224+
"image", "inspect", "--format={{ index .RepoTags 0 }}",
225+
"build-dependencies_service")
226+
res.Assert(t, icmd.Expected{Out: "build-dependencies_service:latest"})
227+
}
228+
229+
t.Run("ClassicBuilder", func(t *testing.T) {
230+
cli := NewParallelCLI(t, WithEnv(
231+
"DOCKER_BUILDKIT=0",
232+
"COMPOSE_FILE=./fixtures/build-dependencies/compose.yaml",
233+
))
234+
doTest(t, cli)
235+
})
236+
237+
t.Run("BuildKit", func(t *testing.T) {
238+
t.Skip("See https://github.com/docker/compose/issues/9232")
239+
})
240+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM alpine
2+
3+
COPY hello.txt /hello.txt
4+
5+
CMD [ "/bin/true" ]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
services:
2+
base:
3+
image: base
4+
build:
5+
context: .
6+
dockerfile: base.dockerfile
7+
service:
8+
depends_on:
9+
- base
10+
build:
11+
context: .
12+
dockerfile: service.dockerfile
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
this file was copied from base -> service
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM alpine
2+
3+
COPY --from=base /hello.txt /hello.txt
4+
5+
CMD [ "cat", "/hello.txt" ]

0 commit comments

Comments
 (0)