# Docker run: Mirror Host User

Docker makes it easy to share host network and filesystem, but it doesn't make it easy to share the host's user ID and group ID. This is very useful when using a container locally via `docker run`, when it needs to write files to a volume shared with the host. In that case it is useful for the files to have the same user ID and group ID as the user on host.

Currently the way I do this is as follows:

* In the `Dockerfile`, I create a user `runuser` and group `rungroup` via `useradd` and `groupadd` commands, and I set final `USER` so container defaults to that user:

```
RUN groupadd rungroup \
 && useradd -ms /bin/bash -g rungroup runuser
 
USER runuser

...more setup...

# ensure container runs as runuser
USER runuser
```

* In a small script, run the docker container in detached mode (`--detach`)

```
  docker run \
    ...
    --env USER \
    --name $CTNR_NAME \
    --rm \
    --detach \
    --tty \
    IMAGE_NAME
```

* Then docker exec `usermod` and `groupmod` to match the host's user ID and group ID:&#x20;

```
docker exec -it -u root $CTNR_NAME groupmod -g "$GROUP_ID" rungroup
docker exec -it -u root $CTNR_NAME usermod -u $UID runuser
```

* A final line in the script executes the desired command in the container, such as a shell. The command will run as `runuser:rungroup` but with the ID that match that of the host:&#x20;

```
# runs shell as last USER in Dockerfile
docker exec -it $CTNR_NAME id
```

* If you need a root shell in container, say to install more apps temporarily (because if you restart the container those apps will be gone -- which is a good thing, ensure clean slate for any new container), change user:&#x20;

```
docker exec -it -u root $CTNR_NAME /bin/bash
```

This is quite tricky and required a fair bit of time to figure out.

I've seen another solution of mounting /etc/passwd and /etc/group but this exposes way more info in the container than necessary (which is just one line of each file). So for me this is not a solution.

In any case the above enables multiple simultaneous shells, each one running as either `root` or `runuser`, in latter case the UID and GROUP\_ID will match that of host user who started the container, and all shells can be exited without terminating the container.&#x20;

One caveat is that there will still be files owned by the original user ID that got created in the `Dockerfile`. Eg if the `useradd` command in `Dockerfile` created user `runuser` with ID 2000, and then in `Dockerfile` other commands are run as that user that creates files, the files will have ownership by user ID 2000. The `docker exec` that is run later changes the `runuser` ID to something else, but this does not change the ownership of any files already created. Therefore, you may need to chown those files via an additional docker exec. Eg&#x20;

```
docker exec -it -u root $CTNR_NAME \
  chown runuser /var/run/docker.sock
```

In the small script I additionally have a check to determine if the container is already running, in that case it skips the docker run, and also to easy choose between `runuser` and `root`:&#x20;

```
#!/usr/bin/env bash

run_as_root=false
if [[ ${1:-} == '--su' ]]; then
  shift
  echo "Will run as root"
  run_as_root=true
fi

CTNR_NAME=something

if [[ -z $( docker ps -qf name=$CTNR_NAME ) ]]; then
  echo "Starting new container $CTNR_NAME"
  docker run \
    ...

  # match host user ID and group ID
  docker exec -it -u root $CTNR_NAME groupmod -g "$GROUP_ID" rungroup
  docker exec -it -u root $CTNR_NAME usermod -u $UID runuser
  
  # some files need to be re-owned by runuser
  docker exec -it -u root $CTNR_NAME chown runuser /var/run/docker.sock
  
else
  echo "Container $CTNR_NAME is already running"
fi

echo "Shelling into $CTNR_NAME container"
if [[ $run_as_root == true ]]; then
  docker exec -it --user root    $CTNR_NAME /bin/bash
else
  docker exec -it --user runuser $CTNR_NAME /bin/bash
fi
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://devops.sentianse.com/notes/docker-run-mirror-host-user.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
