Docker 不实现任何文件或目录访问。作为设计问题,这根本不是 docker 所做的。
docker 在启动容器时所做的就是创建一堆挂载,以便容器内的进程可以发出它们的常规 POSIX 调用。当容器内的进程调用write()时,该调用直接进入Linux内核,无需docker知晓或干预。
现在,您的难题中缺少一个必须以一种或另一种方式实现的部分:应用程序调用例如POSIX write() 函数,而您的文件系统无法拦截此 write() 函数。
所以你有几个选择:
选项 1:在库中实现您的用户空间文件系统:
- 该库将覆盖
write() 函数。
- 您编译库并将其放在某个目录中,例如
/build/artifacts/filesystem.so。
- 您在运行容器时将该目录用作卷,例如
docker run -v /build/artifacts/filesystem.so:/extralibs/filesystem.so ...
- 您将此文件系统添加为预加载库:
docker run ... --env LD_PRELOAD=/extralibs/filesystem.so ...
这将使容器中的所有调用使用您的库,因此它应该将所有不相关的文件(例如/bin/bash、/etc/passwd 等)转发到真实的文件系统。
如果您可以控制图像,则可以将其设置为仅使用此 LD_PRELOAD 执行特定命令。
公平警告:实现一个覆盖系统调用和 libc 的库有很多需要解决的陷阱。一个例子是,如果程序使用例如fprintf(),那么即使fprintf() 调用write(),你也必须覆盖fprintf()。
选项 2:修改应用程序以仅调用您的 filsystem 函数。
这是假设您可以修改应用程序和 docker 映像。
如果您的文件系统是服务,请在容器中运行它并发出适当的 RPC。
如果它需要与其他容器共享,那么文件系统的后备存储可以是一个卷。
选项 3:让您的用户空间文件系统在容器内本地可用。
意味着任何命令都可以发出write() 直接进入内核,内核将其重定向到您的文件系统。
这实质上意味着将您的文件系统实现为 fuse 守护程序,将其挂载到主机上(看看您如何无法将其挂载到容器中),并将其用作 docker 卷。
如果存在不允许在主机上挂载文件系统的特定限制,那么您需要做很多工作才能使选项 1 起作用。否则,我会建议您使用 fuse 实现文件系统并将其安装在主机上 - 它具有最高的投资回报率。