diff --git a/cache/refs.go b/cache/refs.go index 3bd534854ae0..20299df7e84a 100644 --- a/cache/refs.go +++ b/cache/refs.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "slices" + "strconv" "strings" "sync" "time" @@ -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" @@ -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 } diff --git a/cmd/buildkitd/main_oci_worker.go b/cmd/buildkitd/main_oci_worker.go index 658a334fcdc9..dbbd29e7b8c1 100644 --- a/cmd/buildkitd/main_oci_worker.go +++ b/cmd/buildkitd/main_oci_worker.go @@ -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" @@ -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 @@ -488,7 +473,7 @@ 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) } } @@ -496,7 +481,7 @@ func sourceWithSession(hosts docker.RegistryHosts, sm *session.Manager) sgzsourc // Parse all labels for _, id := range ids { // Parse session labels - ref, ok := labels[targetRefLabel+"."+id] + ref, ok := labels[estargz.TargetRefLabel+"."+id] if !ok { continue } @@ -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 @@ -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...) } diff --git a/util/estargz/labels.go b/util/estargz/labels.go index b7576ca97171..96b8a3def2eb 100644 --- a/util/estargz/labels.go +++ b/util/estargz/labels.go @@ -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] + // + // [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" +) + 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() + "," + } + 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 }