Skip to content
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
4 changes: 3 additions & 1 deletion cache/refs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"slices"
"strconv"
"strings"
"sync"
"time"
Expand All @@ -27,6 +28,7 @@ import (
"github.com/moby/buildkit/solver"
"github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/compression"
"github.com/moby/buildkit/util/estargz"
"github.com/moby/buildkit/util/flightcontrol"
"github.com/moby/buildkit/util/leaseutil"
"github.com/moby/buildkit/util/overlay"
Expand Down Expand Up @@ -1210,7 +1212,7 @@ func makeTmpLabelsStargzMode(labels map[string]string, s session.Group) (fields
res[tmpKey] = v
}
for i, sid := range session.AllSessionIDs(s) {
sidKey := "containerd.io/snapshot/remote/stargz.session." + fmt.Sprintf("%d", i) + "." + id
sidKey := estargz.TargetSessionLabel + "." + strconv.Itoa(i) + "." + id
fields = append(fields, "labels."+sidKey)
res[sidKey] = sid
}
Expand Down
29 changes: 7 additions & 22 deletions cmd/buildkitd/main_oci_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/moby/buildkit/session"
"github.com/moby/buildkit/util/bklog"
"github.com/moby/buildkit/util/disk"
"github.com/moby/buildkit/util/estargz"
"github.com/moby/buildkit/util/network/cniprovider"
"github.com/moby/buildkit/util/network/netproviders"
"github.com/moby/buildkit/util/resolver"
Expand Down Expand Up @@ -462,22 +463,6 @@ func validOCIBinary() bool {
return true
}

const (
// targetRefLabel is a label which contains image reference.
targetRefLabel = "containerd.io/snapshot/remote/stargz.reference"

// targetDigestLabel is a label which contains layer digest.
targetDigestLabel = "containerd.io/snapshot/remote/stargz.digest"

// targetImageLayersLabel is a label which contains layer digests contained in
// the target image.
targetImageLayersLabel = "containerd.io/snapshot/remote/stargz.layers"

// targetSessionLabel is a labeld which contains session IDs usable for
// authenticating the target snapshot.
targetSessionLabel = "containerd.io/snapshot/remote/stargz.session"
)

// sourceWithSession returns a callback which implements a converter from labels to the
// typed snapshot source info. This callback is called everytime the snapshotter resolves a
// snapshot. This callback returns configuration that is based on buildkitd's registry config
Expand All @@ -488,15 +473,15 @@ func sourceWithSession(hosts docker.RegistryHosts, sm *session.Manager) sgzsourc
// to the snapshotter API. So, first, get all these IDs
var ids []string
for k := range labels {
if after, ok := strings.CutPrefix(k, targetRefLabel+"."); ok {
if after, ok := strings.CutPrefix(k, estargz.TargetRefLabel+"."); ok {
ids = append(ids, after)
}
}

// Parse all labels
for _, id := range ids {
// Parse session labels
ref, ok := labels[targetRefLabel+"."+id]
ref, ok := labels[estargz.TargetRefLabel+"."+id]
if !ok {
continue
}
Expand All @@ -506,7 +491,7 @@ func sourceWithSession(hosts docker.RegistryHosts, sm *session.Manager) sgzsourc
}
var sids []string
for i := 0; ; i++ {
sidKey := targetSessionLabel + "." + fmt.Sprintf("%d", i) + "." + id
sidKey := estargz.TargetSessionLabel + "." + fmt.Sprintf("%d", i) + "." + id
sid, ok := labels[sidKey]
if !ok {
break
Expand All @@ -521,9 +506,9 @@ func sourceWithSession(hosts docker.RegistryHosts, sm *session.Manager) sgzsourc
HostsFunc(ref.Hostname())
})
if s, err := parse(map[string]string{
targetRefLabel: ref,
targetDigestLabel: labels[targetDigestLabel+"."+id],
targetImageLayersLabel: labels[targetImageLayersLabel+"."+id],
estargz.TargetRefLabel: ref,
estargz.TargetDigestLabel: labels[estargz.TargetDigestLabel+"."+id],
estargz.TargetImageLayersLabel: labels[estargz.TargetImageLayersLabel+"."+id],
}); err == nil {
src = append(src, s...)
}
Expand Down
82 changes: 64 additions & 18 deletions util/estargz/labels.go
Original file line number Diff line number Diff line change
@@ -1,38 +1,84 @@
package estargz

import (
"fmt"
"strings"

ctdlabels "github.com/containerd/containerd/v2/pkg/labels"
"github.com/containerd/stargz-snapshotter/estargz"
"github.com/containerd/containerd/v2/pkg/labels"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)

const (
// TargetRefLabel is a label which contains image reference.
//
// It is a copy of [stargz-snapshotter/fs/source.targetRefLabel].
//
// [stargz-snapshotter/fs/source.targetRefLabel]: https://github.com/containerd/stargz-snapshotter/blob/v0.16.3/fs/source/source.go#L64-L65
TargetRefLabel = "containerd.io/snapshot/remote/stargz.reference"

// TargetDigestLabel is a label which contains layer digest.
//
// It is a copy of [stargz-snapshotter/fs/source.targetDigestLabel].
//
// [stargz-snapshotter/fs/source.targetDigestLabel]: https://github.com/containerd/stargz-snapshotter/blob/v0.16.3/fs/source/source.go#L67-L68
TargetDigestLabel = "containerd.io/snapshot/remote/stargz.digest"

// TargetImageLayersLabel is a label which contains layer digests contained in
// the target image.
//
// It is a copy of [stargz-snapshotter/fs/source.targetImageLayersLabel].
//
// [stargz-snapshotter/fs/source.targetImageLayersLabel]: https://github.com/containerd/stargz-snapshotter/blob/v0.16.3/fs/source/source.go#L70-L72
TargetImageLayersLabel = "containerd.io/snapshot/remote/stargz.layers"

// TargetSessionLabel is a label which contains session IDs usable for
// authenticating the target snapshot.
//
// It has no equivalent in github.com/containerd/stargz-snapshotter.
TargetSessionLabel = "containerd.io/snapshot/remote/stargz.session"
)

const (
// TOCJSONDigestAnnotation is an annotation for an image layer. This stores the
// digest of the TOC JSON.
// This annotation is valid only when it is specified in `.[]layers.annotations`
// of an image manifest.
//
// This is a copy of [estargz.TOCJSONDigestAnnotation]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this imported (or upstream constant just used instead). Same for next.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back-and-forth a bit; initially I had these as alias (TOCJSONDigestAnnotation = estargz.TOCJSONDigestAnnotation), but as we already would have to define the non-exported ones locally (and the estargz package containing much more than just the consts), and these consts to not change, I thought it would be OK to just have our own copy, as long as we refer to where they originate from.

//
// [estargz.TOCJSONDigestAnnotation]: https://pkg.go.dev/github.com/containerd/stargz-snapshotter/estargz@v0.16.3#TOCJSONDigestAnnotation
TOCJSONDigestAnnotation = "containerd.io/snapshot/stargz/toc.digest"

// StoreUncompressedSizeAnnotation is an additional annotation key for eStargz to enable lazy
// pulling on containers/storage. Stargz Store is required to expose the layer's uncompressed size
// to the runtime but current OCI image doesn't ship this information by default. So we store this
// to the special annotation.
//
// This is a copy of [estargz.StoreUncompressedSizeAnnotation]
//
// [estargz.StoreUncompressedSizeAnnotation]: https://pkg.go.dev/github.com/containerd/stargz-snapshotter/estargz@v0.16.3#StoreUncompressedSizeAnnotation
StoreUncompressedSizeAnnotation = "io.containers.estargz.uncompressed-size"
Comment on lines +58 to +59
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why this uses a different prefix (io.containers.estargz) than the other ones, which all use containerd.io/.. 😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because this annotation is necessary to make the filesystem work with github.com/containers/storage library which is used by Podman/CRI-O. c.f. https://github.com/containerd/stargz-snapshotter/blob/2f71f9ea81620e302c5ec6384597fc630fbc6656/estargz/types.go#L78-L82

)

func SnapshotLabels(ref string, descs []ocispecs.Descriptor, targetIndex int) map[string]string {
if len(descs) < targetIndex {
return nil
}
desc := descs[targetIndex]
labels := make(map[string]string)
for _, k := range []string{estargz.TOCJSONDigestAnnotation, estargz.StoreUncompressedSizeAnnotation} {
labels[k] = desc.Annotations[k]
}
labels["containerd.io/snapshot/remote/stargz.reference"] = ref
labels["containerd.io/snapshot/remote/stargz.digest"] = desc.Digest.String()
var (
layersKey = "containerd.io/snapshot/remote/stargz.layers"
layers string
)

var layers string
for _, l := range descs[targetIndex:] {
ls := fmt.Sprintf("%s,", l.Digest.String())
// This avoids the label hits the size limitation.
// Skipping layers is allowed here and only affects performance.
if err := ctdlabels.Validate(layersKey, layers+ls); err != nil {
if err := labels.Validate(TargetImageLayersLabel, layers+l.Digest.String()); err != nil {
break
}
layers += ls
layers += l.Digest.String() + ","
Comment on lines +72 to +75
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight change here; previously this would check the length including the trailing ,, but when setting the label, we trim the trailing comma, so there would be a potential off-by-one here, where we'd skip the label for being too long, even if it wasn't?

}
return map[string]string{
TOCJSONDigestAnnotation: desc.Annotations[TOCJSONDigestAnnotation],
StoreUncompressedSizeAnnotation: desc.Annotations[StoreUncompressedSizeAnnotation],
TargetRefLabel: ref,
TargetDigestLabel: desc.Digest.String(),
TargetImageLayersLabel: strings.TrimSuffix(layers, ","),
}
labels[layersKey] = strings.TrimSuffix(layers, ",")
return labels
}