From e3670f045a10c14d243d39212a48afb2317b3635 Mon Sep 17 00:00:00 2001 From: fatelei Date: Tue, 23 Dec 2025 11:27:14 +0800 Subject: [PATCH] feat: support nydus image format --- internal/image/oci.go | 2 ++ internal/manifest/manifest.go | 4 ++++ manifest/manifest.go | 4 ++++ manifest/oci.go | 18 ++++++++++++++---- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/internal/image/oci.go b/internal/image/oci.go index aaef95ff3d..94ca678847 100644 --- a/internal/image/oci.go +++ b/internal/image/oci.go @@ -292,6 +292,8 @@ func (m *manifestOCI1) convertToManifestSchema2(_ context.Context, options *type case ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc, ociencspec.MediaTypeLayerZstdEnc, ociencspec.MediaTypeLayerNonDistributableEnc, ociencspec.MediaTypeLayerNonDistributableGzipEnc, ociencspec.MediaTypeLayerNonDistributableZstdEnc: return nil, fmt.Errorf("during manifest conversion: encrypted layers (%q) are not supported in docker images", layers[idx].MediaType) + case manifest.NydusBootstrapLayerMediaType, manifest.NydusBlobLayerMediaType: + layers[idx].MediaType = manifest.DockerV2Schema2ForeignLayerMediaType default: return nil, fmt.Errorf("Unknown media type during manifest conversion: %q", layers[idx].MediaType) } diff --git a/internal/manifest/manifest.go b/internal/manifest/manifest.go index 3fb52104a6..6449795725 100644 --- a/internal/manifest/manifest.go +++ b/internal/manifest/manifest.go @@ -32,6 +32,10 @@ const ( DockerV2Schema2ForeignLayerMediaType = "application/vnd.docker.image.rootfs.foreign.diff.tar" // DockerV2Schema2ForeignLayerMediaType is the MIME type used for gzipped schema 2 foreign layers. DockerV2Schema2ForeignLayerMediaTypeGzip = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip" + // NydusBootstrapLayerMediaType is the MIME type used for Nydus bootstrap layers. + NydusBootstrapLayerMediaType = "application/vnd.containers.image.nydus.bootstrap.v1+json" + // NydusBlobLayerMediaType is the MIME type used for Nydus data blob layers. + NydusBlobLayerMediaType = "application/vnd.containers.image.nydus.blob.v1" ) // GuessMIMEType guesses MIME type of a manifest and returns it _if it is recognized_, or "" if unknown or unrecognized. diff --git a/manifest/manifest.go b/manifest/manifest.go index d8f37eb45d..205bee77ae 100644 --- a/manifest/manifest.go +++ b/manifest/manifest.go @@ -32,6 +32,10 @@ const ( DockerV2Schema2ForeignLayerMediaType = manifest.DockerV2Schema2ForeignLayerMediaType // DockerV2Schema2ForeignLayerMediaType is the MIME type used for gzipped schema 2 foreign layers. DockerV2Schema2ForeignLayerMediaTypeGzip = manifest.DockerV2Schema2ForeignLayerMediaTypeGzip + // NydusBootstrapLayerMediaType is the MIME type used for Nydus bootstrap layers. + NydusBootstrapLayerMediaType = manifest.NydusBootstrapLayerMediaType + // NydusBlobLayerMediaType is the MIME type used for Nydus data blob layers. + NydusBlobLayerMediaType = manifest.NydusBlobLayerMediaType ) // NonImageArtifactError (detected via errors.As) is used when asking for an image-specific operation diff --git a/manifest/oci.go b/manifest/oci.go index a18425d0e5..08547a5407 100644 --- a/manifest/oci.go +++ b/manifest/oci.go @@ -47,7 +47,8 @@ func SupportedOCI1MediaType(m string) error { imgspecv1.MediaTypeImageLayerNonDistributable, imgspecv1.MediaTypeImageLayerNonDistributableGzip, imgspecv1.MediaTypeImageLayerNonDistributableZstd, //nolint:staticcheck // NonDistributable layers are deprecated, but we want to continue to support manipulating pre-existing images. imgspecv1.MediaTypeImageManifest, imgspecv1.MediaTypeLayoutHeader, - ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc: + ociencspec.MediaTypeLayerEnc, ociencspec.MediaTypeLayerGzipEnc, + manifest.NydusBootstrapLayerMediaType, manifest.NydusBlobLayerMediaType: return nil default: return fmt.Errorf("unsupported OCIv1 media type: %q", m) @@ -142,9 +143,18 @@ func (m *OCI1) UpdateLayerInfos(layerInfos []types.BlobInfo) error { } mimeType = decMimeType } - mimeType, err := updatedMIMEType(oci1CompressionMIMETypeSets, mimeType, info) - if err != nil { - return fmt.Errorf("preparing updated manifest, layer %q: %w", info.Digest, err) + // Nydus layer types don't support compression/decompression operations + // They should only be preserved as-is + if mimeType == manifest.NydusBootstrapLayerMediaType || mimeType == manifest.NydusBlobLayerMediaType { + if info.CompressionOperation != types.PreserveOriginal { + return fmt.Errorf("preparing updated manifest, layer %q: Nydus layer types (%q) do not support compression or decompression operations", info.Digest, mimeType) + } + } else { + var err error + mimeType, err = updatedMIMEType(oci1CompressionMIMETypeSets, mimeType, info) + if err != nil { + return fmt.Errorf("preparing updated manifest, layer %q: %w", info.Digest, err) + } } if info.CryptoOperation == types.Encrypt { encMediaType, err := getEncryptedMediaType(mimeType)