package containerd import ( "context" "encoding/json" "github.com/containerd/containerd/content" "github.com/containerd/containerd/mount" "github.com/docker/docker/container" "github.com/docker/docker/pkg/archive" "github.com/google/uuid" "github.com/opencontainers/image-spec/identity" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" ) func (i *ImageService) Changes(ctx context.Context, container *container.Container) ([]archive.Change, error) { cs := i.client.ContentStore() imageManifest, err := getContainerImageManifest(container) if err != nil { return nil, err } imageManifestBytes, err := content.ReadBlob(ctx, cs, imageManifest) if err != nil { return nil, err } var manifest ocispec.Manifest if err := json.Unmarshal(imageManifestBytes, &manifest); err != nil { return nil, err } imageConfigBytes, err := content.ReadBlob(ctx, cs, manifest.Config) if err != nil { return nil, err } var image ocispec.Image if err := json.Unmarshal(imageConfigBytes, &image); err != nil { return nil, err } rnd, err := uuid.NewRandom() if err != nil { return nil, err } snapshotter := i.client.SnapshotService(container.Driver) diffIDs := image.RootFS.DiffIDs parent, err := snapshotter.View(ctx, rnd.String(), identity.ChainID(diffIDs).String()) if err != nil { return nil, err } defer func() { if err := snapshotter.Remove(ctx, rnd.String()); err != nil { logrus.WithError(err).WithField("key", rnd.String()).Warn("remove temporary snapshot") } }() var changes []archive.Change err = i.PerformWithBaseFS(ctx, container, func(containerRootfs string) error { return mount.WithReadonlyTempMount(ctx, parent, func(parentRootfs string) error { changes, err = archive.ChangesDirs(containerRootfs, parentRootfs) return err }) }) return changes, err }