在 Windows 上的 Docker 容器内使用 PHP 时(例如使用 DDEV),在容器内创建的符号链接(例如由 composer)似乎无法与 PHP 的文件流一起正常工作。
设想
想象一下下面的 PHP 代码
<?php
mkdir('demo-base-directory');
symlink('demo-base-directory', 'demo-symbolic-link');
var_dump(glob('demo-*', GLOB_ONLYDIR));
如果在容器内执行,它只输出demo-base-directory
,但是demo-symbolic-link
缺少(在 Docker 容器内的 Linux/Unix 系统上,同样的示例按预期工作)
array(1) {
[0]=>
string(19) "demo-base-directory"
}
在主机系统中查看符号链接时(例如cat demo-symbolic-link
在 Windows PowerShell 中使用),它显示
XSym
0019
0df68e8650ddca993c28277a5cfa3dcd
demo-base-directory
Docker for Windows 还有其他关于符号链接仿真的报告 - 我无法为使用fgets
或file_get_contents
但对于提到的glob
调用的文件重现此行为,请参阅
共享卷以 Samba/CIFS 挂载方式挂载在 Windows 主机系统上基于 Linux 的 Docker 容器中,如下所示:
//10.0.75.1/C on /var/www/html type cifs (rw,relatime,vers=3.02,sec=ntlmsspi,cache=strict,username=olly,domain=OLIVERHADERB9D8,uid=0,noforceuid,gid=0 ,noforcegid,addr=10.0.75.1,file_mode=0755,dir_mode=0777,iocharset=utf8,nounix,serverino,mapposix,nobrl,mfsymlinks,noperm,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
挂载选项mfsymlinks
是指Minshall+French 符号链接
解决方法
与其在容器内部创建符号链接,不如在外部(直接在 Windows 中)创建符号链接来解决问题。
在 cmd.exe 中使用普通的 mklink
del demo-symbolic-link
mklink /d demo-symbolic-link demo-base-directory
输出
symbolic link created for demo-symbolic-link <<===>> demo-base-directory
在 PowerShell 中通过 cmd 使用普通 mklink
del demo-symbolic-link
cmd /c mklink /d demo-symbolic-link demo-base-directory
输出
symbolic link created for demo-symbolic-link <<===>> demo-base-directory
旁注:New-Item -ItemType SymbolicLink
无法解决使用glob(..., GLOB_ONLYDIR in PHP
-mklink /d
也在这里使用
在 Windows 上使用 Git-Bash
在以管理员身份执行 Git-Bash 时,我必须执行以下操作。在这里设置环境变量export
很重要 - 请参阅为 Cygwin 启用本机 NTFS 符号链接
rm demo-symbolic-link
export MSYS=winsymlinks:nativestrict
ln -s demo-base-directory/ demo-symbolic-link
辅助工具
我创建了帮助工具示例,用于XSym
在特定目录(与 TYPO3 相关public/typo3conf/ext/
)中搜索 Samba 指针并将 XSym 指针“升级”到正确的符号链接 - 执行这些脚本时可能需要管理员权限:
结果
现在再次从上面执行 PHP 示例会输出两个预期的项目
array(2) {
[0]=>
string(19) "demo-base-directory"
[1]=>
string(18) "demo-symbolic-link"
}
问题
在 Docker 容器中工作并且必须在主机系统上手动调整符号链接实际上只是一种解决方法,而不是解决方案。为了仅使用 Docker 容器创建正确的符号链接,可以在哪个级别进行增强和优化?
似乎这可以在不同的层次上解决:
- PHP的
glob
调用(尤其是flakyGLOB_ONLYDIR
flag) - glibc 的
glob
实现(尤其是Minshall+French symlinksXSym
) - Docker 不使用 Samba/CIFS 进行卷共享
更新
- 从
mklink /j
(junction) 切换到mklink /d
(symlinked directory) 因为删除链接的联结也删除了它的起源 - PowerShell 的符号链接 cmdlet
New-Item -ItemType SymbolicLink
(而不是以前的New-Item -ItemType Junction
)在 PHP 中再次无法解析glob(..., GLOB_ONLYDIR
- 因此,cmd /c mklink /d
在此处使用 - 添加了 Samba/CIFS 挂载信息