Skip to content

Commit 2ed82c7

Browse files
committed
feat: Add buildx option for daemon-less BuildKit support
`docker buildx build` can be configured to execute a remote buildkit instance. No docker daemon is necessary for this to work. This commit removes dependencies on docker daemon if `buildx` is used, so `skaffold build` can be used in a CI without docker daemon.
1 parent 285c697 commit 2ed82c7

File tree

7 files changed

+28
-9
lines changed

7 files changed

+28
-9
lines changed

pkg/skaffold/build/docker/docker.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact,
7272
// ignore useCLI boolean if buildkit is enabled since buildkit is only implemented for docker CLI at the moment in skaffold.
7373
// we might consider a different approach in the future.
7474
// use CLI for cross-platform builds
75-
if b.useCLI || (b.useBuildKit != nil && *b.useBuildKit) || len(a.DockerArtifact.CliFlags) > 0 || matcher.IsNotEmpty() {
75+
if b.useCLI || b.buildx || (b.useBuildKit != nil && *b.useBuildKit) || len(a.DockerArtifact.CliFlags) > 0 || matcher.IsNotEmpty() {
7676
imageID, err = b.dockerCLIBuild(ctx, output.GetUnderlyingWriter(out), a.ImageName, a.Workspace, dockerfile, a.ArtifactType.DockerArtifact, opts, pl)
7777
} else {
7878
imageID, err = b.localDocker.Build(ctx, out, a.Workspace, a.ImageName, a.ArtifactType.DockerArtifact, opts)
@@ -93,6 +93,9 @@ func (b *Builder) Build(ctx context.Context, out io.Writer, a *latest.Artifact,
9393

9494
func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string, workspace string, dockerfilePath string, a *latest.DockerArtifact, opts docker.BuildOptions, pl v1.Platform) (string, error) {
9595
args := []string{"build", workspace, "--file", dockerfilePath, "-t", opts.Tag}
96+
if b.buildx {
97+
args = append([]string{"buildx"}, args...)
98+
}
9699
imgRef, err := docker.ParseReference(opts.Tag)
97100
if err != nil {
98101
return "", fmt.Errorf("couldn't parse image tag: %w", err)
@@ -110,6 +113,9 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string
110113
if err != nil {
111114
return "", fmt.Errorf("getting docker build args: %w", err)
112115
}
116+
if b.buildx && b.pushImages {
117+
cliArgs = append(cliArgs, "--push")
118+
}
113119
args = append(args, cliArgs...)
114120

115121
if b.cfg.Prune() {
@@ -142,7 +148,11 @@ func (b *Builder) dockerCLIBuild(ctx context.Context, out io.Writer, name string
142148
return "", tryExecFormatErr(fmt.Errorf("running build: %w", err), errBuffer)
143149
}
144150

145-
return b.localDocker.ImageID(ctx, opts.Tag)
151+
if b.buildx {
152+
return "", nil // TODO: return id from CLI
153+
} else {
154+
return b.localDocker.ImageID(ctx, opts.Tag)
155+
}
146156
}
147157

148158
func (b *Builder) pullCacheFromImages(ctx context.Context, out io.Writer, a *latest.DockerArtifact, pl v1.Platform) error {

pkg/skaffold/build/docker/docker_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func TestDockerCLIBuild(t *testing.T) {
161161
}
162162
t.Override(&util.OSEnviron, func() []string { return []string{"KEY=VALUE"} })
163163

164-
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv(test.extraEnv), test.cfg, test.localBuild.UseDockerCLI, test.localBuild.UseBuildkit, false, mockArtifactResolver{make(map[string]string)}, nil)
164+
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv(test.extraEnv), test.cfg, test.localBuild.UseDockerCLI, false, test.localBuild.UseBuildkit, false, mockArtifactResolver{make(map[string]string)}, nil)
165165

166166
artifact := &latest.Artifact{
167167
Workspace: ".",
@@ -242,7 +242,7 @@ func TestDockerCLICheckCacheFromArgs(t *testing.T) {
242242
)
243243
t.Override(&util.DefaultExecCommand, mockCmd)
244244

245-
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv([]string{}), mockConfig{}, true, util.Ptr(false), false, mockArtifactResolver{make(map[string]string)}, nil)
245+
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv([]string{}), mockConfig{}, true, false, util.Ptr(false), false, mockArtifactResolver{make(map[string]string)}, nil)
246246
_, err := builder.Build(context.Background(), io.Discard, &a, test.tag, platform.Matcher{})
247247
t.CheckNoError(err)
248248
})

pkg/skaffold/build/docker/errors_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Refer https://skaffold.dev/docs/references/yaml/#build-artifacts-docker for deta
6060
"docker build . --file "+dockerfilePath+" -t tag",
6161
))
6262
t.Override(&docker.DefaultAuthHelper, stubAuth{})
63-
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv([]string{}), mockConfig{}, true, nil, false, mockArtifactResolver{make(map[string]string)}, nil)
63+
builder := NewArtifactBuilder(fakeLocalDaemonWithExtraEnv([]string{}), mockConfig{}, true, false, nil, false, mockArtifactResolver{make(map[string]string)}, nil)
6464

6565
artifact := &latest.Artifact{
6666
ImageName: "test-image",

pkg/skaffold/build/docker/types.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ type Builder struct {
2929
cfg docker.Config
3030
pushImages bool
3131
useCLI bool
32+
buildx bool
3233
useBuildKit *bool
3334
artifacts ArtifactResolver
3435
sourceDependencies TransitiveSourceDependenciesResolver
@@ -45,12 +46,13 @@ type TransitiveSourceDependenciesResolver interface {
4546
}
4647

4748
// NewBuilder returns an new instance of a docker builder
48-
func NewArtifactBuilder(localDocker docker.LocalDaemon, cfg docker.Config, useCLI bool, useBuildKit *bool, pushImages bool, ar ArtifactResolver, dr TransitiveSourceDependenciesResolver) *Builder {
49+
func NewArtifactBuilder(localDocker docker.LocalDaemon, cfg docker.Config, useCLI bool, buildx bool, useBuildKit *bool, pushImages bool, ar ArtifactResolver, dr TransitiveSourceDependenciesResolver) *Builder {
4950
return &Builder{
5051
localDocker: localDocker,
5152
pushImages: pushImages,
5253
cfg: cfg,
5354
useCLI: useCLI,
55+
buildx: buildx,
5456
useBuildKit: useBuildKit,
5557
artifacts: ar,
5658
sourceDependencies: dr,

pkg/skaffold/build/local/local.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,16 @@ func (b *Builder) buildArtifact(ctx context.Context, out io.Writer, a *latest.Ar
9090

9191
imageID := digestOrImageID
9292
b.builtImages = append(b.builtImages, imageID)
93-
return build.TagWithImageID(ctx, tag, imageID, b.localDocker)
93+
94+
if b.local.Buildx {
95+
return "", nil
96+
} else {
97+
return build.TagWithImageID(ctx, tag, imageID, b.localDocker)
98+
}
9499
}
95100

96101
func (b *Builder) runBuildForArtifact(ctx context.Context, out io.Writer, a *latest.Artifact, tag string, platforms platform.Matcher) (string, error) {
97-
if !b.pushImages {
102+
if !b.local.Buildx && !b.pushImages {
98103
// All of the builders will rely on a local Docker:
99104
// + Either to build the image,
100105
// + Or to docker load it.

pkg/skaffold/build/local/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ type artifactBuilder interface {
148148
func newPerArtifactBuilder(b *Builder, a *latest.Artifact) (artifactBuilder, error) {
149149
switch {
150150
case a.DockerArtifact != nil:
151-
return dockerbuilder.NewArtifactBuilder(b.localDocker, b.cfg, b.local.UseDockerCLI, b.local.UseBuildkit, b.pushImages, b.artifactStore, b.sourceDependencies), nil
151+
return dockerbuilder.NewArtifactBuilder(b.localDocker, b.cfg, b.local.UseDockerCLI, b.local.Buildx, b.local.UseBuildkit, b.pushImages, b.artifactStore, b.sourceDependencies), nil
152152

153153
case a.BazelArtifact != nil:
154154
return bazel.NewArtifactBuilder(b.localDocker, b.cfg, b.pushImages), nil

pkg/skaffold/schema/latest/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ type LocalBuild struct {
311311
// UseDockerCLI use `docker` command-line interface instead of Docker Engine APIs.
312312
UseDockerCLI bool `yaml:"useDockerCLI,omitempty"`
313313

314+
Buildx bool `yaml:"buildx,omitempty"`
315+
314316
// UseBuildkit use BuildKit to build Docker images. If unspecified, uses the Docker default.
315317
UseBuildkit *bool `yaml:"useBuildkit,omitempty"`
316318

0 commit comments

Comments
 (0)