mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-20 17:49:10 +00:00
Allow store to docker multiarch builds
We do not allow to load into docker images that are targets another platform differ from current arch. Assume this is because of no support of manifest. But we can keep all images in place by adding arch suffix and using tag without arch suffix to point onto current system arch. It will help to use images from docker for another arch. Signed-off-by: Petr Fedchenkov <giggsoff@gmail.com>
This commit is contained in:
parent
44dfac2725
commit
39f1649995
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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: ®istry.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}, ""},
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user