Skip to content

feat(mount): support --mount type=image#4990

Open
mayur-tolexo wants to merge 1 commit into
containerd:mainfrom
mayur-tolexo:feat/mount-type-image
Open

feat(mount): support --mount type=image#4990
mayur-tolexo wants to merge 1 commit into
containerd:mainfrom
mayur-tolexo:feat/mount-type-image

Conversation

@mayur-tolexo

Copy link
Copy Markdown

Implements --mount type=image (read-only), part of #3867.

Mounts an image's filesystem into a container, matching Docker (moby#48798):
nerdctl run --mount type=image,source=<image>,destination=<path> ...

What it does

  • New mount type image parsed/validated in ProcessFlagMount (source + destination required; read-only; subpath and read-write are rejected with clear errors).
  • setupImageMount ensures + unpacks the source image and creates a read-only, GC-rooted snapshot view of its rootfs, mounted at the destination. The same image can be mounted at multiple destinations (moby#50268).
  • The view's snapshot key is stored in a nerdctl/image-mount-snapshots label and removed when the container is deleted (using the container's own snapshotter), mirroring the anonymous-volume cleanup pattern. Views created during a failed create are also cleaned up, so snapshots don't leak.

Out of scope

  • Read-write image mounts and subpath (rejected with clear errors; left as follow-ups).
  • Linux only (the type is only recognized in the Linux mount parser).

Tests

cmd/nerdctl/container/container_run_mount_image_linux_test.go:

  • image filesystem readable at the target
  • mount is read-only
  • same image to two destinations
  • errors: missing source, unsupported subpath

Plus a parser unit test in pkg/mountutil/mountutil_linux_test.go. Docs updated in command-reference.md.

Verified in a Linux + containerd sandbox: gofmt, go vet, build, unit + integration tests pass; the view is created, survives while the container runs, and is removed on deletion; a failed create leaves no leaked snapshots.

@mayur-tolexo

Copy link
Copy Markdown
Author

Local test results

Linux + containerd dev sandbox (containerd 1.7.24, runc 1.1.15, go 1.26; overlayfs snapshotter).

vet: clean
build: ok
--- unit ---
ok  	github.com/containerd/nerdctl/v2/pkg/mountutil	0.004s
--- integration ---
--- PASS: TestRunMountTypeImageErrors (0.00s)
--- PASS: TestRunMountTypeImageReadOnly (0.35s)
--- PASS: TestRunMountTypeImageMultipleDestinations (0.43s)
--- PASS: TestRunMountTypeImage (0.53s)

Also manually verified: image FS readable at the target; touch into the mount fails (read-only); same image mounted at two destinations; the snapshot view is created at run, survives while the container runs, and is removed on a clean rm (count 1→0); a create that fails after a view is created leaves 0 leaked snapshots.

Comment thread pkg/mountutil/mountutil_linux.go Outdated
Comment thread docs/command-reference.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Linux support for --mount type=image (read-only) by parsing/validating the new mount type and creating a GC-rooted snapshot view of an image’s rootfs that is mounted into the container, with cleanup on container deletion/failure.

Changes:

  • Extend --mount parsing to recognize type=image and enforce required source/destination and read-only semantics.
  • Create and mount per-containerd-snapshotter read-only views for image mounts; persist snapshot keys for cleanup and remove them on container deletion (and on failed create).
  • Add unit + integration tests and update CLI documentation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/mountutil/mountutil.go Adds image mount type constant and tracking field for image-mount snapshot keys.
pkg/mountutil/mountutil_linux.go Parses/validates type=image and rejects unsupported options.
pkg/mountutil/mountutil_linux_test.go Unit tests for --mount type=image parsing/validation.
pkg/labels/labels.go Adds a container label to persist image-mount snapshot keys for cleanup.
pkg/cmd/container/run_mount.go Creates GC-rooted snapshot views for image mounts and cleans them up on errors.
pkg/cmd/container/remove.go Removes recorded image-mount snapshot views during container removal.
pkg/cmd/container/create.go Cleans up image-mount views on failed create; persists snapshot keys in labels on success.
docs/command-reference.md Documents --mount type=image.
cmd/nerdctl/container/container_run_mount_image_linux_test.go Integration tests for mounting an image filesystem read-only, multiple destinations, and error cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/mountutil/mountutil_linux.go
Comment thread pkg/mountutil/mountutil_linux.go
Comment thread docs/command-reference.md
Comment thread pkg/cmd/container/remove.go
@mayur-tolexo mayur-tolexo force-pushed the feat/mount-type-image branch 2 times, most recently from de57f61 to 3d5e266 Compare June 22, 2026 11:24
@mayur-tolexo

mayur-tolexo commented Jun 22, 2026

Copy link
Copy Markdown
Author

Tested locally against containerd, using alpine as both the source and the container image.

Reading a file from the mounted image:

$ nerdctl run --rm --mount type=image,source=alpine,destination=/mnt/img alpine cat /mnt/img/etc/alpine-release
3.24.1

The mount is read-only:

$ nerdctl run --rm --mount type=image,source=alpine,destination=/mnt/img alpine touch /mnt/img/x
touch: /mnt/img/x: Read-only file system

Same image mounted at two destinations:

$ nerdctl run --rm --mount type=image,source=alpine,destination=/a --mount type=image,source=alpine,destination=/b alpine sh -c 'cat /a/etc/alpine-release; cat /b/etc/alpine-release'
3.24.1
3.24.1

Invalid specs are rejected:

$ nerdctl run --rm --mount type=image,source=alpine,destination=/mnt/img,rw alpine true
FATA[0000] type=image mounts are read-only

$ nerdctl run --rm --mount type=image,destination=/mnt/img alpine true
FATA[0000] type=image requires a source (the image reference)

$ nerdctl run --rm --mount type=image,source=alpine,destination=/mnt/img,subpath=etc alpine true
FATA[0000] mount option "subpath" is not yet supported

inspect reports it read-only, and the snapshot view is cleaned up on removal:

$ nerdctl run --name demo --mount type=image,source=alpine,destination=/mnt/img alpine true
$ nerdctl inspect --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}} RW={{.RW}} Mode={{.Mode}}{{end}}' demo
image docker.io/library/alpine:latest -> /mnt/img RW=false Mode=ro

# image-mount snapshot exists while the container is around:
$ ctr snapshot ls | grep -c image-mount
1
$ nerdctl rm demo
demo
$ ctr snapshot ls | grep -c image-mount
0

Comment thread pkg/cmd/container/run_mount.go
Comment thread cmd/nerdctl/container/container_run_mount_image_linux_test.go Outdated
Mount an image's filesystem into a container read-only, matching Docker:
--mount type=image,source=<image>,destination=<path>. The source image is
ensured and unpacked, a read-only snapshot view of its rootfs is created and
mounted at the destination, and the view is removed when the container is
deleted. Read-write and subpath are not yet supported.

Signed-off-by: Mayur Das <mayur.das@neevcloud.com>
@mayur-tolexo mayur-tolexo force-pushed the feat/mount-type-image branch from 00fa805 to 2a89c8c Compare June 22, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants