问题描述
在开发大型代码库时,我希望能够在容器中并行运行多个构建/测试任务。我需要将我的代码库或其他大型目录放入容器中。如果我将其以读/写方式挂载,那么并行进程会互相干扰,我需要在它们之后进行清理,而且还存在权限升级的问题。但如果我将其以只读方式挂载,那么就无法运行需要在目录内部写文件的进程。
Docker建议创建一个新的容器,将代码库复制到其中,保存为新的镜像层,然后从这个新镜像中启动多个容器。但是,每次想要运行测试时都需要复制几百兆的数据,这会导致花费太长时间。
我应该如何高效解决这个问题?
解决方案
请注意以下操作可能涉及特权权限和版本差异,请确保事先做好备份。
方案
为了解决这个问题,可以创建一个覆盖文件系统(overlay filesystem),使其覆盖在只读挂载上。但如果直接进行操作,覆盖文件系统会拒绝在另一个覆盖文件系统上设置上层和工作目录。解决方法是为上层和工作目录创建一个tmpfs,如下所示:
- 创建一个名为
run-in-c.sh
的脚本文件。 - 在脚本中设置必要的变量,如
NAME
、HOSTNAME
、CONTAINER
等。 - 使用
docker container create
命令创建一个容器,并指定挂载只读目录和基础镜像。 - 使用
docker container start
命令启动容器。 - 使用
docker container exec
命令在容器内部创建tmpfs并挂载为上层和工作目录。 - 使用
docker container exec
命令挂载覆盖文件系统。 - 使用
docker container exec
命令在容器内部执行需要的命令。 - 使用
docker container stop
命令停止容器。 - 使用
docker container rm
命令删除容器。
以下是一个示例run-in-c.sh
脚本:
#!/bin/bash
NAME=$1
shift
HOSTNAME=dock${NAME}
CONTAINER=dc-${USER}-${NAME}
REPOSITORY=${HOME}/repository
BASEIMAGE=hub.docker.io/my-org/my-base-container
OVERLAY=/mnt/overlay
LOWERDIR=/mnt/lower
UPPERDIR=${OVERLAY}/upper
WORKDIR=${OVERLAY}/work
TARGET=/mnt/repository
PRIVILEGED="--cap-add SYS_ADMIN"
docker container create --name $CONTAINER $PRIVILEGED --hostname $HOSTNAME --volume ${REPOSITORY}:${LOWERDIR}:ro $BASEIMAGE
docker container start $CONTAINER
docker container exec $CONTAINER mkdir -p $OVERLAY
docker container exec $CONTAINER mount -t tmpfs tmpfs $OVERLAY
docker container exec $CONTAINER mkdir -p $WORKDIR $UPPERDIR $TARGET
docker container exec $CONTAINER mount -t overlay overlay -o lowerdir=${LOWERDIR},upperdir=${UPPERDIR},workdir=${WORKDIR} $TARGET
docker container exec -it --workdir $TARGET $CONTAINER $*
docker container stop $CONTAINER
docker container rm $CONTAINER
使用上述脚本,你可以在容器内部运行命令,例如:
run-in-c.sh test01 'cd dir && command args'
或者获取交互式shell:
run-in-c.sh naming-stuff-is-too-hard bash
请注意,这个解决方案需要在容器内作为root用户运行,因为挂载的卷是以root:root的身份挂载到容器中的。如果你以用户身份执行命令,就无法写入文件(除非你的所有目录都是全局可写的)。如果尝试对代码库中的所有文件进行chown操作,会在上层创建它们的副本,这将产生相反的效果。如果有办法让这个解决方案以普通用户身份运行,我会很感兴趣。
正文完