Merge pull request #3804 from giggsoff/allow-docker-multiarch

Allow store to docker multiarch builds
This commit is contained in:
Avi Deitcher 2022-07-18 19:08:26 +03:00 committed by GitHub
commit 4e7f87e1ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 35 deletions

View File

@ -191,20 +191,6 @@ func (p Pkg) Build(bos ...BuildOpt) error {
return errors.New("must provide linuxkit build cache directory")
}
// if targeting docker, be sure local arch is a build target
if bo.targetDocker {
var found bool
for _, platform := range bo.platforms {
if platform.Architecture == arch {
found = true
break
}
}
if !found {
return fmt.Errorf("must build for local platform 'linux/%s' when targeting docker", arch)
}
}
if p.git != nil && bo.push && bo.release == "" {
r, err := p.git.commitTag("HEAD")
if err != nil {
@ -243,6 +229,24 @@ func (p Pkg) Build(bos ...BuildOpt) error {
} else {
fmt.Fprintf(writer, "%s not found\n", ref)
}
if bo.targetDocker {
notFound := false
for _, platform := range bo.platforms {
archRef, err := reference.Parse(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture))
if err != nil {
return err
}
fmt.Fprintf(writer, "checking for %s in local cache, fallback to remote registry...\n", archRef)
if _, err := c.ImagePull(&archRef, "", platform.Architecture, false); err == nil {
fmt.Fprintf(writer, "%s found or pulled\n", archRef)
skipBuild = true
} else {
fmt.Fprintf(writer, "%s not found\n", archRef)
notFound = true
}
}
skipBuild = skipBuild && !notFound
}
}
if !skipBuild {
@ -327,14 +331,28 @@ func (p Pkg) Build(bos ...BuildOpt) error {
}
// if requested docker, load the image up
// we will store images with arch suffix, i.e. -amd64
// if one of the arch equals with system, we will add tag without suffix
if bo.targetDocker {
cacheSource := c.NewSource(&ref, arch, desc)
reader, err := cacheSource.V1TarReader()
if err != nil {
return fmt.Errorf("unable to get reader from cache: %v", err)
}
if err := d.load(reader); err != nil {
return err
for _, platform := range bo.platforms {
archRef, err := reference.Parse(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture))
if err != nil {
return err
}
cacheSource := c.NewSource(&archRef, platform.Architecture, desc)
reader, err := cacheSource.V1TarReader()
if err != nil {
return fmt.Errorf("unable to get reader from cache: %v", err)
}
if err := d.load(reader); err != nil {
return err
}
if platform.Architecture == arch {
err = d.tag(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture), p.FullTag())
if err != nil {
return err
}
}
}
}
@ -375,9 +393,18 @@ func (p Pkg) Build(bos ...BuildOpt) error {
}
// tag in docker, if requested
// will tag all images with arch suffix
// if one of the arch equals with system will add tag without suffix
if bo.targetDocker {
if err := d.tag(p.FullTag(), fullRelTag); err != nil {
return err
for _, platform := range bo.platforms {
if err := d.tag(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture), fmt.Sprintf("%s-%s", fullRelTag, platform.Architecture)); err != nil {
return err
}
if platform.Architecture == arch {
if err := d.tag(fmt.Sprintf("%s-%s", p.FullTag(), platform.Architecture), fullRelTag); err != nil {
return err
}
}
}
}

View File

@ -9,7 +9,6 @@ import (
"io"
"io/ioutil"
"math/rand"
"runtime"
"strings"
"testing"
@ -116,7 +115,7 @@ func (c *cacheMocker) ImageLoad(ref *reference.Spec, architecture string, r io.R
}
func (c *cacheMocker) imageWriteStream(ref *reference.Spec, architecture string, r io.Reader) (lktspec.ImageSource, error) {
image := ref.String()
image := fmt.Sprintf("%s-%s", ref.String(), architecture)
// make some random data for a layer
b, err := ioutil.ReadAll(r)
@ -154,10 +153,14 @@ func (c *cacheMocker) imageWriteStream(ref *reference.Spec, architecture string,
Annotations: map[string]string{
imagespec.AnnotationRefName: image,
},
Platform: &registry.Platform{
OS: "linux",
Architecture: architecture,
},
}
c.appendImage(image, desc)
return c.NewSource(ref, "", &desc), nil
return c.NewSource(ref, architecture, &desc), nil
}
func (c *cacheMocker) IndexWrite(ref *reference.Spec, descriptors ...registry.Descriptor) (lktspec.ImageSource, error) {
@ -273,7 +276,13 @@ func (c cacheMockerSource) TarReader() (io.ReadCloser, error) {
return nil, errors.New("unsupported")
}
func (c cacheMockerSource) V1TarReader() (io.ReadCloser, error) {
return nil, errors.New("unsupported")
_, found := c.c.images[c.ref.String()]
if !found {
return nil, fmt.Errorf("no image found with ref: %s", c.ref.String())
}
b := make([]byte, 256)
rand.Read(b)
return io.NopCloser(bytes.NewReader(b)), nil
}
func (c cacheMockerSource) Descriptor() *registry.Descriptor {
return c.descriptor
@ -281,14 +290,8 @@ func (c cacheMockerSource) Descriptor() *registry.Descriptor {
func TestBuild(t *testing.T) {
var (
nonLocal string
cacheDir = "somecachedir"
)
if runtime.GOARCH == "amd64" {
nonLocal = "arm64"
} else {
nonLocal = "amd64"
}
tests := []struct {
msg string
p Pkg
@ -302,7 +305,7 @@ func TestBuild(t *testing.T) {
{"not at head", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64"}, commitHash: "foo"}, nil, []string{"amd64"}, &dockerMocker{supportContexts: false}, &cacheMocker{}, "Cannot build from commit hash != HEAD"},
{"no build cache", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64"}, commitHash: "HEAD"}, nil, []string{"amd64"}, &dockerMocker{supportContexts: false}, &cacheMocker{}, "must provide linuxkit build cache"},
{"unsupported contexts", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir)}, []string{"amd64"}, &dockerMocker{supportContexts: false}, &cacheMocker{}, "contexts not supported, check docker version"},
{"load docker without local platform", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64", "arm64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir), WithBuildTargetDockerCache()}, []string{nonLocal}, &dockerMocker{supportContexts: false}, &cacheMocker{}, "must build for local platform"},
{"load docker without local platform", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64", "arm64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir), WithBuildTargetDockerCache()}, []string{"amd64", "arm64"}, &dockerMocker{supportContexts: true, enableBuild: true, images: map[string][]byte{}, enableTag: true}, &cacheMocker{enableImagePull: false, enableImageLoad: true, enableIndexWrite: true}, ""},
{"amd64", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64", "arm64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir)}, []string{"amd64"}, &dockerMocker{supportContexts: true, enableBuild: true}, &cacheMocker{enableImagePull: false, enableImageLoad: true, enableIndexWrite: true}, ""},
{"arm64", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64", "arm64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir)}, []string{"arm64"}, &dockerMocker{supportContexts: true, enableBuild: true}, &cacheMocker{enableImagePull: false, enableImageLoad: true, enableIndexWrite: true}, ""},
{"amd64 and arm64", Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64", "arm64"}, commitHash: "HEAD"}, []BuildOpt{WithBuildCacheDir(cacheDir)}, []string{"amd64", "arm64"}, &dockerMocker{supportContexts: true, enableBuild: true}, &cacheMocker{enableImagePull: false, enableImageLoad: true, enableIndexWrite: true}, ""},

View File

@ -288,7 +288,7 @@ func (dr *dockerRunnerImpl) builderEnsureContainer(ctx context.Context, name, im
}
// create the builder
args := []string{"container", "run", "-d", "--name", name, "--privileged", image, "--allow-insecure-entitlement", "network.host", "--addr", fmt.Sprintf("unix://%s", buildkitSocketPath), "--debug"}
msg := fmt.Sprintf("creating builder container '%s' in context '%s", name, dockerContext)
msg := fmt.Sprintf("creating builder container '%s' in context '%s'", name, dockerContext)
fmt.Println(msg)
if err := dr.command(nil, ioutil.Discard, ioutil.Discard, args...); err != nil {
return nil, err