Skip to content
This repository has been archived by the owner on Sep 2, 2024. It is now read-only.

build: flag images for unpacking by default #79

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/client/image/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ func (s *Build) defaultExporter() ([]buildkit.ExportEntry, error) {
}
exp.Attrs["name"] = strings.Join(tags, ",")
exp.Attrs["name-canonical"] = "" // true
exp.Attrs["unpack"] = "true"
}
return []buildkit.ExportEntry{exp}, nil
}
50 changes: 43 additions & 7 deletions pkg/server/agent_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"fmt"
"io/ioutil"
"net"
"time"

"github.com/containerd/containerd"
"github.com/containerd/containerd/api/events"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/platforms"
"github.com/containerd/typeurl"
"github.com/gogo/protobuf/types"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -141,30 +143,33 @@ func copyImageContent(ctx context.Context, ctr *containerd.Client, name string,
return err
}
contentStore := ctr.ContentStore()
toCtx := namespaces.WithNamespace(ctx, "k8s.io")
handler := images.Handlers(images.ChildrenHandler(contentStore), copyImageContentFunc(toCtx, contentStore, img))
if err = images.Walk(ctx, handler, img.Target); err != nil {
fromCtx, fromCancel := context.WithTimeout(ctx, time.Minute*3)
defer fromCancel()
toCtx := namespaces.WithNamespace(fromCtx, "k8s.io")
handler := images.Handlers(images.ChildrenHandler(contentStore), copyImageContentHandler(toCtx, contentStore, img))
if err = images.Walk(fromCtx, handler, img.Target); err != nil {
return err
}
return fn(toCtx, imageStore, img)
}

func copyImageContentFunc(toCtx context.Context, contentStore content.Store, img images.Image) images.HandlerFunc {
func copyImageContentHandler(toCtx context.Context, contentStore content.Store, img images.Image) images.HandlerFunc {
return func(fromCtx context.Context, desc ocispec.Descriptor) (children []ocispec.Descriptor, err error) {
logrus.Debugf("copy-image-content: media-type=%v, digest=%v", desc.MediaType, desc.Digest)
info, err := contentStore.Info(fromCtx, desc.Digest)
info, err := waitImageContentInfo(fromCtx, contentStore, desc)
if err != nil {
return children, err
}
logrus.Debugf("copy-image-content: info=%#v", info)
ra, err := contentStore.ReaderAt(fromCtx, desc)
if err != nil {
return children, err
}
defer ra.Close()
wopts := []content.WriterOpt{content.WithRef(img.Name)}
if _, err := contentStore.Info(toCtx, desc.Digest); errdefs.IsNotFound(err) {
// if the image does not already exist in the target namespace we supply the descriptor here so as to
// ensure that it is created with proper size information. if the image already exist the size for the digest
// if the image does not already exist in the target namespace we supply the descriptor here to ensure
// that it is created with proper size information. if the image already exists the size for the digest
// for the to-be updated image is sourced from what is passed to content.Copy
wopts = append(wopts, content.WithDescriptor(desc))
}
Expand All @@ -180,3 +185,34 @@ func copyImageContentFunc(toCtx context.Context, contentStore content.Store, img
return children, err
}
}

// waitImageContentInfo waits for all referenced content to become available because buildkit can trigger image
// creation events before all referenced content is fully available (via unpack)
func waitImageContentInfo(ctx context.Context, contentStore content.Store, desc ocispec.Descriptor) (content.Info, error) {
available, _, _, missing, err := images.Check(ctx, contentStore, desc, platforms.Default())
if err != nil {
return content.Info{}, err
}
if !available && len(missing) > 0 {
for _, m := range missing {
logrus.Debugf("wait-image-content: missing=%#v", m)
next:
for {
select {
case <-ctx.Done():
return content.Info{}, ctx.Err()
case <-time.After(100 * time.Millisecond):
info, err := contentStore.Info(ctx, desc.Digest)
if err == nil {
logrus.Debugf("wait-image-content: available=%#v", info)
break next
}
if !errdefs.IsNotFound(err) {
return content.Info{}, err
}
}
}
}
}
return contentStore.Info(ctx, desc.Digest)
}