mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 18:11:35 +00:00
Push arch-specific tags, always build index from registry
Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
parent
79b32dc2c7
commit
df36b7aa7d
102
src/cmd/linuxkit/cache/push.go
vendored
102
src/cmd/linuxkit/cache/push.go
vendored
@ -7,65 +7,9 @@ import (
|
||||
namepkg "github.com/google/go-containerregistry/pkg/name"
|
||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/registry"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PushWithManifest push an image along with, optionally, a multi-arch index.
|
||||
func (p *Provider) PushWithManifest(name, suffix string, pushImage, pushManifest bool) error {
|
||||
var (
|
||||
err error
|
||||
options []remote.Option
|
||||
)
|
||||
imageName := name + suffix
|
||||
ref, err := namepkg.ParseReference(imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if pushImage {
|
||||
fmt.Printf("Pushing %s\n", imageName)
|
||||
// do we even have the given one?
|
||||
root, err := p.FindRoot(imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options = append(options, remote.WithAuthFromKeychain(authn.DefaultKeychain))
|
||||
img, err1 := root.Image()
|
||||
ii, err2 := root.ImageIndex()
|
||||
switch {
|
||||
case err1 == nil:
|
||||
if err := remote.Write(ref, img, options...); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Pushed image %s\n", imageName)
|
||||
case err2 == nil:
|
||||
if err := remote.WriteIndex(ref, ii, options...); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Pushed index %s\n", imageName)
|
||||
default:
|
||||
return fmt.Errorf("name %s unknown in cache", imageName)
|
||||
}
|
||||
} else {
|
||||
fmt.Print("Image push disabled, skipping...\n")
|
||||
}
|
||||
|
||||
auth, err := registry.GetDockerAuth()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get auth: %v", err)
|
||||
}
|
||||
|
||||
if pushManifest {
|
||||
fmt.Printf("Pushing %s to manifest %s\n", imageName, name)
|
||||
_, _, err = registry.PushManifest(name, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fmt.Print("Manifest push disabled, skipping...\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Push push an image along with a multi-arch index.
|
||||
func (p *Provider) Push(name string) error {
|
||||
var (
|
||||
@ -88,17 +32,61 @@ func (p *Provider) Push(name string) error {
|
||||
ii, err2 := root.ImageIndex()
|
||||
switch {
|
||||
case err1 == nil:
|
||||
log.Debugf("pushing image %s", name)
|
||||
if err := remote.Write(ref, img, options...); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Pushed image %s\n", name)
|
||||
case err2 == nil:
|
||||
log.Debugf("pushing index %s", name)
|
||||
// this is an index, so we not only want to write the index, but tags for each arch-specific image in it
|
||||
if err := remote.WriteIndex(ref, ii, options...); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Pushed index %s\n", name)
|
||||
manifest, err := ii.IndexManifest()
|
||||
if err != nil {
|
||||
return fmt.Errorf("successfully pushed index, but could not read images in index: %v", err)
|
||||
}
|
||||
log.Debugf("pushing individual images in the index %s", name)
|
||||
for _, m := range manifest.Manifests {
|
||||
if m.Platform == nil || m.Platform.Architecture == "" {
|
||||
continue
|
||||
}
|
||||
archTag := fmt.Sprintf("%s-%s", name, m.Platform.Architecture)
|
||||
tag, err := namepkg.NewTag(archTag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create a valid arch-specific tag %s: %v", archTag, err)
|
||||
}
|
||||
image, err := p.FindRoot(archTag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find arch-specific image in cache %s: %v", archTag, err)
|
||||
}
|
||||
img, err := image.Image()
|
||||
if err != nil {
|
||||
return fmt.Errorf("found arch-specific image in cache %s, but could not resolve to actual image: %v", archTag, err)
|
||||
}
|
||||
log.Debugf("pushing image %s", tag)
|
||||
if err := remote.Tag(tag, img, options...); err != nil {
|
||||
return fmt.Errorf("error creating tag %s: %v", archTag, err)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("name %s unknown in cache", name)
|
||||
}
|
||||
|
||||
// Even though we may have pushed the index, we want to be sure that we have an index that includes every architecture on the registry,
|
||||
// not just those that were in our local cache. So we use manifest-tool library to build a broad index
|
||||
auth, err := registry.GetDockerAuth()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get auth: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Pushing index based on all arch-specific images in registry %s\n", name)
|
||||
_, _, err = registry.PushManifest(name, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -11,15 +11,23 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var platforms = []string{
|
||||
"linux/amd64", "linux/arm64", "linux/s390x",
|
||||
// these platforms are used only as the source for registry.PushManifestList(). Since it is
|
||||
// configured to ignore missing, we could include dozens if we wanted; it doesn't hurt, adding maybe a few seconds to
|
||||
// the whole run.
|
||||
// Ideally, we could just look for all tags that start with linuxkit/foo:<hash>-*, but the registry API
|
||||
// only supports "list all the tags" and "get a specific tag", no "get by pattern". The "get a specific tag"
|
||||
// is exactly what registry.PushManifestList() uses, so no benefit to use doing that in advance,
|
||||
// while "list all tags" is slow, and has to cycle through all of the (growing numbers of) tags
|
||||
// before we know what exists. Might as well leave it as is.
|
||||
var platformsToSearchForIndex = []string{
|
||||
"linux/amd64", "linux/arm64", "linux/s390x", "linux/riscv64", "linux/ppc64le",
|
||||
}
|
||||
|
||||
// PushManifest create a manifest that supports each of the provided platforms and push it out.
|
||||
func PushManifest(img string, auth dockertypes.AuthConfig) (hash string, length int, err error) {
|
||||
srcImages := []types.ManifestEntry{}
|
||||
|
||||
for i, platform := range platforms {
|
||||
for i, platform := range platformsToSearchForIndex {
|
||||
osArchArr := strings.Split(platform, "/")
|
||||
if len(osArchArr) != 2 && len(osArchArr) != 3 {
|
||||
return hash, length, fmt.Errorf("platform argument %d is not of form 'os/arch': '%s'", i, platform)
|
||||
|
Loading…
Reference in New Issue
Block a user