Docker volume NFS uid - docker

I'm in the process of setting up dovecot as docker container. I want to store the Maildir via NFS on a NAS.
I'm creating the docker volume like this:
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=<ip>,rw \
--opt device=:/vmail \
vmail
in the Dockerfile, I have:
RUN useradd -m -p vmail -s /bin/false vmail
VOLUME /home/vmail
and to run the docker container, I call:
docker run \
-dit \
-p 993:993 \
--mount source=vmail,target=/home/vmail \
my_dovecot
but as a result I get:
docker: Error response from daemon: chown /var/lib/docker/volumes/vmail/_data: operation not permitted.
The issue is clearly related to the way I mount the NFS volume, as - if I drop the --mount statement - it works ok (but obviously can't access my Maildir data from the NAS).
I'm pretty sure that this is related to the fact that dovecot is trying to access the Maildir as vmail user, and that user doesn't have permissions on the NFS share - but even giving everybody write access on the NFS share doesn't make a difference.
I'm looking for any advice to get this NFS volume properly mounted into my docker container.
Regards
StHeine

in the meantime I found the issue.
to fix this, I had to remove the -m in the useradd command to prevent it from creating the /home/vmail directory:
RUN useradd -p vmail -s /bin/false vmail
VOLUME /home/vmail
because if that exists, mounting the volume into that same place, docker tries to copy existing folder data into the volume and chown this to the volume's ownership. due to the fact that the volume comes via NFS from a NAS is doesn't have proper uids, but nobody - and chown fails.
I found references to nocopy to prevent docker from doing this, but I haven't figured how to set that in the docker create statement.

Related

How do I ensure that mounted volumes always have read/write permissions by the current user on the host?

For local development of applications where isolation of folder/file permissions are not mission critical, I'd like to mount local directories into transient containers but retain the ability to delete/modify those directories from the host account without sudo.
I have read that I can create specific volumes and then mount those precreated volumes. The thing is I would like to use self-removing transient containers arbitrarily (e.g. docker run --rm -v "$(pwd):/app" golang go build src/main.go).
The objective is to make it easy to work with various technologies (like databases or languages) without needing to install them on the host.
Running
docker run \
--rm \
-v "${HOME}/foo:/app" \
alpine touch /app/bar.txt
Running this will create a folder/file with root permissions. Trying to use the --user flag still mounts the directory as root gives me the following error:
touch: /app/bar.txt: Permission denied
docker run \
--rm \
--user "$(id -u):$(id -g)" \
-v "${HOME}/foo:/app" \
alpine touch /app/bar.txt
This failure obviously extends to trying to spin up a database instance
docker run \
--rm \
--net=host \
--user $(id -u):$(id -g) \
-v "${HOME}/mongo/foo:/data/db" \
mongo:latest

Receive "connection refused" when I try to run a Docker Container with NFS Volume

I'm working with NFS Volume.
I created a NFS server and on my rasberry pi I set the client and if I mount the directory exposed I can see the content, It's mean that the configuration works.
My goal is to create a volume with the following command:
sudo docker volume create --driver local \
--opt type=nfs \
--opt o=addr=10.0.0.5,rw \
--opt device=:/export/users/reddata \
foo
As I saw in the documentation the create a NFS volume.
My problem is the follow, when I run the container:
sudo docker run -it -p 1880:1880 -v foo:/data --name mynodered -d nodered/node-red
I receive the following error:
docker: Error response from daemon: failed to mount local volume: mount :/export/users/reddata:/var/lib/docker/volumes/foo/_data, data: addr=10.0.0.5: connection refused.
See 'docker run --help'.
I this that something it's not authorized, but I also think that I can mount my shared directory on my pi the configuration previous did should works.
Do you have any idea?
Thanks for your time
Alessandro
I solved the problem.
The problem was the way to create the volume, the right way is:
sudo docker volume create --driver local \
--opt type=nfs \
--opt o=addr=10.0.0.5,nfsvers=4 \
--opt device=:/export/users/reddata \
foo
It's necessary to specify the nfsvers=4.
Another important configuration, in my case it's not necessary to supervise the host that access my folder, in the server my /etc/exports it the follow:
export/users/reddata *(rw,sync,no_subtree_check,insecure)
With the *, I specify all IPs on the network.
Best Regards
Alessandro

Docker volumes : specifying permissions using mount options

I'm trying to use a named volume mounted in a Docker container, but get a Permission denied error when trying to create a file in the mounted folder. So I'm trying to use mount options when creating my volume, but that does not work as I want.
Introduction
I'm totally aware that when mounting a volume (created by docker volume create my_named_volume) with the option -v my_named_volume:/home/user/test or --mount type=volume,source=my_named_volume,target=/home/user/test), the folder inside the container (/home/user/test will be owned by root user, even if /home/user belongs to an user user created in my Dockerfile. If I run :
docker run --rm \
--name test_named_volume \
--mount type=volume,source=my_named_volume,target=/home/user/test \
test_named_volume \
su user -c "touch /home/user/test/a"
Then I get :
touch: cannot touch '/home/user/test/a': Permission denied
I'm understanding that. That's why I'm trying to use mount options when creating my volume.
mount options
I'm specifying an uid when creating my volume, in order to make my user user able to create a file in that volume :
docker volume create my_named_volume \
--opt o=uid=1000
1000 is the uid of the user user created in my Dockerfile :
FROM debian:jessie
ENV HOME /home/user
RUN useradd \
--create-home \
--home-dir $HOME \
--uid 1000 \
user \
&& chown -R user:user $HOME
WORKDIR $HOME
But when running my container (with the same command docker run defined above), I'm getting an error (missing device in volume options) :
docker: Error response from daemon: error while mounting volume '/var/lib/docker/volumes/my_named_volume/_data': missing device in volume options.
From the docs, I see that options --device and --type are missing from my volume creation :
docker volume create my_named_volume \
--opt device=??? \
--opt type=??? \
--opt o=uid=1000
But I cannot see why I must give these options. device needs to be a block device, and from what I read, type should be something like ext4. But what I want is basically just set the uid option to my volume. It looks like creating a block device should work, but it seems too much configuration for a "simple" problem.
I have tried to use tmpfs for device and type, that works fine (file /home/user/test/a is created)... until my container is stopped (the data is not persisted, and that's logical because it's tmpfs). I want to persist that data written in the volume when the container exits.
What is the simplest way to specify permissions when mounting a named volume in a container? I don't want to modify my Dockerfile to use some magic (entrypoint that chown and then execute the command for example). It seems possible using mount options, I feel like I'm close to the solution, but maybe I'm in the wrong way.
Not entirely sure what your issue is, but this worked for me:
docker run --name test_named_volume \
--mount type=volume,source=test_vol,target=/home/user \
--user user \
test_named_volume touch /home/user/a
I think where you could have gone wrong is:
Your mount target is /home/user/test has not been created yet, since the useradd command in your Dockerfile only creates $HOME (/home/user). So docker creates the directory within the container with root permissions.
You were not using the --user flag in docker run to run the container as the specified user.
Just had this issue. And contrary to popular belief the mount did NOT pickup the permissions of the host mounted directory, it reset them.
When I did this, the permissions were changed to 777 inside the container...
volumes:
- ./astro-nginx-php7/logs:/home/webowner/zos/log:rw
The :rw made all the difference for me. My image was nginx:latest.
Docker compose version 3.3

docker how to handle permissions for jupyter notebook - 3 approaches that do not work

What is the best practice for handling uid/gid and permissions with jupyter notebooks in docker?
When one of the jupyter+python Dockerfiles in jupyter/docker-stack is run, a notebook gets saved with uid/gid 1000:100. This will fail if a mounted host folder is not writable by "other", which is an ugly approach.
The notebook image can be run specifying the NB_UID and NB_GID, like this:
docker run -p 8888:8888 -it --rm \
-e NB_UID=$(id -u) \
-e NB_GID=$(id -g) \
-e GRANT_SUDO=yes \
--user root \
--mount type=bind,source="$(pwd)",target=/home/jovyan/work \
myimage
In this case, the uid/gid of joyvan in the container match my uid/gid, so there is no permissions problem writing to a mounted folder. However, now jovyan (the container user) cannot access /opt/conda, which is owned by 1000:100 and is not readable by other. So all the add-on packages cannot be loaded!
We could also run docker build with --build-arg myuid=$(id -u) --build-arg mygid=$(id -g)
I believe this would result in both /home/jovyan and /opt/conda being owned by the same uid:gid as me, everything good. However, the resulting image can be used only by me. If I give it to my collaborators (who has a different UID), it will not work.
So it seems that every possibility is blocked or a poor choice. File permissions in docker are difficult.
Can anyone share the best approach for this problem?
The best practise with Jupyter Notebook is to use your own user id and group id so the new files you create will have correct ownership. Then use --group-add users to add yourself to users group to get access to the required folders (e.g. /opt/conda).
The full command would be:
docker run -it --rm --user $(id -u):$(id -g) --group-add users -v "$(pwd)":/home/jovyan -p 8888:8888 jupyter/scipy-notebook
I encountered the same problem and found a good solution which is referred from here.
COPY --chown=1000:100 hostfolder/* /home/$NB_USER/work/
Note that environment or argument expansion in command options is not implemented yet, thus following line would cause build error failed to build: unable to convert uid/gid chown string to host mapping: can't find uid for user $NB_UID: no such user: $NB_UID
# COPY --chown=$NB_USER:$NB_GID hostfolder/* /home/$NB_USER/work/
Therefore, need to hard code the user(jovyan) and group name(users) or id(1000:100).

How to let dockerd create bind volume dirs with the correct permission

When I run a docker container with the following command :
docker run -ti -v /tmp/michael:/opt/jboss/wildfly/standalone/log jboss
dockerd creates the directory /tmp/michael with owner and group = root. This of course results in permission denied erros for jboss when trying to write its logfiles.
I have to create /tmp/michael manually and give chmod g+w permissions to fix that. dockerd then reuses the existing dir with the correct permissions. This is not what I want. Does anybody know how to force dockerd to create these Directories with the correct permissions
Addtional Information :
Dockerfile :
FROM jboss/wildfly
ADD entrypoint.sh /
ENTRYPOINT "/entrypoint.sh"
entrypoint.sh : (for testing purposes just a touch on the file instead of starting jboss)
#!/usr/bin/env bash
chown jboss:jboss /opt/jboss/wildfly/standalone/log
myfile=lala.`date +"%s"`
touch /opt/jboss/wildfly/standalone/log/${myfile}
But even here if /tmp/michael does not exist and does not have group +w I do receive permission denied. I have no Idea how to get rid of that
You have two possibilities:
chown somewhere in the ENTRYPOINT (making an .sh for entrypoint) (to make this possible from inside the container)
Something like chown jboss:jboss /opt/jboss/wildfly/standalone/log
Change permissions directly outside the container (in the host)
You will not have jboss user or group, you need to do directly with de id.
Look the container /etc/passwd and get the jboss user id (docker exec jboss cat /etc/passwd), write down the id and make chownin the host:
chown 1001:1001 /tmp/michael
Best way is 1, of course. You can use a docker volume for it, etc. Easiest way is 2.
In addition to Alfonso's answer, there's a third option to use a named volume to initialize the directory. You'll need to create the directory with the correct permissions inside your image first. E.g. your Dockerfile could contain the lines:
RUN mkdir -p /opt/jboss/wildfly/standalone/log \
&& chmod 775 /opt/jboss/wildfly/standalone/log
Then on your host you can create the named volume in advance:
docker volume create --driver local \
--opt type=none \
--opt device=/tmp/michael \
--opt o=bind \
jboss_logs
And finally run your container using that named volume:
docker run -ti -v jboss_logs:/opt/jboss/wildfly/standalone/log jboss
As long as /tmp/michael exists but is empty, it will be initialized with the contents of your image, including file and directory permissions, before the container is started.

Resources