Skip to content

Commit

Permalink
Merge pull request #43 from jedevc/docker-buildx
Browse files Browse the repository at this point in the history
Buildkit support with buildx
  • Loading branch information
yosifkit authored Sep 23, 2022
2 parents cb56081 + bf91869 commit f09bb95
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 17 deletions.
31 changes: 21 additions & 10 deletions cmd/bashbrew/cmd-build.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,27 @@ func cmdBuild(c *cli.Context) error {

// 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)

var extraEnv []string = nil
if fromScratch {
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
extraEnv = []string{"DOCKER_DEFAULT_PLATFORM=" + ociArch.String()}
// 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+
}

err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, extraEnv)
if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
switch builder := entry.ArchBuilder(arch); builder {
case "classic", "":
var platform string
if fromScratch {
platform = ociArch.String()
}
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, platform)
if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
}
case "buildkit":
var platform string
if fromScratch {
platform = ociArch.String()
}
err = dockerBuildxBuild(cacheTag, entry.ArchFile(arch), archive, platform)
if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
}
default:
return cli.NewMultiError(fmt.Errorf(`unknown builder %q`, builder))
}
archive.Close() // be sure this happens sooner rather than later (defer might take a while, and we want to reap zombies more aggressively)
}
Expand Down
61 changes: 56 additions & 5 deletions cmd/bashbrew/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
"strconv"
"strings"

"github.com/urfave/cli"
"github.com/docker-library/bashbrew/manifest"
"github.com/urfave/cli"
)

type dockerfileMetadata struct {
Expand Down Expand Up @@ -218,6 +218,11 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
entry.ArchDirectory(arch),
entry.ArchFile(arch),
}
if builder := entry.ArchBuilder(arch); builder != "" {
// NOTE: preserve long-term unique id by only attaching builder if
// explicitly specified
uniqueBits = append(uniqueBits, entry.ArchBuilder(arch))
}
meta, err := r.dockerfileMetadata(entry)
if err != nil {
return nil, err
Expand All @@ -237,14 +242,20 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
return uniqueBits, nil
}

func dockerBuild(tag string, file string, context io.Reader, extraEnv []string) error {
func dockerBuild(tag string, file string, context io.Reader, platform string) error {
args := []string{"build", "--tag", tag, "--file", file, "--rm", "--force-rm"}
args = append(args, "-")
cmd := exec.Command("docker", args...)
if extraEnv != nil {
cmd.Env = append(os.Environ(), extraEnv...)
cmd.Env = append(os.Environ(), "DOCKER_BUILDKIT=0")
if debugFlag {
fmt.Println("$ export DOCKER_BUILDKIT=0")
}
if platform != "" {
// 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+
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
cmd.Env = append(cmd.Env, "DOCKER_DEFAULT_PLATFORM="+platform)
if debugFlag {
fmt.Printf("$ export %q\n", extraEnv)
fmt.Printf("$ export DOCKER_DEFAULT_PLATFORM=%q\n", platform)
}
}
cmd.Stdin = context
Expand All @@ -265,6 +276,46 @@ func dockerBuild(tag string, file string, context io.Reader, extraEnv []string)
}
}

const dockerfileSyntaxEnv = "BASHBREW_BUILDKIT_SYNTAX"

func dockerBuildxBuild(tag string, file string, context io.Reader, platform string) error {
dockerfileSyntax, ok := os.LookupEnv(dockerfileSyntaxEnv)
if !ok {
return fmt.Errorf("missing %q", dockerfileSyntaxEnv)
}

args := []string{
"buildx",
"build",
"--progress", "plain",
"--build-arg", "BUILDKIT_SYNTAX=" + dockerfileSyntax,
"--tag", tag,
"--file", file,
}
if platform != "" {
args = append(args, "--platform", platform)
}
args = append(args, "-")

cmd := exec.Command("docker", args...)
cmd.Stdin = context
if debugFlag {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
fmt.Printf("$ docker %q\n", args)
return cmd.Run()
} else {
buf := &bytes.Buffer{}
cmd.Stdout = buf
cmd.Stderr = buf
err := cmd.Run()
if err != nil {
err = cli.NewMultiError(err, fmt.Errorf(`docker %q output:%s`, args, "\n"+buf.String()))
}
return err
}
}

func dockerTag(tag1 string, tag2 string) error {
if debugFlag {
fmt.Printf("$ docker tag %q %q\n", tag1, tag2)
Expand Down
18 changes: 16 additions & 2 deletions manifest/rfc2822.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Manifest2822Entry struct {
GitCommit string
Directory string
File string
Builder string

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

func (entry *Manifest2822Entry) SeedArchValues() {
for field, val := range entry.Paragraph.Values {
if strings.HasSuffix(field, "-GitRepo") || strings.HasSuffix(field, "-GitFetch") || strings.HasSuffix(field, "-GitCommit") || strings.HasSuffix(field, "-Directory") || strings.HasSuffix(field, "-File") {
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") {
entry.ArchValues[field] = val
}
}
Expand Down Expand Up @@ -142,7 +143,7 @@ func (a Manifest2822Entry) SameBuildArtifacts(b Manifest2822Entry) bool {
}
}

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()
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()
}

// returns a list of architecture-specific fields in an Entry
Expand Down Expand Up @@ -187,6 +188,9 @@ func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifes
if entry.File == defaults.File {
entry.File = ""
}
if entry.Builder == defaults.Builder {
entry.Builder = ""
}
for _, key := range defaults.archFields() {
if defaults.ArchValues[key] == entry.ArchValues[key] {
delete(entry.ArchValues, key)
Expand Down Expand Up @@ -227,6 +231,9 @@ func (entry Manifest2822Entry) String() string {
if str := entry.File; str != "" {
ret = append(ret, "File: "+str)
}
if str := entry.Builder; str != "" {
ret = append(ret, "Builder: "+str)
}
for _, key := range entry.archFields() {
ret = append(ret, key+": "+entry.ArchValues[key])
}
Expand Down Expand Up @@ -300,6 +307,13 @@ func (entry Manifest2822Entry) ArchFile(arch string) string {
return entry.File
}

func (entry Manifest2822Entry) ArchBuilder(arch string) string {
if val, ok := entry.ArchValues[arch+"-Builder"]; ok && val != "" {
return val
}
return entry.Builder
}

func (entry Manifest2822Entry) HasTag(tag string) bool {
for _, existingTag := range entry.Tags {
if tag == existingTag {
Expand Down

0 comments on commit f09bb95

Please sign in to comment.