我可以在Docker Alpine容器中使用“挂载”吗?

时间:2018-09-15 19:38:42

标签: docker sh mount alpine

我正在对一个旧项目进行Docker设计。该项目中的一个功能引入了用户指定的Git仓库,并且由于仓库的大小可能导致文件系统不堪重负,因此我创建了一个固定大小的本地文件系统,然后安装了它。这是为了防止Web主机填充其文件系统。

一般方法是这样:

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向我建议不要急于添加此功能;已经有两年了。

2 个答案:

答案 0 :(得分: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

在此服务中,我们可以通过在单个容器上安装外壳来确保容器已安装:

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

好的,太好了。因此,在保留在此外壳中的同时,让我们尝试以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

事实证明我们可以,所以对我来说看起来很健壮。

Nota bene

该卷是用typedevice的“ tmpfs”创建的,在我看来,这听起来像是RAM磁盘。我已经成功检查了卷,并在系统重新启动后保持完好无损,因此至少对我来说看起来不错。

但是,我要说的是,在组织数据持久性系统时,不要仅仅复制我拥有的内容。在将其投入生产之前,请确保该卷对于您的用例足够坚固,当然,请确保将其包括在备份过程中。

(这是针对Docker 18.06.1-ce版本,内部版本为e68fc7a)。

答案 1 :(得分:1)

您将无法在容器内安全地执行此操作。 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

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

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

唯一的前提条件是在创建服务之前创建此文件并循环设备,并且无论计划了服务的位置都可以访问此文件。我还建议使这些命令中的所有路径完全合格,而不要相对于当前目录。我很确定在某些地方相对路径不起作用。