我正在对一个旧项目进行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=120G
与docker run
一起使用。但是,docker service create
似乎不支持它(除非该选项已重命名)。
根据评论组,我取得了一些进展;我发现将--privileged
添加到docker run
可以进行安装,但要以消除安全隔离为代价。一位有用的评论者说,最好使用--cap-add SYS_ADMIN
的更细粒度的控件,以使容器保留其某些隔离。
但是,Docker Swarm尚未实现这两个标志中的任何一个,因此我无法使用此解决方案。 This lengthy feature request向我建议不要急于添加此功能;已经有两年了。
答案 0 :(得分:1)
我找到了一个我满意的大小限制解决方案,它根本不使用Linux mount
命令。我还没有实现它,但是下面记录的测试已经足够令人满意。读者不妨注意最后的小警告。
在问这个问题之前,我没有尝试挂载Docker卷,因为我的一部分研究偶然发现了Stack Overflow海报,使人们怀疑是否可以制作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
事实证明我们可以,所以对我来说看起来很健壮。
该卷是用type
和device
的“ 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
唯一的前提条件是在创建服务之前创建此文件并循环设备,并且无论计划了服务的位置都可以访问此文件。我还建议使这些命令中的所有路径完全合格,而不要相对于当前目录。我很确定在某些地方相对路径不起作用。