Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for unix file permissions using a volume driver possible? #2042

Closed
Ageraluon opened this issue May 16, 2018 · 14 comments
Closed

Support for unix file permissions using a volume driver possible? #2042

Ageraluon opened this issue May 16, 2018 · 14 comments

Comments

@Ageraluon
Copy link

@Ageraluon Ageraluon commented May 16, 2018

The largest limitation that I am facing using Docker for windows is that all files mounted via a volume are assigned UID 0 : GID 0 755 unix file permissions, which cannot be changed.
Since many linux docker projects involve processes that need file permissions to be changed, these projects cannot be run on a windows host without severe modifications - examples are the standard apache server, nextcloud or gitlab which change file permissions to special users created in the container and fail if they are not able to do so.

Would there be any way to extend that functionality, like creating a volume driver that stores permissions in a special file on the volume on the host and reflects these permissions to the linux container? This could maybe even be expanded to an ACL later on. I would be willing to invest some time in this endeavor, but unfortunately do not have very specific knowledge on the plugin system or how to model this yet. So any hint on where and how to start would be welcome. Would this be even doable by creating a standard volume plugin?

Thank you for your insight!

@rn

This comment has been minimized.

Copy link
Contributor

@rn rn commented May 17, 2018

@Ageraluon thanks for the issue. Docker for Windows currently uses SMB/CIFS for host volumes. Unfortunately that protocol does not support multiple users nor different file permissions. So this is not something which is easily changeable.

A common approach to overcome this limitation is to create a local volume docker volume create and mount that into containers. This does not allow sharing the files with the host but it makes them persistent across runs. You can then bind mount other files, say your source code for whatever service you are using.

Another future option is Linux Container on Windows (LCOW). This uses a entirely different approach to mounting the host filesystem into the container (using 9p). This currently provides less Unix semantics than SMB/CIFS but has the potential to provide a better mapping in the future. LCOW is developed primarily by Microsoft and I have little visibility on the roadmap.

I'm closing this issue for now, as this is not something we can fix but feel free to ask further questions. I hope the suggestion above may help

@rn rn closed this May 17, 2018
@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 17, 2018

@rn Thank you for your detailed answer, this helps me a lot in understanding the nature of the problem. I get that the issue is rather with the SMB/CIFS limitation than anything docker-specific.

Further search gives me the impression that while using this protocol it is not possible to change file permissions during run time, it seems however basically possible to mount a CIFS share with a specific UID/GID and global set of file/folder permission at, like in this example:

https://ubuntuforums.org/showthread.php?t=1951219&s=d3199a9da1f6d83ac1213ffc4e6b23af&p=11811816#post11811816

//<ip-address>/share/<folder_name> /media/buffalo cifs noauto,rw,dir_mode=0777,file_mode=0666 0 0

Would it basically be possible to add configuration options to a docker share that mount a (non-named) volume with a specific combination of UID:GID (XXXX) permission set?

I'll also continue investigating further down the LCOW Road, thank you very much for the hint!

@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 20, 2018

Further search gives me the impression that while using this protocol it is not possible to change file permissions during run time, it seems however basically possible to mount a CIFS share with a specific UID/GID and global set of file/folder permission at, like in this example:

https://ubuntuforums.org/showthread.php?t=1951219&s=d3199a9da1f6d83ac1213ffc4e6b23af&p=11811816#post11811816

//<ip-address>/share/<folder_name> /media/buffalo cifs noauto,rw,dir_mode=0777,file_mode=0666 0 0

Would it basically be possible to add configuration options to a docker share that mount a (non-named) volume with a specific combination of UID:GID (xrwxrwxrw) permission set?

If this is not the case, this thread can be closed.

EDIT: More fine-grained mounting options seem to appear in this example:
https://askubuntu.com/a/764028

//192.168.0.5/storage /media/myname/TK-Public/ cifs username=YOURUSERNAME,password=YOURPASSWORD,iocharset=utf8,file_mode=0777,dir_mode=0777

This suggests the use of umask instead of filemode/dir_mode:
https://stackoverflow.com/a/40527234

//address/location /mount/location cifs credentials=/location,uid=id,gid=id,umask=700 0 0

@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 21, 2018

another issue for which this might be of help:

#2048

@rn

This comment has been minimized.

Copy link
Contributor

@rn rn commented May 24, 2018

@Ageraluon thanks for the pointers. I was aware of most of them.

Currently Docker for Windows mounts the shared drives once into the Linux VM and then the host volumes are simple bind mounts from the root filesystem into the container. This means there is only one set of SMB/CIFS mount options for the entire system, basically you can't change the uid/gid/permissions on a per container basis. Allowing the user to change the global options is also problematic as settings for one container are likely not working for another container, so we stick to some common parameters.

Creating a SMB mount on the fly per container is also problematic, not just for passing in arguments, but also clean up, scaling etc.

One potential solution would be to use a SMB/CIFS volume plugin and explicitly create custom volumes and use those when running containers. It's not quite as flexible but may work for some use cases. I don't know if there is a suitable SMB/CIFS volume plugin for docker. I haven't tried it, but maybe something like https://hub.docker.com/r/trajano/cifs-volume-plugin/ might work (see the Testing outside the swarm section...also note there is no link to the source code so be careful running arbitrary binaries...). I also had a quick look at https://github.com/ContainX/docker-volume-netshare but that seems to be doing most of the volume plugin setup from Linux host, so might not be suitable.

@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 26, 2018

@rn: Thank you very much for your insight in this matter and the most helpful pointers!

One potential solution would be to use a SMB/CIFS volume plugin and explicitly create custom volumes and use those when running containers.

This would be exactly what I am looking for! I'll try these out and see whether they can be of help here. Unfortunately, right now it looks as if the trajano/cifs-volume-plugin/ also requires a credentials file for each share mounted in the linux (vm) host in the /root folder. I'll report if I can work around that.

Allowing the user to change the global options is also problematic as settings for one container are likely not working for another container, so we stick to some common parameters.

Fully agreed.

Creating a SMB mount on the fly per container is also problematic, not just for passing in arguments, but also clean up, scaling etc.

Currently Docker for Windows mounts the shared drives once into the Linux VM

Agreed, one bind mount per container also seems inefficient to me. For the initial mount into the VM, there is still one mount operation per volume needed, correct? Also, if 'docker run' is called with a '-v' option, a new bind operation would be executed anyway, correct? Might it theoretically be possible to make these mounts a little more flexible and allow for a specific uid/gid/perm set per mount? These would then still be available to all containers that attach to that volume using the mount from the linux root system into the containers (and thus allow for the same efficiency in scaling/cleanup, etc).

Only being able to create a volume with the --mount option to 'docker run' with a specific uid/gid/perm set might be enough to pose a solution to this limitation in a first step. Here, the uid/git/perm would be given as extra options to the 'docker run --mount' command which would even allow to mount the same folder with permission set 'A' for container/stack/swarm A and a different permission set 'B' for container/stack/swarm B.

Provided you would deem this stuff above theoretically possible/ also sensible, I'd be willing to try some legwork with a possible implementation. I am not that versed in go though and would be very grateful for some hints which parts of docker (I guess the moby vm ?/ the docker engine?) might need to be modified to facilitate this.
Meanwhile, I'll research on the plugins!

Thank you for any input on this!

@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 27, 2018

There are two options that might seem feasible for me as of now:

1.) Modify the 'local' windows driver to allow for unix-local-driver style options : (https://github.com/moby/moby/blob/9c2c887b125df56e622d20ebbbe626c55b61e44a/volume/local/local_windows.go#L30), or modify the --mount option for docker run. The latter already allows for host to vm mounting but modifications might be time-intensive and I do not have enough overview to see whether this might break any compatibility. The former might lead to development of a windows volume plugin on the basis of the unix 'local' driver - maybe a more feasible/compatible option, but the actual host-to-vm mounting would need to be added

2.) The netshare-plugin looks very promising, but as @rn already mentioned, seems to rely heavily on the linux host (the moby vm) to be modified. This article: https://forums.docker.com/t/how-can-i-ssh-into-the-betas-mobylinuxvm/10991 describes how the vm might be accessed in order to make the required modifications (as described in http://netshare.containx.io/docs/cifs, the netwhare deb packet would need to be installed and the following command would need to be run inside the vm:

sudo docker-volume-netshare cifs

Here, we'd probably be violating a lot of security concerns, and this would not be a permanent solution but more like a hackfix that might bridge the time until the LCOW mounts are more developed. So this would make sense only if there is some development on the horizon. I've started a thread here: moby/moby#37158 in the hope to get some estimate on this.

?3.)? Installing a samba client in a separate (privileged?) docker container, 'mounting' the shares there with specific options and then (how?) mounting these as volumes in other containers? (Based on this? : https://hub.docker.com/r/irobie/moby-cifs-mount/) Alternatively: this? : https://hub.docker.com/r/dli16/cifs-alpine/

@Ageraluon

This comment has been minimized.

Copy link
Author

@Ageraluon Ageraluon commented May 29, 2018

For the reference, as @rn and @thaJeztah helped me figure out, here:

moby/moby#37161

mounting volumes with specific uid/gid/permissions set is actually possible using standard docker syntax:

docker volume create \
  --opt type=cifs \
  --opt device=//Server/Testvolume \
  --opt o=username=Testuser,password=Testpassword,file_mode=0777,dir_mode=0777,uid=2000,gid=2000 \
  myvolume

The local driver for linux containers on windows hosts fully supports the extra option set. That should actually fully solve the issue without any need for plugins.
Thank you both!

@rn

This comment has been minimized.

Copy link
Contributor

@rn rn commented May 31, 2018

@Ageraluon glad it works for you. You may want to use 10.0.75.1 instead of server name. You may get better perf that way as well

@MatthewLymer

This comment has been minimized.

Copy link

@MatthewLymer MatthewLymer commented Sep 10, 2018

I am having a similar issue, I am using Postgres and postgres complains about the PGDATA folder being hosted on Windows about file owners.

Would it be possible to create a virtual ext hdd from within the container that's in a folder that's mounted within a shared volume?

@alesana-san

This comment has been minimized.

Copy link

@alesana-san alesana-san commented Feb 27, 2019

Hi!

I'm in the need as @Ageraluon was. I want to mount a host folder with proper permissions.
But I face permission denied error when running container using -v myvolume:/home/path.
Am I lacking some permissions or flags passed when creating a volume?

@thaJeztah

This comment has been minimized.

Copy link
Member

@thaJeztah thaJeztah commented Feb 27, 2019

@alesana-san -v myvolume:/home/path will mount a volume named myvolume, so that's not mounting a path from the host. If you want to bind-mount a path from the host, you need to use -v /path/on/host:/path/in/container

However, when bind-mounting files/directories from the host, take into account that;

@alesana-san

This comment has been minimized.

Copy link

@alesana-san alesana-san commented Feb 27, 2019

@thaJeztah, wow, thanks for a quick response!
I wanted to try a trick that @Ageraluon described:

  • Create a volume with docker create volume under my Windows 10 host;
  • Pass it to my docker run command like -v myvolume:/some/path

But I get permission denied error.
Here's an example:

PS C:\Users\Роман Ширяев\Desktop> docker volume rm myvolume
myvolume
PS C:\Users\Роман Ширяев\Desktop> docker volume create --opt type=cifs --opt device=//10.0.75.1/hlds --opt o=username=dockerfile,password=docker myvolume
myvolume
PS C:\Users\Роман Ширяев\Desktop> docker run --rm -v myvolume:/root -it --privileged debian:stretch bash
C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: error while mounting volume with options: type='cifs' device='//10.0.75.1/hlds' o='username=dockerfile,password=docker': permission denied.
See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'.
PS C:\Users\Роман Ширяев\Desktop> docker version
Client: Docker Engine - Community
 Version:           18.09.1
 API version:       1.39
 Go version:        go1.10.6
 Git commit:        4c52b90
 Built:             Wed Jan  9 19:34:26 2019
 OS/Arch:           windows/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.1
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.6
  Git commit:       4c52b90
  Built:            Wed Jan  9 19:41:49 2019
  OS/Arch:          linux/amd64
  Experimental:     false
@alesana-san

This comment has been minimized.

Copy link

@alesana-san alesana-san commented Mar 2, 2019

After some trials and tributations I found a solution that worked for me.
Preset: I'm trying to make a docker image for HLDS server (Counter-Strike 1.6). When container starts I copy all config files in an opt folder and create links instead of actual files in right dirs. So when you binding a host dir to opt folder you can configure your server from your host machine. But when using regular F:\some\dir:/opt my HLDS server threw errors that it couldn't find some files and couldn't _stat some files. First I thought it's because root owned the mounted host dir so my guest Debian user couldn't do stuff with my files in a mounted dir. Then I ran into this topic and tried @Ageraluon solution. But it failed because of error above (permission denied).
So accidentally I left some files in a //10.0.75.1/hlds (dir wasn't empty) and my container successfully started and all files in a mounted dir were owned by non-root user!
I thought it solved my riddle but no. HLDS server still threw errors like nothing changed. I tried mount command inside a container and check all options used to mount my cifs dir. I tried to changed them and after adding noserverino to my docker create volume options my server started successfully.
So @thaJeztah can you help with explanation of such strange (for me, at least) behaviour of mounting a host dir?
To sum up, I did the following:

  1. Put dummy file to the mounting dir
  2. Added noserverino option
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.