TL;DR/Notice:
If you experience a directory being created in place of the file you are trying to mount, you have probably failed to supply a valid and absolute path. This is a common mistake with a silent and confusing failure mode.
File volumes are done this way in docker (absolute path example (can use env variables), and you need to mention the file name) :
文件卷在docker中以这种方式完成(绝对路径示例(可以使用环境变量),您需要提及文件名):
volumes:
- /src/docker/myapp/upload:/var/www/html/upload
- /src/docker/myapp/upload/config.php:/var/www/html/config.php
You can also do:
您还可以执行以下操作:
volumes:
- ${PWD}/upload:/var/www/html/upload
- ${PWD}/upload/config.php:/var/www/html/config.php
If you fire the docker-compose from /src/docker/myapp
folder
如果启动docker-compose from/src/docker/myapp文件夹
I had been suffering from a similar issue. I was trying to import my config file to my container so that I can fix it every time I need without re-building the image.
我也有过类似的问题。我试图将我的配置文件导入到我的容器中,这样我就可以在任何需要的时候修复它,而不需要重新构建映像。
I mean I thought the below command would map $(pwd)/config.py
from Docker host to /root/app/config.py
into the container as a file.
我的意思是,我认为下面的命令会将$(Pwd)/config.py从Docker主机映射到/root/app/config.py作为一个文件到容器中。
docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image
However, it always created a directory named config.py
, not a file.
但是,它总是创建一个名为config.py的目录,而不是一个文件。
while looking for clue, I found the reason(from here)
在寻找线索的过程中,我(从这里)找到了原因
If you use -v or --volume to bind-mount a file or directory that does
not yet exist on the Docker host, -v will create the endpoint for you.
It is always created as a directory.
Therefore, it is always created as a directory because my docker host does not have $(pwd)/config.py
.
因此,它总是被创建为一个目录,因为我的docker主机没有$(Pwd)/config.py。
Even if I create config.py in docker host.
$(pwd)/config.py
just overwirte /root/app/config.py
not exporting /root/app/config.py
.
即使我在docker host中创建了config.py。$(Pwd)/config.py只是覆盖/ROOT/app/config.py,而不是导出/ROOT/app/config.py。
The way that worked for me is to use a bind
mount
对我来说起作用的方法是使用绑定坐骑
version: "3.7"
services:
app:
image: app:latest
volumes:
- type: bind
source: ./sourceFile.yaml
target: /location/targetFile.yaml
Thanks mike breed for the answer over at: Mount single file from volume using docker-compose
感谢Mike Breed给出的答案:使用docker-compose从卷装载单个文件
You need to use the "long syntax" to express a bind
mount using the volumes
key: https://docs.docker.com/compose/compose-file/compose-file-v3/#long-syntax-3
您需要使用“长语法”来表示使用卷键的绑定挂载:https://docs.docker.com/compose/compose-file/compose-file-v3/#long-syntax-3
Use mount (--mount
) instead volume (-v
)
使用装载(--mount)而不是卷(-v)
More info: https://docs.docker.com/storage/bind-mounts/
更多信息:https://docs.docker.com/storage/bind-mounts/
Example:
Ensure /tmp/a.txt exists on docker host
确保docker主机上存在/tmp/a. txt
docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh
As of docker-compose file version 3.2, you can specify a volume mount of type "bind" (instead of the default type "volume") that allows you to mount a single file into the container. Search for "bind mount" in the docker-compose volume docs:
https://docs.docker.com/compose/compose-file/#volumes
从docker-compose文件3.2版开始,您可以指定类型为“BIND”(而不是默认类型“VOLUME”)的卷挂载,允许您将单个文件挂载到容器中。在Docker-Compose卷文档中搜索“BIND MOUNT”:https://docs.docker.com/compose/compose-file/#volumes
In my case, I was trying to mount a single ".secrets" file into my application that contained secrets for local development and testing only. In production, my application fetches these secrets from AWS instead.
在我的例子中,我试图将一个“.secrets”文件装入到我的应用程序中,该文件包含仅用于本地开发和测试的机密。在生产中,我的应用程序从AWS获取这些秘密。
If I mounted this file as a volume using the shorthand syntax:
如果我使用速记语法将此文件作为卷装载:
volumes:
- ./.secrets:/data/app/.secrets
Docker would create a ".secrets" directory inside the container instead of mapping to the file outside of the container. My code would then raise an error like "IsADirectoryError: [Errno 21] Is a directory: '.secrets'".
Docker将在容器内创建“.secrets”目录,而不是映射到容器外部的文件。然后,我的代码会出现类似“IsADirectoryError:[Errno 21]is a directory:‘.secrets’”这样的错误。
I fixed this by using the long-hand syntax instead, specifying my secrets file using a read-only "bind" volume mount:
我改用了长手语法,使用只读“绑定”卷挂载指定了我的机密文件,从而修复了这个问题:
volumes:
- type: bind
source: ./.secrets
target: /data/app/.secrets
read_only: true
Now Docker correctly mounts my .secrets file into the container, creating a file inside the container instead of a directory.
现在,Docker将我的.secrets文件正确地挂载到容器中,在容器中创建了一个文件,而不是目录。
For anyone using Windows container like me, know that you CANNOT bind or mount single files using windows container.
对于像我这样使用Windows容器的人来说,要知道你不能使用Windows容器绑定或挂载单个文件。
The following examples will fail when using Windows-based containers, as the destination of a volume or bind mount inside the container must be one of: a non-existing or empty directory; or a drive other than C:. Further, the source of a bind mount must be a local directory, not a file.
net use z: \\remotemachine\share
docker run -v z:\foo:c:\dest ...
docker run -v \\uncpath\to\directory:c:\dest ...
docker run -v c:\foo\somefile.txt:c:\dest ...
docker run -v c:\foo:c: ...
docker run -v c:\foo:c:\existing-directory-with-contents ...
It's hard to spot but it's there
它很难被发现,但它就在那里
Link to the Github issue regarding mapping files into Windows container
指向有关将文件映射到Windows容器的Github问题的链接
All above answers are Correct.
以上所有答案都是正确的。
but one thing that I found really helpful is that mounted file should exist inside docker host in advance otherwise docker will create a directory instead.
但我发现有一件事非常有用,那就是挂载的文件应该事先存在于docker主机中,否则docker会创建一个目录。
for example:
例如:
/a/file/inside/host/hostFile.txt:/a/file/inside/container/containerFile.txt
hostFile.txt
should exist in advance.
otherwise you will receive this error: containerFile.txt is a directory
HostFile.txt应该提前存在。否则,您将收到此错误:tainerFile.txt是一个目录
You can also use a relative path in your docker-compose.yml
file like this (tested on Windows host, Linux container):
您还可以在docker-compose.yml文件中使用相对路径,如下所示(在Windows主机、Linux容器上测试):
volumes:
- ./test.conf:/fluentd/etc/test.conf
In compose I am using a relative path and it works:
在Compose中,我使用的是相对路径,它起作用了:
version: "3.7"
services:
svc1:
volumes:
# Current dir is parent of src
- "./src/file.conf:/path/in/container/file.conf
Using docker run
command to bind mount a file produces:
使用docker run命令绑定装载文件会产生以下结果:
docker: Error response from daemon: invalid mount config for type "bind": invalid mount path: 'path/file.conf' mount path must be absolute.
See 'docker run --help'.
Apparently the only way to do this is to specify an absolute mount path like this:
显然,执行此操作的唯一方法是指定一个绝对挂载路径,如下所示:
docker run -it --rm --mount type=bind,source="/path/to/file.conf",target=/file.conf alpine sh
also using "%cd%"
for Windows Users or "$(pwd)"
for Linux Users is a way to deal with absolute paths.
对Windows用户使用“%cd%”或对Linux用户使用“$(Pwd)”也是处理绝对路径的一种方法。
see storage bind mounts
请参见存储绑定装载
For Visual Studio Code Users make sure you are running the %cd% command in a Command Prompt Terminal, not PowerShell.
You can mount files or directories/folders it all depends on Source file or directory. And also you need to provide full path or if you are not sure you can use PWD. Here is a simple working example.
您可以挂载文件或目录/文件夹,这完全取决于源文件或目录。此外,您还需要提供完整路径,或者如果您不确定是否可以使用PWD。下面是一个简单的工作示例。
In this example, I am mounting env-commands file which already exists in my working directory
在本例中,我挂载的是工作目录中已经存在的env-Commands文件
$ docker run --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"
Be carefull if you use docker context to operate with docker on remote virtual machine. In this case the file you trying to mount will certanly not exist on target VM. Thus you not existed file will be mount as folder.
如果您使用Docker上下文在远程虚拟机上使用Docker进行操作,请务必小心。在这种情况下,您尝试挂载的文件肯定不存在于目标VM上。因此,您不存在的文件将作为文件夹挂载。
TL&DR: Docker defaults all mount points to directories. If you want to make sure your file is mounted into your docker instance, the file must already exist prior to docker-compose up and running.
Tl&dr:docker将所有挂载点默认到目录。如果您希望确保将文件装载到docker实例中,则在docker-compose启动和运行之前,该文件必须已经存在。
Explanation:
解释:
Traditionally, the purpose of mounting a volume has always meant mounting a storage location to a directory. However, that is now changing with the ability to now just share files. From a programmer's perspective, its hard to know whether a "/tmp/something" is a file or a directory. Docker, therefore, assumes all mount points are first a directory unless the file already exists.
传统上,装载卷的目的总是意味着将存储位置装载到目录。然而,随着现在只共享文件的能力的增加,这种情况正在改变。从程序员的角度来看,很难知道“/tmp/”是一个文件还是一个目录。因此,Docker假定所有挂载点首先都是一个目录,除非该文件已经存在。
In your example if you want a file to be mounted, make sure it already exists on the host system. When Docker sees that this entry already exists it will mount the file into the docker environment.
在您的示例中,如果希望挂载文件,请确保主机系统上已存在该文件。当Docker发现该条目已经存在时,它会将该文件挂载到docker环境中。
I had the same issue, docker-compose was creating a directory instead of a file, then crashing mid-way.
我也有同样的问题,docker-compose是在创建目录而不是文件,然后在中途崩溃。
what i did :
我做了什么:
run the container without mapping the file
copy the config file to the host location :
docker cp containername:/var/www/html/config.php ./config.php
remove the container (docker-compose down)
put the mapping back and remount up the container
docker compose will find the config file, and will map that instead of trying to create a directory.
Docker Compose将找到配置文件,并对其进行映射,而不是尝试创建目录。
2022 answer, on Mac with Minikube/Hyperkit docker and Docker Compose
2022答案,在配备Minikube/Hyperkit坞站和坞站的Mac上
Since I'm not using Docker Desktop any longer, I've experienced numerous issues similar to "docker in docker (dind)" paradigm with minikube...
由于我不再使用Docker Desktop了,我在使用minikube时遇到了许多类似于“docker in docker(dind)”范式的问题。
- mount minikube
- use absolute path
e.g., easiest way was to mount the exact home path...
例如,最简单的方法是安装准确的回家路径。
minikube mount $HOME:/Users/<you>
... keeps running...
docker-compose.yaml
Docker-compose.yaml
volumes:
- /Users/<you>/path/to/file.yaml:/somedir/file.yaml
For me, the issue was that I had a broken symbolic link on the file I was trying to mount into the container
对我来说,问题是我在试图挂载到容器中的文件上有一个断开的符号链接
I had the same issue on Windows, Docker 18.06.1-ce-win73 (19507)
.
我在Windows上也遇到了同样的问题,Docker 18.06.1-ce-win73(19507)。
Removing and re-adding the shared drive via the Docker settings panel and everything worked again.
通过Docker设置面板移除并重新添加共享驱动器,一切都恢复正常。
In windows,
if you need the a ${PWD} env variable in your docker-compose.yml you can creat a .env file in the same directory as your docker-compose.yml file then insert manualy the location of your folder.
在Windows中,如果您需要在docker-compose.yml中包含${pwd}环境变量,您可以在您的docker-compose.yml文件所在的目录中创建一个.env文件,然后手动插入文件夹的位置。
CMD (pwd_var.bat) :
Cmd(pwd_var.bat):
echo PWD=%cd% >> .env
Powershell (pwd_var.ps1) :
PowerShell(pwd_var.ps1):
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env
There is more good features hear for docker-compose .env variables:
https://docs.docker.com/compose/reference/envvars/ especially for the COMPOSE_CONVERT_WINDOWS_PATHS
env variable that allow docker compose to accept windows path with baskslash "\"
.
Docker-Compose.env变量还有更好的特性:https://docs.docker.com/compose/reference/envvars/,特别是Compose_Convert_WINDOWS_PATHS环境变量,它允许Docker Compose接受带有斜杠“\”的Windows路径。
When you want to share a file on windows, the file must exist before sharing it with the container.
如果要在Windows上共享文件,则在与容器共享该文件之前,该文件必须存在。
Maybe this helps someone.
也许这对某个人有帮助。
I had this problem and tried everything. Volume bindings looked well and even if I mounted directory (not files), I had the file names in the mounted directory correctly but mounted as dirs.
我遇到了这个问题,我试了所有的方法。卷绑定看起来很好,即使我挂载了目录(而不是文件),我在挂载的目录中有正确的文件名,但作为目录挂载。
I tried to re-enable shared drives and Docker complained the firewall is active.
我试图重新启用共享驱动器,Docker抱怨防火墙处于活动状态。
After disabling the firewall all was working fine.
关闭防火墙后,一切正常。
This also seems to happen if you forget to actually include the file you want to mount in the source dir. I learned the hard way. No error message such as 'file not present', instead creates a directory in the destination.
如果您忘记在源目录中实际包含要挂载的文件,似乎也会发生这种情况。我吃了苦头才学会的。不会出现错误消息,例如‘文件不存在’,而是在目标中创建一个目录。
I have same issue on my Windows 8.1
我的Windows 8.1也有同样的问题
It turned out that it was due to case-sensitivity of path.
I called docker-compose up
from directory cd /c/users/alex/
and inside container a file was turned into directory.
事实证明,这是由于Path区分大小写造成的。我从CD/c/USERS/Alex/目录调用docker-compose,在容器中将一个文件转换为目录。
But when I did cd /c/Users/alex/
(not Users capitalized) and called docker-compose up
from there, it worked.
但当我执行cd/c/USERS/Alex/(不是大写用户)并从那里调用docker-compose时,它起作用了。
In my system both Users dir and Alex dir are capitalized, though it seems like only Users dir matter.
在我的系统中,用户dir和Alex dir都是大写的,尽管似乎只有用户dir才重要。
For myself, the issue was that I specified the incorrect source file.
对我自己来说,问题是我指定了不正确的源文件。
Here's an example:
下面是一个例子:
robert ❱ ~ ❱ docker run --rm -it -v "${PWD}/non-existant:/root/destination" -w /root --entrypoint /usr/bin/ls ubuntu -lad destination
drwxr-xr-x 2 root root 64 Mar 29 05:54 destination
robert ❱ ~ ❱ touch exists
robert ❱ ~ ❱ docker run --rm -it -v "${PWD}/exists:/root/destination" -w /root --entrypoint /usr/bin/ls ubuntu -lad destination
-rw-r--r-- 1 root root 0 Mar 29 05:58 destination
robert ❱ ~ ❱
TL;DR - It could be your spelling as it was for me.
这可能是你的拼写,就像对我一样。
I'm on OSX Ventura: running docker compose up
without detach option (-d) solved issue.
我在OSX Ventura上:在没有分离选项(-d)的情况下运行码头组合解决了问题。
更多回答
Like I said, if I try /src/docker/myapp/upload/config.php:/var/www/html/config.php Docker creates the upload folder and then a config.php folder. Not a file.
就像我说的,如果我尝试一下,/src/docker/myapp/upload/config.php:/var/www/html/config.php Docker会创建一个Upload文件夹,然后再创建一个Config.php文件夹。不是一个文件。
In your post you wrote differently. If the file is there it should mount as file.
在你的帖子中,你写得不同。如果文件在那里,它应该作为文件挂载。
In order for this to work I had to supply an absolute path. The tip using PWD helped a lot here, thanks!
为了实现这一点,我必须提供一条绝对路径。使用PWD的技巧在这里帮助很大,谢谢!
For me is creating a folder rather than the files, but I think because that file is copied later in that path is there anyway to postpone the binding?
对我来说,是创建一个文件夹而不是文件,但我认为,因为该文件是在该路径中较晚复制的,所以有必要推迟绑定吗?
if /src/docker/myapp/upload/config.php doesn't exists in the host docker will create a folder... What i'm doing is creating a script that creates an empty file before running docker run - would be ideal if I can instruct docker to do it for me via cmd line args.
如果主机中不存在/src/docker/myapp/pload/config.php,docker将创建一个文件夹...我正在做的是创建一个脚本,在运行docker run之前创建一个空文件-如果我可以通过cmd行参数指示docker为我做这件事,那将是最理想的。
I just added a touch path/to/file
in the Dockerfile
so that when I mount it would still be a file (not a created dir)
我只是在Dockerfiles中添加了一个触摸路径/to/文件,这样当我挂载时,它仍然是一个文件(而不是创建的目录)
left side of :
has to be full path. It works this way
左侧:必须为完整路径。它是这样运作的
The touch
was the answer, do that in Dockerfile then your docker-compose volume mount will work correctly without creating a directory
触摸屏就是答案,在Dockerfile中这样做,那么您的docker组成的卷装载将正常工作,而不需要创建目录
And don't forget to mkdir -p /path/to/file
for good measure before touch /path/to/file
在触摸/Path/to/file之前,不要忘了mkdir-p/Path/to/file
Thanks! This was the issue for my case. I use './docker/uploads.ini:/usr/...' but the docker-compose file in in docker folder. So I change to './uploads.ini:/usr/...' and it works.
谢谢!这是我的案子的问题所在。我使用‘./docker/ploads.ini:/usr/...’但被叫者撰写的文件在被叫者文件夹中。因此,我将更改为‘./ploads.ini:/usr/...’而且它起作用了。
This answer is way more concise than the above and did exactly what I needed. Thank you.
这个答案比上面的要简洁得多,正好做了我需要的事情。谢谢。
this doesn't work in case of file is created in container, it throws Error response from daemon: invalid mount config for type "bind": bind source path does not exist
如果在容器中创建了文件,则这不起作用,它从守护进程抛出错误响应:类型“BIND”的挂载配置无效:绑定源路径不存在
Thank you Subbu, @Jakub Juszczak this should be the accepted answer, it's the only answer that answers the question at all, and it worked for me
谢谢Subbu,@Jakub Juszczak这应该是被接受的答案,这是唯一能回答这个问题的答案,它对我很管用
This does not really answer the question. volumes will work as well (because the issue is in absolute path). The only difference between --mount
and -v
is behavior when host part of the volume doesn't exist yet. As per your link: >If you use -v or --volume to bind-mount a file or directory that does not yet exist on the Docker host, -v creates the endpoint for you. It is always created as a directory.
这并没有真正回答问题。卷也可以正常工作(因为问题在绝对路径中)。--mount和-v之间的唯一区别是当卷的主机部分还不存在时的行为。根据您的链接:>如果您使用-v或--volume绑定挂载Docker主机上尚不存在的文件或目录,-v将为您创建端点。它总是被创建为一个目录。
I do not know how to translate this into a docker-compose. 'Little help?
我不知道如何把它翻译成一个码头作文。“”帮个忙好吗?
@msanford I added a docker-compose example to the answer.
@msanford我在答案中添加了一个docker-compose的例子。
I have the same error also by specifying a "bind" volume mount, any source is mounted as a directory
我有同样的错误也通过指定一个“绑定”卷挂载,任何源挂载为一个目录
Do you know if it is still the case in july 2020 ?
你知道2020年7月会不会还是这样?
@OvidiuBuligan Yes. According a comment from a docker developer on the issue, it's preferable to mount directory anyway, even on linux. They also said they cannot allow this behavior without a massive rewrite. So I really doubt we will see this in the short-medium term.
@OvidiuBuligan:是的。根据一位docker开发人员对该问题的评论,无论如何都最好挂载目录,即使是在Linux上。他们还表示,如果不进行大规模重写,他们不能允许这种行为。因此,我真的怀疑我们是否会在中短期内看到这一点。
We faced the same scenario. But in K8s it allowed mounting as a destination file from conigMap entry. Link to repo in case anyone is interested. github.com/ms-azure-demos/…
我们面临着同样的情况。但在K8S中,它允许从conigMap条目挂载为目标文件。链接到回购,以防任何人感兴趣。Githeb.com/ms-azure-demos/…
I tested this on Mac with version: '3.7'
specified in the docker-compose.yml
file with docker-compose version 1.24.1, build 4667896b, and it worked.
我在Mac上用docker-compose.yml文件中指定的版本‘3.7’与docker-compose版本1.24.1,内部版本4667896b进行了测试,它起作用了。
I still get a directory instead of a file.
我仍然得到一个目录,而不是一个文件。
And read that line over and over. I'm consistent in trying to map .env
as ./env:/app.env
and forgetting the dot (so instead of ./.env:/app.env
). I think because I already typed it (to specify current dir) my muscle memory does not want to add the second dot.. :-P
一遍又一遍地读这句话。我始终尝试将.env映射为./env:/app.env并忘记点(所以不是./.env:/app.env)。我想因为我已经输入了它(以指定当前目录),我的肌肉记忆不想添加第二个点。:-P
This is a great comment
这是一个很好的评论
This is my situation - but what should I do to solve the issue?
这就是我的情况--但我应该做些什么来解决这个问题呢?
@david-montgomery, you should change your approach or move the mounted files to the remote machine or place them to the docker image
@David-Montgomery,您应该改变您的方法或将挂载的文件移动到远程计算机或将它们放置到扩展底座映像
Yeah I was doing that already, I misunderstood what this question was saying @falko
是的,我已经在这么做了,我误解了这个问题的意思@Falko
You can not use PowerShell with docker, it creates a vendor lock-in and hurts the community...
您不能将PowerShell与docker一起使用,它会造成供应商锁定并损害社区……
Thank you for that! Your post made me realize that my selinux was set to enforcing and that was causing all of my troubles. Don't know why you were down-voted ¯_(ツ)_/¯
谢谢你这么做!你的帖子让我意识到我的selinux被设置为强制执行,这导致了我所有的麻烦。不知道为什么你被否决了_(ツ)_/
This is absolutely wrong and completely unrelated to the question. The -d
option does not affect the mounting of volumes.
这是绝对错误的,与问题完全无关。-d选项不会影响卷的装载。
@yivi in theory, right?
理论上是@yi vi,对吗?
No, in practice. That option has nothing to do with volume mounting, nor there is any way it impacts the working of mounted volumes. If it worked for you, something else changed when you used this option, which you didn't realize or noted, and correlated the wrong thing.
不,在练习中。该选项与卷装载无关,也不会以任何方式影响已装载卷的工作。如果它对你有效,那么当你使用这个选项时,其他一些东西发生了变化,你没有意识到或没有注意到,并将错误的事情联系在一起。
@yivi I really hope that you speak from knowledge based on docker internals, otherwise my answer is addressed toward lost soul who does not try this option because 'it does not make sense'.
@yivi我真的希望你能从基于Docker内部的知识中说话,否则我的回答是针对那些不尝试这个选项的迷失灵魂的,因为“它没有意义”。
It's still wrong. As advising, "try wearing red socks, it worked for me". ¯\_(ツ)_/¯
这仍然是错误的。建议说:“试试穿红色的袜子吧,对我很管用。”\_(ツ)_/
我是一名优秀的程序员,十分优秀!