Merge pull request #30 from infosiftr/scratch-platform

Set DOCKER_DEFAULT_PLATFORM when building "FROM scratch" images
This commit is contained in:
yosifkit 2021-08-02 15:25:28 -07:00 committed by GitHub
commit 3ebdb4c18f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 3 deletions

View File

@ -1,5 +1,7 @@
package architecture package architecture
import "path"
// https://github.com/opencontainers/image-spec/blob/v1.0.1/image-index.md#image-index-property-descriptions // https://github.com/opencontainers/image-spec/blob/v1.0.1/image-index.md#image-index-property-descriptions
// see "platform" (under "manifests") // see "platform" (under "manifests")
type OCIPlatform struct { type OCIPlatform struct {
@ -25,3 +27,12 @@ var SupportedArches = map[string]OCIPlatform{
"windows-amd64": {OS: "windows", Architecture: "amd64"}, "windows-amd64": {OS: "windows", Architecture: "amd64"},
} }
// https://pkg.go.dev/github.com/containerd/containerd/platforms
func (p OCIPlatform) String() string {
return path.Join(
p.OS,
p.Architecture,
p.Variant,
)
}

View File

@ -48,7 +48,9 @@ func cmdBuild(c *cli.Context) error {
return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }
fromScratch := false
for _, from := range froms { for _, from := range froms {
fromScratch = fromScratch || from == "scratch"
if from != "scratch" && pull != "never" { if from != "scratch" && pull != "never" {
doPull := false doPull := false
switch pull { switch pull {
@ -93,7 +95,14 @@ 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) // 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)
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive) 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 { if err != nil {
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err) return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
} }

View File

@ -237,10 +237,16 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
return uniqueBits, nil return uniqueBits, nil
} }
func dockerBuild(tag string, file string, context io.Reader) error { func dockerBuild(tag string, file string, context io.Reader, extraEnv []string) error {
args := []string{"build", "-t", tag, "-f", file, "--rm", "--force-rm"} args := []string{"build", "--tag", tag, "--file", file, "--rm", "--force-rm"}
args = append(args, "-") args = append(args, "-")
cmd := exec.Command("docker", args...) cmd := exec.Command("docker", args...)
if extraEnv != nil {
cmd.Env = append(os.Environ(), extraEnv...)
if debugFlag {
fmt.Printf("$ export %q\n", extraEnv)
}
}
cmd.Stdin = context cmd.Stdin = context
if debugFlag { if debugFlag {
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout

View File

@ -8,6 +8,7 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/docker-library/bashbrew/architecture"
"github.com/docker-library/bashbrew/manifest" "github.com/docker-library/bashbrew/manifest"
) )
@ -22,6 +23,7 @@ var (
defaultCache string defaultCache string
arch string arch string
ociArch architecture.OCIPlatform
namespace string namespace string
constraints []string constraints []string
exclusiveConstraints bool exclusiveConstraints bool
@ -166,6 +168,11 @@ func main() {
constraints = c.GlobalStringSlice("constraint") constraints = c.GlobalStringSlice("constraint")
exclusiveConstraints = c.GlobalBool("exclusive-constraints") exclusiveConstraints = c.GlobalBool("exclusive-constraints")
var ok bool
if ociArch, ok = architecture.SupportedArches[arch]; !ok {
return fmt.Errorf("invalid architecture: %q", arch)
}
archNamespaces = map[string]string{} archNamespaces = map[string]string{}
for _, archMapping := range c.GlobalStringSlice("arch-namespace") { for _, archMapping := range c.GlobalStringSlice("arch-namespace") {
splitArchMapping := strings.SplitN(archMapping, "=", 2) splitArchMapping := strings.SplitN(archMapping, "=", 2)