c8d: Fix `docker diff`
- fixes https://github.com/moby/moby/issues/46607

**- What I did**

Diffing a container yielded some extra changes that come from the files/directories that we mount inside the container (/etc/resolv.conf for example). To avoid that we create an intermediate snapshot that has these files, with this we can now diff the container fs with its parent and only get the differences that were made inside the container.

**- How I did it**

Added a layer for the base snapshot of a container containing the files that are created by the runtime.

**- How to verify it**

Run `TestDiff`

```console
$ make DOCKER_GRAPHDRIVER=overlayfs TEST_FILTER=TestDiff TEST_INTEGRATION_USE_SNAPSHOTTER=1 TEST_IGNORE_CGROUP_CHECK=1 test-integration
```

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->
- containerd integration: Fixed `docker diff` containing extra differences

**- A picture of a cute animal (not mandatory but encouraged)**


daemon/containerd/image_changes.go
package containerd

import (
	"context"
	"encoding/json"

	"github.com/containerd/containerd/content"
	"github.com/containerd/containerd/log"
	"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"
)

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 {
			log.G(ctx).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
}

package containerd

import (
	"context"

	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/mount"
	"github.com/docker/docker/container"
	"github.com/docker/docker/pkg/archive"
)

func (i *ImageService) Changes(ctx context.Context, container *container.Container) ([]archive.Change, error) {
	snapshotter := i.client.SnapshotService(container.Driver)
	info, err := snapshotter.Stat(ctx, container.ID)
	if err != nil {
		return nil, err
	}

	imageMounts, _ := snapshotter.View(ctx, container.ID+"-parent-view", info.Parent)

	defer func() {
		if err := snapshotter.Remove(ctx, container.ID+"-parent-view"); err != nil {
			log.G(ctx).WithError(err).Warn("error removing the parent view snapshot")
		}
	}()

	var changes []archive.Change
	err = i.PerformWithBaseFS(ctx, container, func(containerRoot string) error {
		return mount.WithReadonlyTempMount(ctx, imageMounts, func(imageRoot string) error {
			changes, err = archive.ChangesDirs(containerRoot, imageRoot)
			return err
		})
	})

	return changes, err
}

The warn here should probably be `error removing the parent view snapshot` or `removing the parent view snapshot` (it's clear form it being a warning and an error as detail that an error occurred while doing so).