mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-20 17:49:10 +00:00
Merge pull request #3688 from deitch/manifest-anywhere
Push arch-specific tags, always build index from registry
This commit is contained in:
commit
acc34e5ee3
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"
|
namepkg "github.com/google/go-containerregistry/pkg/name"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
"github.com/linuxkit/linuxkit/src/cmd/linuxkit/registry"
|
"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.
|
// Push push an image along with a multi-arch index.
|
||||||
func (p *Provider) Push(name string) error {
|
func (p *Provider) Push(name string) error {
|
||||||
var (
|
var (
|
||||||
@ -88,17 +32,61 @@ func (p *Provider) Push(name string) error {
|
|||||||
ii, err2 := root.ImageIndex()
|
ii, err2 := root.ImageIndex()
|
||||||
switch {
|
switch {
|
||||||
case err1 == nil:
|
case err1 == nil:
|
||||||
|
log.Debugf("pushing image %s", name)
|
||||||
if err := remote.Write(ref, img, options...); err != nil {
|
if err := remote.Write(ref, img, options...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Pushed image %s\n", name)
|
fmt.Printf("Pushed image %s\n", name)
|
||||||
case err2 == nil:
|
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 {
|
if err := remote.WriteIndex(ref, ii, options...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Printf("Pushed index %s\n", name)
|
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:
|
default:
|
||||||
return fmt.Errorf("name %s unknown in cache", name)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,23 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var platforms = []string{
|
// these platforms are used only as the source for registry.PushManifestList(). Since it is
|
||||||
"linux/amd64", "linux/arm64", "linux/s390x",
|
// 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.
|
// 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) {
|
func PushManifest(img string, auth dockertypes.AuthConfig) (hash string, length int, err error) {
|
||||||
srcImages := []types.ManifestEntry{}
|
srcImages := []types.ManifestEntry{}
|
||||||
|
|
||||||
for i, platform := range platforms {
|
for i, platform := range platformsToSearchForIndex {
|
||||||
osArchArr := strings.Split(platform, "/")
|
osArchArr := strings.Split(platform, "/")
|
||||||
if len(osArchArr) != 2 && len(osArchArr) != 3 {
|
if len(osArchArr) != 2 && len(osArchArr) != 3 {
|
||||||
return hash, length, fmt.Errorf("platform argument %d is not of form 'os/arch': '%s'", i, platform)
|
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