在Docker容器中挂载SMB/CIFS共享

77

我有一个在Docker容器中运行的Web应用程序。该应用程序需要访问我们公司文件服务器上的一些文件(带有Active Directory域控制器的Windows Server)。我要访问的文件是为我们的客户创建的图像文件,Web应用程序将其作为客户组合部分的一部分显示。

在我的开发计算机上,我通过/etc/fstab中的条目挂载了适当的文件夹,并且使用--volume参数在Docker容器中挂载主机挂载点。这完美地起作用。

现在我正在尝试组装一个生产容器,在不依赖于主机上挂载CIFS共享的情况下在不同服务器上运行。因此,我尝试将适当的条目添加到容器中的/etc/fstab文件中,并使用mount -a将它们挂载。我得到了mount error(13): Permission denied

在线上做了一些研究,我找到了有关Docker安全性的这篇文章。如果我理解正确,似乎Docker明确拒绝在容器内挂载文件系统的能力。我尝试以只读方式挂载共享,但这也(毫不奇怪地)失败了。

因此,我有两个问题:

  1. 我是否正确理解Docker阻止在容器内使用mount的任何用途?

  2. 有人能想到另一种不需要在主机上挂载CIFS共享然后将主机文件夹挂载到Docker容器中来完成此操作的方法吗?


请问您能否分享一下代码,说明如何修改 /etc/fstab 文件以包含网络驱动器的详细信息?此外,您是否在 DOCKERFILE 中完成了所有这些操作? - Ankush Jain
1
@AnkushJain 我不经常这样做,但当我这样做时,我通常会参考此文档页面 - Kryten
2
我在这里写了一篇关于完整的基于C#.NET解决方案的博客 - https://coderjony.com/blogs/mount-a-windows-share-on-linux-container-using-cnet/ - Ankush Jain
5个回答

63

是的,Docker出于安全考虑防止您将远程卷作为容器内部挂载。如果您信任您的镜像和运行它们的人,则可以在docker run命令中使用--privileged标志来禁用这些安全措施。

此外,您可以结合使用--cap-add--cap-drop,使容器只具备其实际需要的功能权限。(参见文档) SYS_ADMIN 权限授予挂载特权。


我已经在docker run命令中添加了--privileged标志...但我的CIFS共享在容器启动时无法自动挂载。如果我在容器内部输入mount -a,则一切正常。 有什么建议吗?谢谢。 - Fabrizio A
@FabrizioA 挂载卷是客户端的责任。允许(或禁止)挂载卷是 Docker 的责任。如果您需要更多帮助,应该提出一个新问题,因为这与 Kryten 的问题不同。 - Nathaniel Waisbrot
嗨,@NathanielWaisbrot,好的,我会开一个新问题。谢谢。 - Fabrizio A

34
  1. 是的
  2. 有一个已关闭的问题容器内mount.cifs

https://github.com/docker/docker/issues/22197

根据该问题,添加以下内容到运行选项中:

--cap-add SYS_ADMIN --cap-add DAC_READ_SEARCH

将使 mount -t cifs 可以操作。

我试过了,容器内的以下命令可以正常工作:

mount -t cifs //<host>/<path> /<localpath> -o user=<user>,password=<user>


我还需要添加 --security-opt apparmor:unconfined - Steve
5
这个方法以前对我起作用,但现在又需要“特权”才行 :-/ - Günter Zöchbauer

17
您可以使用Samba软件包中的smbclient命令在Docker容器内访问SMB/CIFS服务器,而无需挂载它,就像使用curl下载或上传文件一样。关于此问题,Unix StackExchange上有一个相关的问题。
smbclient //server/share -c 'cd /path/to/file; put myfile'

对于多个文件,可以使用-T选项创建或提取.tar存档文件,但这似乎需要进行两步操作(一步创建.tar文件,另一步在本地提取)。我不确定是否可以使用管道在一步中完成。

1
你刚刚帮我解决了一个巨大的头痛问题,非常感谢。 - Jeremy Morren

4
不要通过暴露许多端口来挂载共享文件夹,或者使用--privileged运行容器以降低其安全性。以下是我解决这个问题的方法:
1. 首先,在运行Docker的服务器上挂载卷。 sudo mount -t cifs -o username=YourUserName,uid=$(id -u),gid=$(id -g) //SERVER/share ~/WinShare 在此更改用户名、服务器和WinShare。它将要求您输入sudo密码,然后要求您输入远程共享的密码。
假设您在home文件夹中创建了WinShare文件夹。运行此命令后,您应该能够在WinShare文件夹中看到所有共享的文件夹和文件。此外,由于您使用uid和gid标签,因此您将无需始终使用sudo即可具有写入权限。
2. 现在,您可以使用-v标记在服务器和容器之间共享一个卷。
例如,您可以像下面这样运行它。 docker run -d --name mycontainer -v /home/WinShare:/home 2d244422164 现在,您应该能够从容器中访问并修改Windows共享。
3. 要测试,请执行以下操作: docker exec -it yourRunningContainer /bin/bash cd /Home touch testdocfromcontainer.txt 现在,您应该能够在Windows共享中看到testdocfromcontainer.txt

9
这种方法可行,但需要在主机上进行更改,并且在多用户场景中存在问题,每个容器都需要具有特定用户的访问权限。(OP明确要求“解决方案不依赖于CIFS共享在主机上被挂载”) - hans_meine
似乎在OSX上无法工作。似乎对于在rootfs之上挂载的文件系统有一个特殊的例外。 - sherrellbc

4
你可以使用Netshare Docker卷插件,它允许您将远程CIFS / Samba挂载为卷。请参考此文档

1
由于该网站已不再提供服务,这里提供该项目的Github页面链接:https://github.com/ContainX/docker-volume-netshare请注意,最后一次提交是在2020年。 - Jayrassic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接