moby/daemon/containerd/image_changes.go
Paweł Gronowski 6da42ca830
c8d/diff: Reuse mount, mount parent as read-only
The container rw layer may already be mounted, so it's not safe to use
it in another overlay mount. Use the ref counted mounter (which will
reuse the existing mount if it exists) to avoid that.

Also, mount the parent mounts (layers of the base image) in a read-only
mode.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
2023-08-11 15:30:38 +02:00

69 lines
1.8 KiB
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
}