Skip to content

Commit f09bb95

Browse files
authored
Merge pull request #43 from jedevc/docker-buildx
Buildkit support with buildx
2 parents cb56081 + bf91869 commit f09bb95

File tree

3 files changed

+93
-17
lines changed

3 files changed

+93
-17
lines changed

cmd/bashbrew/cmd-build.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,27 @@ func cmdBuild(c *cli.Context) error {
9595

9696
// TODO use "meta.StageNames" to do "docker build --target" so we can tag intermediate stages too for cache (streaming "git archive" directly to "docker build" makes that a little hard to accomplish without re-streaming)
9797

98-
var extraEnv []string = nil
99-
if fromScratch {
100-
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
101-
extraEnv = []string{"DOCKER_DEFAULT_PLATFORM=" + ociArch.String()}
102-
// ideally, we would set this via an explicit "--platform" flag on "docker build", but it's not supported without buildkit until 20.10+ and this is a trivial way to get Docker to do the right thing in both cases without explicitly trying to detect whether we're on 20.10+
103-
}
104-
105-
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, extraEnv)
106-
if err != nil {
107-
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
98+
switch builder := entry.ArchBuilder(arch); builder {
99+
case "classic", "":
100+
var platform string
101+
if fromScratch {
102+
platform = ociArch.String()
103+
}
104+
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, platform)
105+
if err != nil {
106+
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
107+
}
108+
case "buildkit":
109+
var platform string
110+
if fromScratch {
111+
platform = ociArch.String()
112+
}
113+
err = dockerBuildxBuild(cacheTag, entry.ArchFile(arch), archive, platform)
114+
if err != nil {
115+
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
116+
}
117+
default:
118+
return cli.NewMultiError(fmt.Errorf(`unknown builder %q`, builder))
108119
}
109120
archive.Close() // be sure this happens sooner rather than later (defer might take a while, and we want to reap zombies more aggressively)
110121
}

cmd/bashbrew/docker.go

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
"strconv"
1414
"strings"
1515

16-
"github.com/urfave/cli"
1716
"github.com/docker-library/bashbrew/manifest"
17+
"github.com/urfave/cli"
1818
)
1919

2020
type dockerfileMetadata struct {
@@ -218,6 +218,11 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
218218
entry.ArchDirectory(arch),
219219
entry.ArchFile(arch),
220220
}
221+
if builder := entry.ArchBuilder(arch); builder != "" {
222+
// NOTE: preserve long-term unique id by only attaching builder if
223+
// explicitly specified
224+
uniqueBits = append(uniqueBits, entry.ArchBuilder(arch))
225+
}
221226
meta, err := r.dockerfileMetadata(entry)
222227
if err != nil {
223228
return nil, err
@@ -237,14 +242,20 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
237242
return uniqueBits, nil
238243
}
239244

240-
func dockerBuild(tag string, file string, context io.Reader, extraEnv []string) error {
245+
func dockerBuild(tag string, file string, context io.Reader, platform string) error {
241246
args := []string{"build", "--tag", tag, "--file", file, "--rm", "--force-rm"}
242247
args = append(args, "-")
243248
cmd := exec.Command("docker", args...)
244-
if extraEnv != nil {
245-
cmd.Env = append(os.Environ(), extraEnv...)
249+
cmd.Env = append(os.Environ(), "DOCKER_BUILDKIT=0")
250+
if debugFlag {
251+
fmt.Println("$ export DOCKER_BUILDKIT=0")
252+
}
253+
if platform != "" {
254+
// ideally, we would set this via an explicit "--platform" flag on "docker build", but it's not supported without buildkit until 20.10+ and this is a trivial way to get Docker to do the right thing in both cases without explicitly trying to detect whether we're on 20.10+
255+
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
256+
cmd.Env = append(cmd.Env, "DOCKER_DEFAULT_PLATFORM="+platform)
246257
if debugFlag {
247-
fmt.Printf("$ export %q\n", extraEnv)
258+
fmt.Printf("$ export DOCKER_DEFAULT_PLATFORM=%q\n", platform)
248259
}
249260
}
250261
cmd.Stdin = context
@@ -265,6 +276,46 @@ func dockerBuild(tag string, file string, context io.Reader, extraEnv []string)
265276
}
266277
}
267278

279+
const dockerfileSyntaxEnv = "BASHBREW_BUILDKIT_SYNTAX"
280+
281+
func dockerBuildxBuild(tag string, file string, context io.Reader, platform string) error {
282+
dockerfileSyntax, ok := os.LookupEnv(dockerfileSyntaxEnv)
283+
if !ok {
284+
return fmt.Errorf("missing %q", dockerfileSyntaxEnv)
285+
}
286+
287+
args := []string{
288+
"buildx",
289+
"build",
290+
"--progress", "plain",
291+
"--build-arg", "BUILDKIT_SYNTAX=" + dockerfileSyntax,
292+
"--tag", tag,
293+
"--file", file,
294+
}
295+
if platform != "" {
296+
args = append(args, "--platform", platform)
297+
}
298+
args = append(args, "-")
299+
300+
cmd := exec.Command("docker", args...)
301+
cmd.Stdin = context
302+
if debugFlag {
303+
cmd.Stdout = os.Stdout
304+
cmd.Stderr = os.Stderr
305+
fmt.Printf("$ docker %q\n", args)
306+
return cmd.Run()
307+
} else {
308+
buf := &bytes.Buffer{}
309+
cmd.Stdout = buf
310+
cmd.Stderr = buf
311+
err := cmd.Run()
312+
if err != nil {
313+
err = cli.NewMultiError(err, fmt.Errorf(`docker %q output:%s`, args, "\n"+buf.String()))
314+
}
315+
return err
316+
}
317+
}
318+
268319
func dockerTag(tag1 string, tag2 string) error {
269320
if debugFlag {
270321
fmt.Printf("$ docker tag %q %q\n", tag1, tag2)

manifest/rfc2822.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ type Manifest2822Entry struct {
4343
GitCommit string
4444
Directory string
4545
File string
46+
Builder string
4647

4748
// architecture-specific versions of the above fields
4849
ArchValues map[string]string
@@ -93,7 +94,7 @@ func (entry Manifest2822Entry) Clone() Manifest2822Entry {
9394

9495
func (entry *Manifest2822Entry) SeedArchValues() {
9596
for field, val := range entry.Paragraph.Values {
96-
if strings.HasSuffix(field, "-GitRepo") || strings.HasSuffix(field, "-GitFetch") || strings.HasSuffix(field, "-GitCommit") || strings.HasSuffix(field, "-Directory") || strings.HasSuffix(field, "-File") {
97+
if strings.HasSuffix(field, "-GitRepo") || strings.HasSuffix(field, "-GitFetch") || strings.HasSuffix(field, "-GitCommit") || strings.HasSuffix(field, "-Directory") || strings.HasSuffix(field, "-File") || strings.HasSuffix(field, "-Builder") {
9798
entry.ArchValues[field] = val
9899
}
99100
}
@@ -142,7 +143,7 @@ func (a Manifest2822Entry) SameBuildArtifacts(b Manifest2822Entry) bool {
142143
}
143144
}
144145

145-
return a.ArchitecturesString() == b.ArchitecturesString() && a.GitRepo == b.GitRepo && a.GitFetch == b.GitFetch && a.GitCommit == b.GitCommit && a.Directory == b.Directory && a.File == b.File && a.ConstraintsString() == b.ConstraintsString()
146+
return a.ArchitecturesString() == b.ArchitecturesString() && a.GitRepo == b.GitRepo && a.GitFetch == b.GitFetch && a.GitCommit == b.GitCommit && a.Directory == b.Directory && a.File == b.File && a.Builder == b.Builder && a.ConstraintsString() == b.ConstraintsString()
146147
}
147148

148149
// returns a list of architecture-specific fields in an Entry
@@ -187,6 +188,9 @@ func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifes
187188
if entry.File == defaults.File {
188189
entry.File = ""
189190
}
191+
if entry.Builder == defaults.Builder {
192+
entry.Builder = ""
193+
}
190194
for _, key := range defaults.archFields() {
191195
if defaults.ArchValues[key] == entry.ArchValues[key] {
192196
delete(entry.ArchValues, key)
@@ -227,6 +231,9 @@ func (entry Manifest2822Entry) String() string {
227231
if str := entry.File; str != "" {
228232
ret = append(ret, "File: "+str)
229233
}
234+
if str := entry.Builder; str != "" {
235+
ret = append(ret, "Builder: "+str)
236+
}
230237
for _, key := range entry.archFields() {
231238
ret = append(ret, key+": "+entry.ArchValues[key])
232239
}
@@ -300,6 +307,13 @@ func (entry Manifest2822Entry) ArchFile(arch string) string {
300307
return entry.File
301308
}
302309

310+
func (entry Manifest2822Entry) ArchBuilder(arch string) string {
311+
if val, ok := entry.ArchValues[arch+"-Builder"]; ok && val != "" {
312+
return val
313+
}
314+
return entry.Builder
315+
}
316+
303317
func (entry Manifest2822Entry) HasTag(tag string) bool {
304318
for _, existingTag := range entry.Tags {
305319
if tag == existingTag {

0 commit comments

Comments
 (0)