WSL 上的 Docker 无法绑定挂载 $HOME

WSL 上的 Docker 无法绑定挂载 $HOME

我最初在 Stack Overflow 上问过这个问题,但我认为超级用户可能更合适。

我在 WSL(适用于 Linux 的 Windows 子系统,Ubuntu 16.04)上使用 Docker 时遇到了最奇怪的情况。我试图将 mount 绑定/home/username(或只是$HOME为了方便)为容器中的卷,但我没有在容器中找到我的主目录的内容,而是得到了完全不同的卷。

奇怪的是,每当我尝试绑定挂载$HOME或时,这个“其他卷”都会从一个容器持续到另一个容器/home/username。如果我触摸一个新文件,它会出现在我挂载到的所有其他容器中$HOME。所有其他绑定挂载到任何其他目录都可以正常工作。

例如,这些都共享同一个神秘文件夹:

docker run -it --rm -v /home/username:/test alpine sh
docker run -it --rm -v $HOME:/test alpine sh
docker run -it --rm -v $HOME:/test -v $HOME:/test2 alpine sh

当我执行时,docker volume ls没有名为的卷/home/username,因此排除了意外拥有同名的docker托管卷。

我正在挂载的这个神秘卷是什么?为什么 docker 不能$HOME正确挂载我的目录?

答案1

Docker 守护进程在哪里运行?我猜它在某个服务器上运行,或者如果你使用的是 Windows 版 Docker(带有 Windows 容器/LCOW),它在 WSL 之外的主机上运行。绑定挂载很可能在主持人而不是在运行 Docker 客户端的 WSL 环境中。根据你对 /c 和 /d 工作的评论,听起来它们被映射回主机上的 C:\ 和 D:\ 驱动器,这表明你正在使用 Docker for Windows

从 WSL 内部来看,驱动器似乎安装在 WSL 内部,但 rootfs 位于虚拟文件系统上,这可以解释为什么 /c 和 /d 可以正常工作

nick@nick-desktop:/mnt$ mount
rootfs on / type lxfs (rw,noatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,noatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,noatime)
none on /dev type tmpfs (rw,noatime,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,noatime,gid=5,mode=620)
none on /run type tmpfs (rw,nosuid,noexec,noatime,mode=755)
none on /run/lock type tmpfs (rw,nosuid,nodev,noexec,noatime)
none on /run/shm type tmpfs (rw,nosuid,nodev,noatime)
none on /run/user type tmpfs (rw,nosuid,nodev,noexec,noatime,mode=755)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,noatime)
C: on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000)
W: on /mnt/w type drvfs (rw,noatime,uid=1000,gid=1000)
X: on /mnt/x type drvfs (rw,noatime,uid=1000,gid=1000)
Z: on /mnt/z type drvfs (rw,noatime,uid=1000,gid=1000)

以下是一些有关 WSL 中的 Linux rootfs 如何工作的文档https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support/

Windows WSL rootfs 所在的位置列在 KCU:\Software\Microsoft\Windows\CurrentVersion\Lxss 中(请参阅https://github.com/Microsoft/WSL/issues/2578

以下是有关 Docker 架构的一些附加信息,解释了 Docker 守护进程和客户端之间的区别https://docs.docker.com/engine/docker-overview/

答案2

没有好的办法可以做到这一点,因为 MobyLinuxVM 中的 docker 守护进程不了解 WSL,反之亦然。

如果您尝试将包含 WSL 文件的 AppData 文件夹作为卷挂载,则会遇到问题,因为您在写入文件时没有创建适当的 Linux 文件系统元数据:

https://blogs.msdn.microsoft.com/commandline/2016/11/17/do-not-change-linux-files-using-windows-apps-and-tools/

可能更好的做法是在 C: 驱动器的其他位置创建一个文件夹,您可以从 WSL 下的 访问该文件夹/mnt/c,并且可以使用 从 docker 挂载该文件夹。为方便起见,您可以在 WSL内-v "C:\foldername":/test绑定挂载,以便使用 编写 docker 命令。/mnt/c/c-v /c/foldername:/test

sudo mkdir /c sudo mount --bind /mnt/c /c

https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly

如果您确实需要将 $HOME 挂载为 docker 卷,您可以尝试将您的 WSL 主文件夹设置为C:诸如上的文件夹C:\home,如下所述:

https://brianketelsen.com/going-overboard-with-wsl-metadata/

然后,您可以将其挂载C:\home为 docker 卷。但是,在 WSL 中工作时可能会遇到问题,因为您的主文件夹现在将作为drvfs文件系统而不是挂载lxfs

答案3

我遇到了同样的问题,我同意 Nijave 的观点,问题在于 Docker Host 挂载的文件系统(在我的情况下是在 Hyper-V 中运行的 MobyLinuxVM)与 WSL 管理的文件系统不同(其位置是隐藏在 C: 驱动器上的用户应用程序数据中)。

为了解决这个问题,我首先得到了可以访问 Docker 主机使用的文件系统的 shell

docker run --privileged -it -v /var/run/docker.sock:/var/run/docker.sock jongallant/ubuntu-docker-client
docker run --net=host --ipc=host --uts=host --pid=host -it --security-opt=seccomp=unconfined --privileged --rm -v /:/host alpine /bin/sh
chroot /host

然后,我将我的 WSL 主目录(使用 Windows 路径)链接到 Docker Host 使用的文件系统上的主目录:

ln -s /C/Users/WINDOWS_USERNAME/AppData/Local/Packages/CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc/LocalState/rootfs/home/LINUX_USERNAME/ /home/

之后我就可以做如下事情:

docker run -it --rm -v ~/.ssh:/root/.ssh alpine some-ssh-command

注意:Docker Core 中有一个错误是为了解决这个问题: https://github.com/docker/for-win/issues/2151

警告:您可能只应在对 $HOME 目录进行只读访问时才这样做。在上述错误中,我被告知此方法仍通过 Samba 访问 Windows 文件系统,因此如果您创建/编辑文件,您可能会遇到以下问题:https://blogs.msdn.microsoft.com/commandline/2016/11/17/do-not-change-linux-files-using-windows-apps-and-tools/

相关内容