是否可以获取 docker 容器的 rootfs 而不管使用的存储驱动程序如何?
Is it possible to get the rootfs of a docker container regardless of the storage-driver used?
我正在尝试通过将文件夹从 container 安装到 host 来使用 docker 进行开发,作为标准主机到容器的方法不适用于我正在处理的某个项目。
目前,我按照 issue:
中的建议使用 bindfs
(这也映射了用户权限)来做到这一点
pid=$( docker inspect -f '{{.State.Pid}}' "$container")
root=/proc/$pid/root
sudo bindfs --map=1000/"$(id -u)" "$root$source" "$target"
但是,从 proc
中获取 rootfs
似乎非常 脆弱 ,因为它取决于过程的 pid
。有其他方法可以做到这一点吗?
如果有找到 rootfs
的方法——无论使用何种存储驱动程序,我都可以在 bindfs
中使用它。 Where is the rootfs of container in host machine after docker 1.6.0 说它可能会根据使用的存储驱动程序而有所不同,但没有说明如何获得它。
由于性能原因,我真的不敢使用依赖于特定存储驱动程序的解决方案。我也想知道这是否可能,因为它是一个“联合文件系统”——那么是否会有一个“静态”rootfs
?
如果我理解正确的话,您不一定要访问容器的整个文件系统,而是只想访问包含应用程序的相关目录。
如果您的主要目的是允许将您的 运行-time 环境作为单个捆绑容器映像发送,但允许您的用户访问和修改应用程序文件,然后使用普通绑定卷并将文件复制到在我看来,启动将是最简单的方法,即
docker run -v $PWD:/app-data/ your_app
这会将您的当前目录作为(空的)/app-data/
绑定挂载到容器中。然后在容器中,您需要将应用程序文件复制到该目录(如果不存在):
#!/bin/bash
# script /docker-entrypoint.sh
# test if volume is already initialized
# e.g. see if src directory exists
if ! [ -d /app-data/src ]; then
# copy all files from shipped /app-dist/ to the actual run-time location
cp -a /app-dist/* /app-data/
fi
# continue executing the command
exec "$@"
这会将已发布的应用程序文件复制到主机上的已安装卷中,用户可以在其中访问和编辑它们。如果您总是 想要使用当前图像中的最新文件,您可以无条件地cp
使用它们。需要的文件需要放入Dockerfile
中的/app-dist/
这种方法的好处是非常容易支持,因为它使用普通卷。缺点当然是启动时间增加,因为必须先复制所有文件。
下一个最佳方法是使用未命名的卷并将它们绑定安装到可访问的路径:
# start container with volume
docker run -d -v /app-data/ --name your_app_container your_app
# get underlying volume path of /app-data on the host
VOLUME_HOST_PATH="$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/app-data"}}{{.Source}}{{end}}{{end}}' your_app_container)"
# bind-mount the volume path to a user-accessible path
sudo mount --bind "$VOLUME_HOST_PATH" "$target"
除了使用显式 -v
启动容器外,您还可以在 Dockerfile
.
中使用 VOLUME
这种方法的优点是 docker
会在初始化卷时为您进行复制 - 因此不需要自定义入口点 - 而且您不会依赖于 $pid
与您的解决方案中的容器一样。
但是启动时间增加的缺点仍然存在,因为仍然需要复制文件。此外,这可能不适用于所有存储驱动程序。
最后,您自己的解决方案通过绑定安装容器 /proc/$pid/root/
应该适用于所有存储驱动程序,因为 /proc/$pid/root/
允许您访问容器所见的整个文件系统 =64=],即在其命名空间内包含所有附加(绑定)装载和卷。
在任何情况下,在 docker
主机和实际 macOS / Windows 之间共享卷时,都不需要使用 bindfs
,因为访问权限的映射是在不同主机之间自动完成的操作系统。
同时,这可能会禁止后一种解决方案,因为绑定安装只能在内部 Linux VM 用作docker 主机在这种设置中不会转换为 macOS/Windows 主机上的映射路径。
附录
我刚刚想到的另一种方法:通过网络公开文件系统访问。
您可以添加另一个服务,通过 FTP、SFTP 或 SMB 等网络协议提供文件访问,或者集成到现有服务中。这将消除不必要的数据复制,并将适用于所有设置和存储驱动程序,因为它只需要公开一个网络端口。
这样做的“缺点”是这不会(自动)将卷映射到主机的本地文件系统。这 可能会也可能不会 成为您的用例的问题。
我正在尝试通过将文件夹从 container 安装到 host 来使用 docker 进行开发,作为标准主机到容器的方法不适用于我正在处理的某个项目。
目前,我按照 issue:
中的建议使用bindfs
(这也映射了用户权限)来做到这一点
pid=$( docker inspect -f '{{.State.Pid}}' "$container")
root=/proc/$pid/root
sudo bindfs --map=1000/"$(id -u)" "$root$source" "$target"
但是,从 proc
中获取 rootfs
似乎非常 脆弱 ,因为它取决于过程的 pid
。有其他方法可以做到这一点吗?
如果有找到 rootfs
的方法——无论使用何种存储驱动程序,我都可以在 bindfs
中使用它。 Where is the rootfs of container in host machine after docker 1.6.0 说它可能会根据使用的存储驱动程序而有所不同,但没有说明如何获得它。
由于性能原因,我真的不敢使用依赖于特定存储驱动程序的解决方案。我也想知道这是否可能,因为它是一个“联合文件系统”——那么是否会有一个“静态”rootfs
?
如果我理解正确的话,您不一定要访问容器的整个文件系统,而是只想访问包含应用程序的相关目录。
如果您的主要目的是允许将您的 运行-time 环境作为单个捆绑容器映像发送,但允许您的用户访问和修改应用程序文件,然后使用普通绑定卷并将文件复制到在我看来,启动将是最简单的方法,即
docker run -v $PWD:/app-data/ your_app
这会将您的当前目录作为(空的)/app-data/
绑定挂载到容器中。然后在容器中,您需要将应用程序文件复制到该目录(如果不存在):
#!/bin/bash
# script /docker-entrypoint.sh
# test if volume is already initialized
# e.g. see if src directory exists
if ! [ -d /app-data/src ]; then
# copy all files from shipped /app-dist/ to the actual run-time location
cp -a /app-dist/* /app-data/
fi
# continue executing the command
exec "$@"
这会将已发布的应用程序文件复制到主机上的已安装卷中,用户可以在其中访问和编辑它们。如果您总是 想要使用当前图像中的最新文件,您可以无条件地cp
使用它们。需要的文件需要放入Dockerfile
/app-dist/
这种方法的好处是非常容易支持,因为它使用普通卷。缺点当然是启动时间增加,因为必须先复制所有文件。
下一个最佳方法是使用未命名的卷并将它们绑定安装到可访问的路径:
# start container with volume
docker run -d -v /app-data/ --name your_app_container your_app
# get underlying volume path of /app-data on the host
VOLUME_HOST_PATH="$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/app-data"}}{{.Source}}{{end}}{{end}}' your_app_container)"
# bind-mount the volume path to a user-accessible path
sudo mount --bind "$VOLUME_HOST_PATH" "$target"
除了使用显式 -v
启动容器外,您还可以在 Dockerfile
.
VOLUME
这种方法的优点是 docker
会在初始化卷时为您进行复制 - 因此不需要自定义入口点 - 而且您不会依赖于 $pid
与您的解决方案中的容器一样。
但是启动时间增加的缺点仍然存在,因为仍然需要复制文件。此外,这可能不适用于所有存储驱动程序。
最后,您自己的解决方案通过绑定安装容器 /proc/$pid/root/
应该适用于所有存储驱动程序,因为 /proc/$pid/root/
允许您访问容器所见的整个文件系统 =64=],即在其命名空间内包含所有附加(绑定)装载和卷。
在任何情况下,在 docker
主机和实际 macOS / Windows 之间共享卷时,都不需要使用 bindfs
,因为访问权限的映射是在不同主机之间自动完成的操作系统。
同时,这可能会禁止后一种解决方案,因为绑定安装只能在内部 Linux VM 用作docker 主机在这种设置中不会转换为 macOS/Windows 主机上的映射路径。
附录
我刚刚想到的另一种方法:通过网络公开文件系统访问。
您可以添加另一个服务,通过 FTP、SFTP 或 SMB 等网络协议提供文件访问,或者集成到现有服务中。这将消除不必要的数据复制,并将适用于所有设置和存储驱动程序,因为它只需要公开一个网络端口。
这样做的“缺点”是这不会(自动)将卷映射到主机的本地文件系统。这 可能会也可能不会 成为您的用例的问题。