在Docker容器中使用符号链接挂载主机目录

200

我使用以下参数挂载容器:

-v /home/test/:/home/test

在主机的 /home/test 目录下有一个符号链接指向 /mnt/ 文件夹。

但是,在容器内部,这个链接似乎无法使用,尽管可以看到它指向了哪里。

root@f93f72b45013:/var/www/html# cd /home/test/ 
root@f93f72b45013:/home/test# ls -lrt 
total 11956 
lrwxrwxrwx. 1 root root 40 Jul 20 15:55 file -> /mnt/mountedfile/
root@f93f72b45013:/home/test# ls -lrt file/*
ls: cannot access file/*: No such file or directory

在docker中是否有可能完成这个任务?我不确定是否有方法可以做到。

我知道我可以直接挂载符号链接指向的位置,但我只是想知道这是否可行。


我听说过将数据映射到 /mnt 终端可能会出现问题,这可能是特定于主机的。如果可以的话,最保险的做法是避免使用它。 - ldg
摆脱符号链接混乱的一种可能方法是使用 mount --bindbind -t overlay。这些都是本地 Linux 内核功能,在容器内部完美运行。 https://unix.stackexchange.com/a/198591/423231 如果您没有合并两个目录的计划,请选择绑定挂载。 - pPanda_beta
6个回答

258

符号链接在Docker中是一个很大的挑战。在您的情况下,您可以挂载两个目录:

-v /home/test/:/home/test -v /mnt/mountedfile:/mnt/mountedfile

为了使符号链接在容器内外都能正常工作,它们必须是绝对路径,并且使用完全相同的名称。

总的来说,在docker中符号链接不能正常工作。我是通过艰难的方式发现这个问题的。


如果我在Windows中创建了一个符号链接,该怎么办?路径可能是c:\(带有驱动器字母、分号和反斜杠)? - Eitan
5
当您想要使用Docker进行工作时,请离开Windows并拥抱Linux/Unix系统。 - Nam G VU
是的,我已经意识到Windows使用CIF,而NFS仅适用于Windows Server版本(为什么这个基本功能只在Windows服务器上 - 只是因为它需要花费,而Microsoft希望你付款)。 - Eitan
1
整整一天都在努力尝试让Laravel storage符号链接工作。对于 docker-compose 配置,应该像这样:volumes: [./:/var/www, ./public/storage:/var/www/public/storage]。这里的 public/storage 是指向 ./storage/app/public 的符号链接。感谢您提供的解决方案! - Yan Ivanov
我能够在docker 4.2.0和Windows 10中使用相对路径的符号链接。然而,绝对路径的符号链接无法正常工作。 - J.Vo
谢谢,这帮助我解决了我的问题。想要补充一点,在声明挂载的顺序也很重要(至少对于docker compose来说)。在我的情况下,volumes: [./web/linked_folder/:/var/www/web/linked_folder/, ./:var/www] 可以工作,但是 volumes: [./:var/www, ./web/linked_folder/:/var/www/web/linked_folder/] 就不行。希望这能帮到别人。 - Belac

33
一种解决方法是让Docker挂载原始文件,但使用readlink -f来打印文件的实际位置。这样,您仍然可以在命令中引用符号链接位置,例如:docker run -it -v $(readlink -f /home/test/):/home/test/ ...

无法工作 - 这会导致相同的丢失符号链接。 - Ami Mahloof
在 macOS 上:perl -MCwd -le 'print Cwd::abs_path(shift)' "$path"(来自 https://dev59.com/5nVD5IYBdhLWcg3wWaNh) - akauppi
15
我没有在 Docker 中测试过,但是通过使用 readlink 进行实验,看起来如果 /home/test/ 是符号链接,则这将起作用,但如果 /home/test/ 包含符号链接,则不会。 - Justin Donnelly
1
如何将此变量放入docker-compose文件中? - Ömer An

10

你好,感谢您的帮助。在我这个案例中,我正在努力使我的angular nginx应用程序启用https。

docker run -p 80:80 -p 443:443 \
   --name test \
   -v /etc/letsencrypt/live/exemple.com:/etc/nginx/certs \
   -v /home/admin/nginx-default.conf:/etc/nginx/conf.d/default.conf:ro test

无法将 cert.pem 和 privkey.pem 链接到 Docker 内部

但是,如果我像这样显式地使用所有文件路径

docker run -p 80:80 -p 443:443 \
   --name test \
   -v /etc/letsencrypt/live/example.com/cert.pem:/etc/nginx/certs/cert.pem \
   -v /etc/letsencrypt/live/example.com/privkey.pem:/etc/nginx/certs/privkey.pem \
   -v /home/admin/nginx-default.conf:/etc/nginx/conf.d/default.conf:ro test

一切都顺利进行了,我想你可以用docker-compose完全做同样的事情。


如果我挂载整个目录,Docker 就无法读取符号链接,我必须在 docker-compose yml 中链接每个 pem 文件。 - Marc Guillem

6

这是可以做到的,但如果你有指向随机位置的随机文件的符号链接,那么实际上可能并不值得。

但考虑以下情况:

你有两个文件夹,一个包含真实文件,另一个包含指向真实文件的符号链接:

/static-data/
|_ data-file1.dat
|_ data-file2.dat
|
|__index/
   |_a.txt
   |_b.txt

/other/
|_ data-file1.dat -> /static-data/data-file1.dat 
|_ data-file2.dat -> /static-data/data-file2.dat 
|
|__index/
   |_a.txt
   |_b.txt

现在,如果您在容器中挂载/other:/data

当您执行ls -lah /data时,您会看到损坏的链接,因为容器中不存在/static-data。解决方案是在主机上创建损坏的链接,假设/other对主机不是直接重要的,以便被破坏,因此您的新结构将是:

/other/
|_ data-file1.dat -> /mirror/data-file1.dat 
|_ data-file2.dat -> /mirror/data-file2.dat 
|
|__index/
   |_a.txt
   |_b.txt

然后您需要2个挂载记录

/other:/data
/static-data:/mirror

现在,当您运行容器时,对于主机来说破损的符号链接,在容器中不再是破损的,所以/data/data-file1.dat -> /mirror/data-file1.dat并且容器已经挂载了/mirror,因此从主机指向/static-data/data-file1.dat的符号链接。 如果您不想在主机上有破损的符号链接,那么您可以将两个目录都挂载为:
/other:/data
/static-data:/static-data

现在链接可以在主机和容器中有效。

正如您所看到的,这是可行的,我进行了测试并且它可以工作,但只适用于明显的文件群集。如果全部随机,那么您将最终挂载许多目录或可能是单个文件,以反映主机结构在容器中的情况。


2

我无法回复之前的答案,但在类似的情况下,我需要获取一个链接文件,在compose文件中设置完整的文件路径像你建议的那样对我有用:

  - /opt/cert/ssl/live/example.com/cert.pem:/certs/cert.pem
  - /opt/cert/ssl/live/example.com/privkey.pem:/certs/privkey.pem

cert.pemprivkey.pem两个文件在example.com下,它们都是指向Certbot定位证书的文件的链接。


目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

0

我认为解决这个问题的好方法是:

在 Docker 容器中,从主机挂载的符号链接可能无法正常工作。但是,在 Docker 容器内创建的符号链接可以正常工作。因此,一种好的方法是首先将感兴趣的根目录(使用绝对路径)挂载到容器中,然后在容器内创建符合需求的结构的符号链接。通过这种方式,您就可以很好地解决这个问题。

希望这能有所帮助。


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

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