【问题标题】:Can I use "mount" inside a Docker Alpine container?我可以在 Docker Alpine 容器中使用“mount”吗?
【发布时间】:2019-02-20 05:25:35
【问题描述】:

我正在 Dockerising 一个旧项目。项目中的一个功能引入了用户指定的 Git 存储库,由于存储库的大小可能导致文件系统不堪重负,我创建了一个固定大小的本地文件系统,然后将其挂载。这是为了防止网络主机的文件系统被填满。

一般的做法是这样的:

IMAGE=filesystem/image.img
MOUNT_POINT=filesystem/mount
SIZE=20
PROJECT_ROOT=`pwd`

# Number of M to set aside for this filing system
dd if=/dev/zero of=$IMAGE bs=1M count=$SIZE &> /dev/null

# Format: the -F permits creation even though it's not a "block special device"
mkfs.ext3 -F -q $IMAGE

# Mount if the filing system is not already mounted
$MOUNTCMD | cut -d ' ' -f 3 | grep -q "^${PROJECT_ROOT}/${MOUNT_POINT}$"
if [ $? -ne 0 ]; then
    # -p Create all parent dirs as necessary
    mkdir -p $MOUNT_POINT
    /bin/mount -t ext3 $IMAGE $MOUNT_POINT
fi

这在 Linux 本地或远程 VM 中运行良好。不过,我想在容器内部运行这个shell代码或类似的东西。我想这样做的部分原因是将所有繁琐的东西包含在一个容器中,以便构建一个新的主机尽可能简单(在我看来,设置自定义挂载和 cron-restart 规则主持人反对)。

因此,此命令在容器内不起作用(“文件系统”是主机上的 Docker 卷)

mount -t ext3 filesystem/image.img filesystem/mount
mount: can't setup loop device: No space left on device

它也不适用于容器文件夹(“filesystem2”是容器目录):

dd if=/dev/zero of=filesystem2/image.img bs=1M count=20
mount -t ext3 filesystem2/image.img filesystem2/mount
mount: can't setup loop device: No space left on device

我想知道容器是否没有合适的内部机器来进行安装,因此我是否应该改变方向。我不想在这方面花费太多时间(我只是将一个项目移动到一个仅限 Docker 的服务器),这就是为什么我想尽可能让mount 工作。

其他选项

如果这不可行,那么我需要研究一个可与 Docker 和 Swarm 一起使用的大小受限的 Docker 卷。关于这是否真的有效,网络上有相互矛盾的报道 (see this question)。

suggestion here 表示 Flocker 支持此功能。但是,我很犹豫是否要使用它,因为在 be abandoned 看来,可能受到了 ClusterHQ 破产的影响。

This post 表示我可以将--storage-opt size=120Gdocker run 一起使用。但是,docker service create 似乎不支持它(除非该选项已被重命名)。

更新

根据评论会议,我取得了一些进展;我发现将--privileged 添加到docker run 可以启用挂载,但代价是取消了安全隔离。一位乐于助人的评论者说,最好使用--cap-add SYS_ADMIN 的更细粒度的控制,让容器保留一些隔离。

但是,Docker Swarm 还没有实现这些标志,所以我不能使用这个解决方案。 This lengthy feature request 建议我不要着急添加此功能;已经等了两年了。

【问题讨论】:

  • 啊,我刚刚用--privileged在一个Ubuntu容器中挂载了一个文件。现在,我只需要在服务中执行此操作,但这还不允许;解决方法是somewhere in here
  • 您可以在容器中允许mount 使用--cap-add SYS_ADMIN 而不是--privileged
  • 谢谢@mviereck。我同意这样会更安全,但看起来(我当前版本的)Swarm (docker service create) 也不支持。

标签: docker sh mount alpine


【解决方案1】:

我找到了一个我很满意的大小限制解决方案,它根本不使用 Linux mount 命令。我还没有实现它,但是下面记录的测试已经足够令人满意了。读者不妨注意最后的小警告。

在提出这个问题之前,我没有尝试安装 Docker 卷,因为我的部分研究偶然发现了一张 Stack Overflow 海报,让人怀疑 Docker 卷是否可以遵守大小限制。我的测试表明它们可以,但您可能希望在自己的平台上进行测试以确保它适合您。

Docker 容器的大小限制

以下命令是从网络上的各种来源拼凑而成的。

首先,我创建一个像这样的卷,大小限制为 20m:

docker volume create \
    --driver local \
    --opt o=size=20m \
    --opt type=tmpfs \
    --opt device=tmpfs \
    hello-volume

然后我创建一个 Alpine Swarm 服务并在此容器上挂载:

docker service create \
    --mount source=hello-volume,target=/myvol \
    alpine \
    sleep 10000

我们可以通过在这个服务的单个容器上获取​​一个 shell 来确保容器被挂载:

docker exec -it amazing_feynman.1.lpsgoyv0jrju6fvb8skrybqap
/ # ls - /myvol
total 0

好的,太好了。因此,在保留在这个 shell 中的同时,让我们尝试以 5m 的增量慢慢压倒这个磁盘。我们可以看到它在第五次尝试时失败了,这是我们所期望的:

/ # cd /myvol
/myvol # ls
/myvol # dd if=/dev/zero of=image1 bs=1M count=5
5+0 records in
5+0 records out
/myvol # dd if=/dev/zero of=image2 bs=1M count=5
5+0 records in
5+0 records out
/myvol # ls -l
total 10240
-rw-r--r--    1 root     root       5242880 Sep 16 13:11 image1
-rw-r--r--    1 root     root       5242880 Sep 16 13:12 image2
/myvol # dd if=/dev/zero of=image3 bs=1M count=5
5+0 records in
5+0 records out
/myvol # dd if=/dev/zero of=image4 bs=1M count=5
5+0 records in
5+0 records out
/myvol # ls -l
total 20480
-rw-r--r--    1 root     root       5242880 Sep 16 13:11 image1
-rw-r--r--    1 root     root       5242880 Sep 16 13:12 image2
-rw-r--r--    1 root     root       5242880 Sep 16 13:12 image3
-rw-r--r--    1 root     root       5242880 Sep 16 13:12 image4
/myvol # dd if=/dev/zero of=image5 bs=1M count=5
dd: writing 'image5': No space left on device
1+0 records in
0+0 records out
/myvol # 

最后,让我们看看我们是否可以通过一次压倒磁盘得到错误,以防限制仅适用于满盘中新打开的文件句柄:

/ # cd /myvol
/ # rm *
/myvol # dd if=/dev/zero of=image1 bs=1M count=21
dd: writing 'image1': No space left on device
21+0 records in
20+0 records out

事实证明我们可以,所以这对我来说看起来很强大。

注意事项

该卷是使用“tmpfs”的typedevice 创建的,在我看来,这听起来像一个RAM 磁盘,令人担忧。我已成功检查卷在系统重新启动后是否保持连接且完好无损,因此对我来说看起来不错,至少目前是这样。

但是,我想说的是,在组织数据持久性系统时,不要只是复制我所拥有的。在将其投入生产之前,请确保该卷对于您的用例来说足够强大,当然,还要确保将其包含在您的备份过程中。

(这是针对 Docker 版本 18.06.1-ce,构建 e68fc7a)。

【讨论】:

  • 奇怪,该目录应该重置为空,而不会超过重新启动容器。 “tmpfs”是一个 ram 磁盘。
  • 啊,谢谢@BMitch - 我会做更多的测试。到目前为止,我只用dd 随机文件尝试过它,但是是的,它们似乎确实被保留在 Ubuntu 主机reboot 上。
【解决方案2】:

您无法在容器内安全地执行此操作。 Docker 从容器中删除了挂载权限,因为使用它可以挂载主机文件系统并转义容器。但是,您可以在容器外部执行此操作,并使用默认本地驱动程序将文件系统作为卷挂载到容器中。大多数文件系统不支持 size 选项,tmpfs 是少数例外之一。它们中的大多数使用您使用映像文件创建命令定义的底层设备的大小:

dd if=/dev/zero of=filesystem/image.img bs=1M count=$SIZE

我无法让 docker 动态创建循环设备,所以这里是手动创建它的过程:

$ sudo losetup --find --show ./vol-image.img
/dev/loop0
$ sudo mkfs -t ext3 /dev/loop0
mke2fs 1.43.4 (31-Jan-2017)
Creating filesystem with 10240 1k blocks and 2560 inodes
Filesystem UUID: 25c95fcd-6c78-4b8e-b923-f808517b28df
Superblock backups stored on blocks:
        8193

Allocating group tables: done
Writing inode tables: done
Creating journal (1024 blocks): done
Writing superblocks and filesystem accounting information: done

在定义卷挂载选项时,几乎从您在命令行上运行的挂载命令逐字传递:

docker volume create --driver local --opt type=ext3 \
  --opt device=filesystem/image.img app_vol
docker service create --mount type=volume,src=app_vol,dst=/filesystem/mount ...

或在单个服务创建命令中:

docker service create \
  --mount type=volume,src=app_vol,dst=/filesystem/mount,volume-driver=local,volume-opt=type=ext3,volume-opt=device=filesystem/image.img ...

使用docker run,命令如下:

$ docker run -it --rm --mount type=volume,dst=/data,src=ext3vol,volume-driver=local,volume-opt=type=ext3,volume-opt=device=/dev/loop0 busybox /bin/sh
/ # ls -al /data
total 17
drwxr-xr-x    3 root     root          1024 Sep 19 14:39 .
drwxr-xr-x    1 root     root          4096 Sep 19 14:40 ..
drwx------    2 root     root         12288 Sep 19 14:39 lost+found

唯一的先决条件是您在创建服务之前创建此文件和循环设备,并且该文件可在任何安排服务的地方访问。我还建议使这些命令中的所有路径都完全限定,而不是相对于当前目录。我很确定有些地方的相对路径不起作用。

【讨论】:

  • 感谢这个 BMitch,很棒的东西。关于创建大小受限的卷,正确获取像 type 这样的内容是否重要?例如,我在其他地方发现了一个线程说ext4 不起作用,因为该驱动程序不支持大小限制。您通常会在这里联系ext3 吗?
  • @halfer 我选择了 ext3 来匹配您的问题。 Docker 只是将挂载选项传递给底层的挂载命令,其中大多数限制了设备大小。
  • 啊,对,很公平。根据我在自己的回答下的评论,我将切换到 ext3 并查看大小限制是否以 tmpfs 支持的方式得到遵守,我将根据我的发现进行更新。
  • @halfer 我不认为 size 是任何 extX 文件系统类型的有效选项。您可以查看 mount 上的手册页以进行验证。它需要使用底层设备大小(使用用于创建映像文件的 dd 命令)来完成。 Tmpfs 是少数支持此选项以避免使用所有内存的文件系统之一。
  • 啊,那是最有用的,感谢 BMitch - 这些知识可能为我省去了一些麻烦,因为我可以使用基于文件的挂载。如果您可以在某处将该信息编辑到您的答案中,我会优先选择您的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
  • 2014-11-11
  • 2020-10-26
  • 1970-01-01
相关资源
最近更新 更多