使用 docker-compose 在派生映像中创建的挂载目录出错
Error mounting directory created in derived image with docker-compose
总结
使用 docker-compose,使用 Nginx 基础映像中存在的目标目录安装卷,按预期工作。但是,当挂载目标是在派生映像中创建的子目录时,docker-compose up
出现错误。这是错误的要点:
mounting "newdir" to rootfs at "/usr/share/nginx/html/newdir" caused:
mkdir newdir: read-only file system: unknown
我不明白为什么它似乎在尝试创建已经存在的目录 (newdir)!
详情
下面的完整错误:
ERROR: for test_nginx_1 Cannot start service nginx: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/home/user/test/newdir" to rootfs at "/usr/share/nginx/html/newdir" caused: mkdir /var/lib/docker/overlay2/accdaa147d7825a7d2c71b68f76e0b8663d00f6e46fcfb5c0ec32ada8baf85af/merged/usr/share/nginx/html/newdir: read-only file system: unknown
ERROR: for nginx Cannot start service nginx: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/home/user/test/newdir" to rootfs at "/usr/share/nginx/html/newdir" caused: mkdir /var/lib/docker/overlay2/accdaa147d7825a7d2c71b68f76e0b8663d00f6e46fcfb5c0ec32ada8baf85af/merged/usr/share/nginx/html/newdir: read-only file system: unknown.
这里是docker-compose.yml:
version: '3'
services:
nginx:
image: local/mynginx:withsubdir
volumes:
- ./html:/usr/share/nginx/html:ro
- ./newdir:/usr/share/nginx/html/newdir
上图 local/mynginx:withsubdir
是使用以下 Docker 文件:
构建的
FROM docker.io/library/nginx:1.21
RUN mkdir /usr/share/nginx/html/newdir && ls -lah /usr/share/nginx/html/newdir
并且我验证了我可以挂载该卷并使用 docker 查看其内容:
$ docker run --rm -ti -v /home/user/test/newdir:/usr/share/nginx/html/newdir local/mynginx:withsubdir bash
root@7db709476271:/# ls /usr/share/nginx/html/newdir
hallo.imhere
所以这个问题似乎特定于 docker-compose。如果我删除 docker-compose.yml 中的最后一行,那么 docker-compose up
会成功启动。如何挂载在派生映像中创建的目录?谢谢。
附加说明
顺便说一句,我原来的 docker-compose.yml 更长,它有一个指向 Dockerfile 创建新目录。但是我在排除故障时创建了这个较小的复制器,并且我手动构建了新图像:
docker build . -t local/mynginx:withsubdir
我在两个不同的环境(Docker version 20.10.7, build 20.10.7-0ubuntu1~20.04.1 and Docker 版本 20.10.12,构建 e91ed5707e),有或没有 :ro
.
我的test
目录文件:
.
├── docker-compose.yml
├── Dockerfile
├── html
│ └── index.html
└── newdir
└── hallo.imhere
我做了一些在线研究,但找不到任何解决方案。
问题似乎是第二个目标装载是第一个目标的子目录。构建新图像后,我将 docker-compose.yml 更改为此,现在错误消失了:
version: '3'
services:
nginx:
image: local/mynginx:withsubdir
volumes:
- ./html:/usr/share/nginx/html:ro
- ./newdir:/usr/share/nginx/newdir:ro
希望这是我可以解决的问题,但至少谜团似乎已经解开了。
Docker 正在尝试在 read-only 目录中创建挂载点,但失败了。
正常的Linuxmount(8)调用,以及底层的mount(2)系统调用,mount一些一些现有目录上的文件系统。 Linux 绑定挂载是这种情况的一种特殊情况,其中正在挂载的文件系统也是一个现有目录,而 Docker 绑定挂载使用相同的机制。
一般来说,在Docker中,如果任何类型的挂载目标不存在,Docker将创建一个新的空目录。通常这是在容器文件系统中,但如果您尝试将卷安装在其他类型的安装卷中,则安装点将在外部卷中创建。
演示这一点的一个简单方法是使用简单的 docker run
命令,在其中安装外部卷和内部卷,但外部卷实际上是绑定安装:
# Create a new empty local "outer" directory
rm -rf outer
mkdir outer
# Create a new empty container...
docker run --rm \
-v "$PWD/outer:/outer" \ # bind-mounting the outer directory
-v inner:/outer/inner \ # mounting a named volume within that
busybox \ # running any image
ls /outer # and a command that exits immediately
# Look inside the host directory, and an empty `inner` directory will exist
ls ./outer
# Clean up
docker volume rm inner
rm -rf outer
(这与的机制相同。)
现在,考虑到这些机制,您已经告诉 Docker 将外部目录挂载为 read-only,它确实做到了。然后 newdir
目录在容器文件系统中不存在,所以 Docker 尝试创建它作为挂载点,但它不能,因为该目录在 read-only 文件系统中.这就是你得到的错误。
对于纯 Docker 卷,一些可能的解决方法是:
在启动容器之前在主机文件系统上创建挂载点
mkdir ./html/newdir
docker-compose up -d
不要将外部目录挂载为read-only
volumes:
- ./html:/usr/share/nginx/html # not ...:ro
像在
中所做的那样,将内部目录安装到其他地方
volumes:
- ./html:/usr/share/nginx/html:ro
- ./newdir:/usr/share/nginx/newdir:ro # not under .../html
更好的答案仍然是完全避免此处的卷。在 Docker 文件中,您可以 COPY
此内容到您的图像中。由于容器文件系统与主机隔离,这消除了容器修改主机文件的风险,并且您可以根据需要在 Docker 文件中重组内容。这也意味着您可以 运行 另一个系统上的图像,而无需同时拥有要在那里提供的文件的副本。
FROM nginx
COPY html/ /usr/share/nginx/html/
COPY newdir/ /usr/share/nginx/html/newdir/
# no need to repeat base image's EXPOSE or CMD
总结
使用 docker-compose,使用 Nginx 基础映像中存在的目标目录安装卷,按预期工作。但是,当挂载目标是在派生映像中创建的子目录时,docker-compose up
出现错误。这是错误的要点:
mounting "newdir" to rootfs at "/usr/share/nginx/html/newdir" caused: mkdir newdir: read-only file system: unknown
我不明白为什么它似乎在尝试创建已经存在的目录 (newdir)!
详情
下面的完整错误:
ERROR: for test_nginx_1 Cannot start service nginx: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/home/user/test/newdir" to rootfs at "/usr/share/nginx/html/newdir" caused: mkdir /var/lib/docker/overlay2/accdaa147d7825a7d2c71b68f76e0b8663d00f6e46fcfb5c0ec32ada8baf85af/merged/usr/share/nginx/html/newdir: read-only file system: unknown
ERROR: for nginx Cannot start service nginx: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/home/user/test/newdir" to rootfs at "/usr/share/nginx/html/newdir" caused: mkdir /var/lib/docker/overlay2/accdaa147d7825a7d2c71b68f76e0b8663d00f6e46fcfb5c0ec32ada8baf85af/merged/usr/share/nginx/html/newdir: read-only file system: unknown.
这里是docker-compose.yml:
version: '3'
services:
nginx:
image: local/mynginx:withsubdir
volumes:
- ./html:/usr/share/nginx/html:ro
- ./newdir:/usr/share/nginx/html/newdir
上图 local/mynginx:withsubdir
是使用以下 Docker 文件:
FROM docker.io/library/nginx:1.21
RUN mkdir /usr/share/nginx/html/newdir && ls -lah /usr/share/nginx/html/newdir
并且我验证了我可以挂载该卷并使用 docker 查看其内容:
$ docker run --rm -ti -v /home/user/test/newdir:/usr/share/nginx/html/newdir local/mynginx:withsubdir bash
root@7db709476271:/# ls /usr/share/nginx/html/newdir
hallo.imhere
所以这个问题似乎特定于 docker-compose。如果我删除 docker-compose.yml 中的最后一行,那么 docker-compose up
会成功启动。如何挂载在派生映像中创建的目录?谢谢。
附加说明
顺便说一句,我原来的 docker-compose.yml 更长,它有一个指向 Dockerfile 创建新目录。但是我在排除故障时创建了这个较小的复制器,并且我手动构建了新图像:
docker build . -t local/mynginx:withsubdir
我在两个不同的环境(Docker version 20.10.7, build 20.10.7-0ubuntu1~20.04.1 and Docker 版本 20.10.12,构建 e91ed5707e),有或没有 :ro
.
我的test
目录文件:
.
├── docker-compose.yml
├── Dockerfile
├── html
│ └── index.html
└── newdir
└── hallo.imhere
我做了一些在线研究,但找不到任何解决方案。
问题似乎是第二个目标装载是第一个目标的子目录。构建新图像后,我将 docker-compose.yml 更改为此,现在错误消失了:
version: '3'
services:
nginx:
image: local/mynginx:withsubdir
volumes:
- ./html:/usr/share/nginx/html:ro
- ./newdir:/usr/share/nginx/newdir:ro
希望这是我可以解决的问题,但至少谜团似乎已经解开了。
Docker 正在尝试在 read-only 目录中创建挂载点,但失败了。
正常的Linuxmount(8)调用,以及底层的mount(2)系统调用,mount一些一些现有目录上的文件系统。 Linux 绑定挂载是这种情况的一种特殊情况,其中正在挂载的文件系统也是一个现有目录,而 Docker 绑定挂载使用相同的机制。
一般来说,在Docker中,如果任何类型的挂载目标不存在,Docker将创建一个新的空目录。通常这是在容器文件系统中,但如果您尝试将卷安装在其他类型的安装卷中,则安装点将在外部卷中创建。
演示这一点的一个简单方法是使用简单的 docker run
命令,在其中安装外部卷和内部卷,但外部卷实际上是绑定安装:
# Create a new empty local "outer" directory
rm -rf outer
mkdir outer
# Create a new empty container...
docker run --rm \
-v "$PWD/outer:/outer" \ # bind-mounting the outer directory
-v inner:/outer/inner \ # mounting a named volume within that
busybox \ # running any image
ls /outer # and a command that exits immediately
# Look inside the host directory, and an empty `inner` directory will exist
ls ./outer
# Clean up
docker volume rm inner
rm -rf outer
(这与
现在,考虑到这些机制,您已经告诉 Docker 将外部目录挂载为 read-only,它确实做到了。然后 newdir
目录在容器文件系统中不存在,所以 Docker 尝试创建它作为挂载点,但它不能,因为该目录在 read-only 文件系统中.这就是你得到的错误。
对于纯 Docker 卷,一些可能的解决方法是:
在启动容器之前在主机文件系统上创建挂载点
mkdir ./html/newdir docker-compose up -d
不要将外部目录挂载为read-only
volumes: - ./html:/usr/share/nginx/html # not ...:ro
像在
中所做的那样,将内部目录安装到其他地方volumes: - ./html:/usr/share/nginx/html:ro - ./newdir:/usr/share/nginx/newdir:ro # not under .../html
更好的答案仍然是完全避免此处的卷。在 Docker 文件中,您可以 COPY
此内容到您的图像中。由于容器文件系统与主机隔离,这消除了容器修改主机文件的风险,并且您可以根据需要在 Docker 文件中重组内容。这也意味着您可以 运行 另一个系统上的图像,而无需同时拥有要在那里提供的文件的副本。
FROM nginx
COPY html/ /usr/share/nginx/html/
COPY newdir/ /usr/share/nginx/html/newdir/
# no need to repeat base image's EXPOSE or CMD