Mirror host user ownership in and out of rootful Docker containers.
This projects uses a pair of scripts to mirror the host user in a container:
docker compose build
./user-mirror docker compose run --rm {{service}}
entrypoint
(build time): Installsetpriv
orgosu
.user-mirror
: Create mount source items on the host before Docker does (so they're owned by the current host user rather than root).user-mirror
: Inject environment variables into the Docker/Podman command and run it.entrypoint
(run time): Create a mirrored host user in the container from the injected environment variables.entrypoint
(run time):chown
mount destination items in the container to the mirrored user.entrypoint
(run time): Step-down from root to the mirrored user to execute the command.
- Copy the
entrypoint
script to the directory of your Dockerfile. - Copy the
user-mirror
script to the root of your project. - Append
Dockerfile.user-mirror
to your project's Dockerfile. - Add
cap_add
,cap_drop
, andenvironment
fromcompose.yml
to your project's compose file. - Prepend your project's compose entrypoint with
[/entrypoint, --,
...
Lets say you want to mount a volume inside a bind mount.
-v ./:/app -v /app/volume
↑ ↖ volume mount within the exiting bind mount (/app)
bind mount
Here's what would happen with rootful Docker on Linux systems:
(IMAGE_ID="debian:latest"; \
docker run --rm -u "$(id -u):$(id -g)" -v ./:/app -v /app/volume -w /app "$IMAGE_ID" sh -c \
'id && find volume -printf "%m %u:%g %f (container)\n"' && \
docker image rm "$IMAGE_ID" >/dev/null) && \
find volume -printf "%m %u:%g %f (host)\n" && \
rm -rf volume
uid=1000 gid=1000 groups=1000
755 root:root volume (container) ⇐😭
755 root:root volume (host) ⇐😭
Even though we used the -u, --user
option to mirror the host user inside the container, volume
still ends up being owned by root
! What a pain!
Thankfully, that's where this project steps in to help:
(IMAGE_ID="$(docker build -q image/)"; \
./user-mirror docker run --rm -v ./:/app -v /app/volume -w /app "$IMAGE_ID" sh -c \
'id && find volume -printf "%m %u:%g %f (container)\n"' && \
docker image rm "$IMAGE_ID" >/dev/null) && \
find volume -printf "%m %u:%g %f (host)\n" && \
rm -rf volume
uid=1000(user) gid=1000(user) groups=1000(user)
755 user:user volume (container) ⇐🥳
755 user:user volume (host) ⇐🥳
Also compatible with rootless Docker and Podman!
uid=0(root) gid=0(root) groups=0(root)
755 root:root volume (container)
755 user:user volume (host)
The big benefit to using this project over other workarounds is that it's all automatic. The file ownership fixes are all inferred directly from your command or compose specification.
Run ci
to run the test scripts in test/
with the images in images/
using both Docker Compose and Podman Compose (if installed).