Skip to content

containers: strip any bind mode from run volumes - #3445

Open
breken-ai wants to merge 1 commit into
docker:mainfrom
breken-ai:fix-run-volumes-bind-options
Open

breken-ai wants to merge 1 commit into
docker:mainfrom
breken-ai:fix-run-volumes-bind-options

Conversation

@breken-ai

Copy link
Copy Markdown

What's wrong

containers.run() / containers.create() build the container's volumes list from the volumes=[...] bind strings via _host_volume_from_bind. It only strips a trailing :ro or :rw. Any other bind mode stays in the destination:

bind volume sent in Config.Volumes
/src:/app:z /app:z
/src:/app:ro,Z /app:ro,Z
/src:/app:rw,rprivate /app:rw,rprivate
/src:/app:cached /app:cached

The daemon treats that as a separate anonymous volume. So next to the bind, every such container gets an extra anonymous volume mounted at the literal path /app:z. The volume is left behind unless the container is removed with v=True. docker run -v /src:/app:z doesn't do this.

Reproduction against Docker Desktop (engine 27.5) on main:

c = docker.from_env()
ct = c.containers.run('redis:7-alpine', ['ls', '/mnt'], volumes=['/tmp:/mnt/x:z'], detach=True)
# ls /mnt -> ['x', 'x:z']
# Mounts  -> bind /tmp -> /mnt/x, volume <anon> -> /mnt/x:z

The same happens with :ro,Z and :cached. With this branch, ls /mnt gives only x, and the only mount is the bind.

Fix

After the source, drop whatever mode follows the destination. Windows drive letters in the destination are kept (C:\src:D:\dst:ro,Z gives D:\dst). Bare ro/rw handling is unchanged.

Tests

  • New test_create_volumes_with_bind_options in tests/unit/models_containers_test.py. It fails on main (volumes=['/mnt/z:z', '/mnt/ro-z:ro,Z', ...]) and passes on this branch.
  • pytest tests/unit: 615 passed, run with an isolated HOME. Two existing tests read the developer's own ~/.docker config and fail the same way on main.
  • ruff check docker tests is clean.

This was found and fixed with help from an AI coding assistant (Claude). I checked the change and reproduced the bug and the fix against a real daemon as shown above. The commit is signed off and carries an Assisted-By: trailer.

containers.run()/create() derive the container's volume list from the
`volumes` bind strings. Only a trailing ":ro" or ":rw" was removed, so
a bind such as "/src:/app:z", "/src:/app:ro,Z" or "/src:/app:cached"
added "/app:z" (etc.) to Config.Volumes, and the daemon created an
extra anonymous volume mounted at that literal path next to the bind.

Drop whatever mode follows the destination, keeping Windows drive
letters in the destination intact.

Assisted-By: Claude
Signed-off-by: breken-ai <312387581+breken-ai@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant