Docker can start a container with a specific user by passing the id on the command line with -u
.
The parameter to the -u
switch is either a username or id of a user existing inside the container. More precisely,
the container must have valid /etc/passwd
file with the defined user:
$ mkdir etc
$ echo 'postgres:x:1000:1000::/home/postgres:/bin/sh' > etc/passwd
While not needed for this simple experiment, we might want to create group and shadow files for completeness:
$ echo 'postgres:x:1000:' > etc/group
$ echo 'postgres:!:16452:0:99999:7:::' > etc/shadow
$ echo 'postgres:!::' > etc/gshadow
The next step is to create a directory in our build folder and chown it to user 1000
--we don't have to have the
user with this id locally.
$ mkdir data
$ touch data/file
$ chown -R 1000:1000 data
We must tar the data
directory with a p
flag to preserve permissions. Otherwise, if we just ADD
or COPY
the
folder in the Dockerfile, the Docker daemon will re-set ownership on all files back to the root user (0:0
).
$ tar -cpf data.tar data
Finally, we build the container. Let's also ignore the data folder so it doesn't have to be uploaded to the docker daemon as part of the build environment:
$ echo 'data' > .dockerignore
$ echo 'FROM debian:jessie
COPY etc /etc
ADD data.tar /
VOLUME ["/data"]' > Dockerfile
$ docker build -t base .
And now we can verify that indeed the permissions are preserved:
$ docker run --rm -it base ls -l /data
total 0
-rw-r--r-- 1 postgres postgres 0 Jan 17 14:17 file
Let's run as user postgres
:
$ docker run --rm -itu postgres base id
uid=1000(postgres) gid=1000(postgres) groups=1000(postgres)
The volume itself also preserves the permissions when we attach it to another container. No need to run the container, just create it; the volume is usable even when the container is not running:
$ docker create --name datavolume base /bin/true
$ docker run --rm -it --volumes-from datavolume debian:jessie ls -ln /data
total 0
-rw-r--r-- 1 1000 1000 0 Jan 17 14:17 file
The permissions and ownership are preserved! Any container with user 1000:1000 will have ownership of this volume. We didn't need
a full container to define ownership, nor gosu
to run as a specific user.
This method will work for creating lightweight data volume containers as well--we don't need the /etc/passwd
file in this volume container;
preserve the permissions within the folder:
$ tar cpv data/ | docker import - minimal
$ docker create --name data-only minimal :
We need to specify some command for docker create
; in our case a good choice is :
, which does nothing.
We can also build the same thing with a Dockerfile:
$ echo 'FROM scratch
ADD data.tar /
VOLUME ["/data"]' > Dockerfile
$ docker build -t minimal .
$ docker create --name minimal minimal :
The container that mounts this minimal volume container needs to create the user with id 1000:
$ docker run --rm --volumes-from minimal -it debian:jessie /bin/bash -c 'useradd postgres && ls -l /data'
total 0
-rw-r--r-- 1 postgres postgres 0 Jan 17 14:17 file