From d2878d841beffd7e2fbf3603ac8962430f5c68eb Mon Sep 17 00:00:00 2001 From: BBQ <35603386+HoneyBBQ@users.noreply.github.com> Date: Thu, 26 Feb 2026 19:55:46 +0800 Subject: [PATCH] fix(containerd): use image RootFS for snapshot parent chain ID (#132) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous snapshotParentFromLayers manually decompressed layer blobs to compute diffIDs, which could diverge from the IDs that containerd's Unpack uses (e.g. gzip vs zstd). Use image.RootFS() instead — the canonical source containerd itself relies on. --- internal/containerd/service.go | 38 ++++------------------------------ 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/internal/containerd/service.go b/internal/containerd/service.go index f46726e7..dd5b630a 100644 --- a/internal/containerd/service.go +++ b/internal/containerd/service.go @@ -1,8 +1,6 @@ package containerd import ( - "bytes" - "compress/gzip" "context" "errors" "fmt" @@ -17,16 +15,13 @@ import ( tasksv1 "github.com/containerd/containerd/api/services/tasks/v1" tasktypes "github.com/containerd/containerd/api/types/task" containerd "github.com/containerd/containerd/v2/client" - "github.com/containerd/containerd/v2/core/content" "github.com/containerd/containerd/v2/core/images" "github.com/containerd/containerd/v2/core/snapshots" "github.com/containerd/containerd/v2/pkg/cio" "github.com/containerd/containerd/v2/pkg/namespaces" "github.com/containerd/containerd/v2/pkg/oci" "github.com/containerd/errdefs" - "github.com/containerd/platforms" "github.com/memohai/memoh/internal/config" - "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/identity" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -300,37 +295,12 @@ func (s *DefaultService) CreateContainer(ctx context.Context, req CreateContaine } func (s *DefaultService) snapshotParentFromLayers(ctx context.Context, image containerd.Image) (string, error) { - manifest, err := images.Manifest(ctx, s.client.ContentStore(), image.Target(), platforms.Default()) + diffIDs, err := image.RootFS(ctx) if err != nil { - return "", err + return "", fmt.Errorf("read image rootfs: %w", err) } - if len(manifest.Layers) == 0 { - return "", fmt.Errorf("image has no layer descriptors") - } - diffIDs := make([]digest.Digest, 0, len(manifest.Layers)) - for _, layer := range manifest.Layers { - blob, err := content.ReadBlob(ctx, s.client.ContentStore(), layer) - if err != nil { - return "", err - } - reader := bytes.NewReader(blob) - var r io.ReadCloser - if strings.Contains(layer.MediaType, "gzip") { - r, err = gzip.NewReader(reader) - if err != nil { - return "", err - } - } else { - r = io.NopCloser(reader) - } - - digester := digest.Canonical.Digester() - if _, err := io.Copy(digester.Hash(), r); err != nil { - _ = r.Close() - return "", err - } - _ = r.Close() - diffIDs = append(diffIDs, digester.Digest()) + if len(diffIDs) == 0 { + return "", fmt.Errorf("image has no layers") } chainIDs := identity.ChainIDs(diffIDs) return chainIDs[len(chainIDs)-1].String(), nil