Skip to content

Commit

Permalink
Merge pull request #3487 from AkihiroSuda/docker-v25-avoid-broken-oci
Browse files Browse the repository at this point in the history
`kind build node-image`: Support Docker v25.0.1
  • Loading branch information
k8s-ci-robot authored Jan 25, 2024
2 parents ad3437c + 10c59fd commit 3ff0e90
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 127 deletions.
33 changes: 23 additions & 10 deletions pkg/build/nodeimage/buildcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package nodeimage

import (
"fmt"
"io"
"math/rand"
"os"
"path"
Expand Down Expand Up @@ -185,13 +184,16 @@ func (c *buildContext) prePullImagesAndWriteManifests(bits kube.Bits, parsedVers
// correct set of built tags using the same logic we will use to rewrite
// the tags as we load the archives
fixedImages := sets.NewString()
fixedImagesMap := make(map[string]string, builtImages.Len()) // key: original images, value: fixed images
for _, image := range builtImages.List() {
registry, tag, err := docker.SplitImage(image)
if err != nil {
return nil, err
}
registry = fixRepository(registry)
fixedImages.Insert(registry + ":" + tag)
fixedImage := registry + ":" + tag
fixedImages.Insert(fixedImage)
fixedImagesMap[image] = fixedImage
}
builtImages = fixedImages
c.logger.V(1).Info("Detected built images: " + strings.Join(builtImages.List(), ", "))
Expand Down Expand Up @@ -286,14 +288,8 @@ func (c *buildContext) prePullImagesAndWriteManifests(bits kube.Bits, parsedVers
return err
}
defer f.Close()
//return importer.LoadCommand().SetStdout(os.Stdout).SetStderr(os.Stderr).SetStdin(f).Run()
// we will rewrite / correct the tags as we load the image
if err := exec.RunWithStdinWriter(importer.LoadCommand().SetStdout(os.Stdout).SetStderr(os.Stdout), func(w io.Writer) error {
return docker.EditArchive(f, w, fixRepository, c.arch)
}); err != nil {
return err
}
return nil
return importer.LoadCommand().SetStdout(os.Stdout).SetStderr(os.Stderr).SetStdin(f).Run()
// we will rewrite / correct the tags in tagFns below
})
}

Expand All @@ -303,6 +299,23 @@ func (c *buildContext) prePullImagesAndWriteManifests(bits kube.Bits, parsedVers
return nil, err
}

// create a plan of image re-tagging
tagFns := []func() error{}
for unfixed, fixed := range fixedImagesMap {
unfixed, fixed := unfixed, fixed // capture loop var
if unfixed != fixed {
tagFns = append(tagFns, func() error {
return importer.Tag(unfixed, fixed)
})
}
}

// run all image re-tragging concurrently until one fails or all succeed
if err := errors.UntilErrorConcurrent(tagFns); err != nil {
c.logger.Errorf("Image build Failed! Failed to re-tag images %v", err)
return nil, err
}

return importer.ListImported()
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/build/nodeimage/imageimporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ func (c *containerdImporter) LoadCommand() exec.Cmd {
)
}

func (c *containerdImporter) Tag(src, target string) error {
return c.containerCmder.Command(
"ctr", "--namespace=k8s.io", "images", "tag", "--force", src, target,
).Run()
}

func (c *containerdImporter) ListImported() ([]string, error) {
return exec.OutputLines(c.containerCmder.Command("ctr", "--namespace=k8s.io", "images", "list", "-q"))
}
117 changes: 0 additions & 117 deletions pkg/build/nodeimage/internal/container/docker/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"fmt"
"io"
"os"
"strings"

"sigs.k8s.io/kind/pkg/errors"
)
Expand Down Expand Up @@ -84,136 +83,20 @@ func GetArchiveTags(path string) ([]string, error) {
return res, nil
}

// EditArchive applies edit to reader's image repositories,
// IE the repository part of repository:tag in image tags
// This supports v1 / v1.1 / v1.2 Docker Image Archives
//
// editRepositories should be a function that returns the input or an edited
// form, where the input is the image repository
//
// https://github.com/moby/moby/blob/master/image/spec/v1.md
// https://github.com/moby/moby/blob/master/image/spec/v1.1.md
// https://github.com/moby/moby/blob/master/image/spec/v1.2.md
func EditArchive(reader io.Reader, writer io.Writer, editRepositories func(string) string, architectureOverride string) error {
tarReader := tar.NewReader(reader)
tarWriter := tar.NewWriter(writer)
// iterate all entries in the tarball
for {
// read an entry
hdr, err := tarReader.Next()
if err == io.EOF {
return tarWriter.Close()
} else if err != nil {
return err
}
b, err := io.ReadAll(tarReader)
if err != nil {
return err
}

// edit the repostories and manifests files when we find them
if hdr.Name == "repositories" {
b, err = editRepositoriesFile(b, editRepositories)
if err != nil {
return err
}
hdr.Size = int64(len(b))
} else if hdr.Name == "manifest.json" {
b, err = editManifestRepositories(b, editRepositories)
if err != nil {
return err
}
hdr.Size = int64(len(b))
// edit image config when we find that
} else if strings.HasSuffix(hdr.Name, ".json") {
if architectureOverride != "" {
b, err = editConfigArchitecture(b, architectureOverride)
if err != nil {
return err
}
hdr.Size = int64(len(b))
}
}

// write to the output tarball
if err := tarWriter.WriteHeader(hdr); err != nil {
return err
}
if len(b) > 0 {
if _, err := tarWriter.Write(b); err != nil {
return err
}
}
}
}

/* helpers */

func editConfigArchitecture(raw []byte, architectureOverride string) ([]byte, error) {
var cfg map[string]interface{}
if err := json.Unmarshal(raw, &cfg); err != nil {
return nil, err
}
const architecture = "architecture"
if _, ok := cfg[architecture]; !ok {
return raw, nil
}
cfg[architecture] = architectureOverride
return json.Marshal(cfg)
}

// archiveRepositories represents repository:tag:ref
//
// https://github.com/moby/moby/blob/master/image/spec/v1.md
// https://github.com/moby/moby/blob/master/image/spec/v1.1.md
// https://github.com/moby/moby/blob/master/image/spec/v1.2.md
type archiveRepositories map[string]map[string]string

func editRepositoriesFile(raw []byte, editRepositories func(string) string) ([]byte, error) {
tags, err := parseRepositories(raw)
if err != nil {
return nil, err
}

fixed := make(archiveRepositories)
for repository, tagsToRefs := range tags {
fixed[editRepositories(repository)] = tagsToRefs
}

return json.Marshal(fixed)
}

// https://github.com/moby/moby/blob/master/image/spec/v1.2.md#combined-image-json--filesystem-changeset-format
type metadataEntry struct {
Config string `json:"Config"`
RepoTags []string `json:"RepoTags"`
Layers []string `json:"Layers"`
}

// applies
func editManifestRepositories(raw []byte, editRepositories func(string) string) ([]byte, error) {
var entries []metadataEntry
if err := json.Unmarshal(raw, &entries); err != nil {
return nil, err
}

for i, entry := range entries {
fixed := make([]string, len(entry.RepoTags))
for i, tag := range entry.RepoTags {
parts := strings.Split(tag, ":")
if len(parts) > 2 {
return nil, fmt.Errorf("invalid repotag: %s", entry)
}
parts[0] = editRepositories(parts[0])
fixed[i] = strings.Join(parts, ":")
}

entries[i].RepoTags = fixed
}

return json.Marshal(entries)
}

// returns repository:tag:ref
func parseRepositories(data []byte) (archiveRepositories, error) {
var repoTags archiveRepositories
Expand Down

0 comments on commit 3ff0e90

Please sign in to comment.