121

Docker documentation says that it's possible to mount a single file into a Docker container:

The -v flag can also be used to mount a single file - instead of just directories - from the host machine.

$ docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash

This will drop you into a bash shell in a new container, you will have your bash history from the host and when you exit the container, the host will have the history of the commands typed while in the container.

When I try that however the file mounts as a directory:

tom@u ~/project $ docker run --rm -it -v file.json:/file.json test
total 80K
drwxr-xr-x  9 root root 4.0K Dec  7 12:58 .
drwxr-xr-x 63 root root 4.0K Dec  7 12:58 ..
drwxr-xr-x  2 root root 4.0K Dec  4 16:10 file.json

My Dockerfile looks like this:

FROM ubuntu:14.04
MAINTAINER Tom
CMD ["ls", "-lah", "/test"]

Docker version is 1.9.1, build a34a1d5.

Is this a documentation issue, a misunderstanding on my side, or is there something else going on?

TTT
  • 6,505
  • 10
  • 56
  • 82
  • 2
    Slightly related; if your windows password changes and you do not update it in docker for windows you might see all mounts (file or directory) showing up as empty directories – KCD Oct 11 '17 at 01:10
  • This error can be made obvious if you use `--mount` instead of `-v`, since [`mount` doesn't create directories automatically](https://docs.docker.com/storage/bind-mounts/#differences-between--v-and---mount-behavior). – deamon Apr 24 '18 at 14:33
  • 1
    When you use `-v` and put a string without `/` on the left hand side you actually create a named volume. In this case the `file.json` will be a volume that you can see with `docker volume ls`. – efx May 26 '21 at 19:06
  • In case you can't find your answer here because the file exists on the host there is one other thing that I ran into: Make sure you are using the local docker context (`docker context use default`). I've been using other contexts for remote development the other day but then forgot about that and was debugging locally created containers forever... – dom Mar 06 '23 at 08:19

11 Answers11

141

Maybe that's clear in the answers above... but it took me some time to figure it out in my case.

The underlying reason causing the file being shared with -v to appear as a directory instead of a file is that Docker could not find the file on the host. So Docker creates a new directory in the container with the name being the name of the non existing file on the host as docker thinks that the user just want to share a volume/directory that will be created in the future.

So in the problem reported above, if you used a relative directory in the -v command and docker does not understand relative directories, that means that the file was not found on the host and so docker created a directory. And the answer above which suggests to use $(pwd) will be the correct solution when the problem is due to a relative directory.

But for those reading this page who are not using a relative directory and are having the same problem... then try to understand why the file is missing on the host.

It could just be a stupid typo...

It could be that you're running the "docker run" command from a client which spawns the docker container on a different host and the file being shared does not exist on that different host. The file being shared with -v must exist on the host where the docker agent will spawn the container... not necessarily on the client where the "docker run -v ..." command is executed (although they will be the same in many cases).

There are other possible explanations above for Mac and Windows... that could be it too.

So the file missing from the host is the problem... troubleshoot the problem in your setup... using $(pwd) could be the solution but not always.

Nikopol
  • 1,419
  • 2
  • 8
  • 3
  • 8
    Nice advice. +1 – VonC Jul 06 '17 at 13:39
  • 2
    Yes, indeed +1. In certain use-cases if your container should be creating this file (and it doesn't exist on the host yet) this would indeed not work (ie. "docker run ... -v $(pwd)/file.json:" would be actually creating file.json as a *dir* and you wouldn't be able to write to it from the container since it's not a *file* but a *dir*). To workaround this make sure to create an empty file.json *file* first on the host with something like "$ touch file.json" and then running your container. – Koka Oct 18 '17 at 20:47
  • 1
    i.e. are you using docker-machine – nik.shornikov Apr 16 '18 at 14:44
  • Thanks for elaborating further on the problem. This was driving me mad! My issue was executing the docker command from the wrong pwd on the host. Lesson learned. – Karl Pokus Feb 13 '20 at 09:59
  • The point about running `docker run` not on same host as the docker engine was very insightful, helped me work around my issue. Thank you! – Lester Peabody Sep 10 '20 at 02:00
  • This had me stumped. Such a simple mistake. Now I know, Docker will think its a directory if it can't find the specific file it is trying to mount. Thanks! – Trinitrotoluene Oct 06 '20 at 03:43
  • Nice answer. However, I need the application inside the container is the one who creates the file in my use case. Is it possible to bind it, but let the container create the file that will later appear on host? – Filip Kubicz Apr 07 '23 at 13:50
  • This worked for me running docker-compuse up --build on Windows 10/WSL2/Docker Desktop. – pybynumbers Jul 26 '23 at 10:37
59

test is the name of your image that you have built with 'docker build -t test', not a /test folder.

Try a Dockerfile with:

CMD ["ls", "-lah", "/"]
or
CMD ["cat", "/file.json"]

And:

docker run --rm -it -v $(pwd)/file.json:/file.json test

Note the use of $(pwd) in order to mount a file with its full absolute path (relative paths are not supported)

By using $(pwd), you will get an absolute path which does exists, and respect the case, as opposed to a file name or path which might not exist.
An non-existing host path would be mounted as a folder in the container.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 1
    Thanks, I tried that as you suggested, but it shows an empty directory. – TTT Dec 07 '15 at 15:40
  • 1
    @TTT then try with `CMD ["ls", "-lah", "file.json"]` to see your file, or `CMD ["cat", "/file.json"]` to check its content – VonC Dec 07 '15 at 15:41
  • If I do `ls -lah` with just `file.json` it shows an empty directory, with `cat` it says `cat: file.json: Is a directory`. – TTT Dec 07 '15 at 15:45
  • 2
    @TTT can you try and mount it with `$(pwd)/`? `docker run --rm -it -v $(pwd)/file.json:/file.json test` – VonC Dec 07 '15 at 15:51
  • 2
    @TTT Great! I have included the use of an absolute path in the answer, for more visibility. – VonC Dec 07 '15 at 15:55
  • 4
    Note to people who found this via Google, the `$(pwd)` is why you came here. @Nikopol's answer below explains this in great detail. https://stackoverflow.com/a/44950494/117471 – Bruno Bronosky Jul 15 '17 at 01:09
  • Is it possible to mount just single file via named volume? – Eugen Konkov Oct 13 '22 at 06:59
  • 1
    @EugenKonkov I think it is: "[Mounting a Single File in a Volume Using Docker](https://www.baeldung.com/ops/docker-mount-single-file-in-volume)". I used to [not use a volume for that](https://stackoverflow.com/a/34135752/6309). – VonC Oct 13 '22 at 08:01
  • @VonC: Thank you. I saw that, but mounting via named volume return error: `Error response from daemon: failed to mount local volume: mount /home/kes/o/server/monitoring2/volumes/loki/loki-config.yaml:/media/kes/WORK-DATA/docker_images/volumes/monitoring2_loki-conf/_data, flags: 0x1000: not a directory` – Eugen Konkov Oct 13 '22 at 08:12
  • @EugenKonkov OK, I understand: can uou ask that as a separate question, with more details? (namely your OS and Docker version) – VonC Oct 13 '22 at 08:14
33

When running docker inside docker (by mounting /var/run/docker.sock for example), you need to be aware that if you do mounts inside docker, the filepaths that are used are always the one on your host.

So if on your host you do the following mount :

-v /tmp/foobar.txt:/my/path/foobar.txt

you should not do the following mount inside docker :

-v /my/path/foobar.txt:/my/other/path.txt

but instead, use the host filepath, eg :

-v /tmp/foobar.txt:/my/other/path.txt
yuklia
  • 6,733
  • 5
  • 20
  • 26
edi9999
  • 19,701
  • 13
  • 88
  • 127
23

I spent a bit fighting with and diagnosing this issue running docker on Windows. This could also effect people running on Mac OSX, so I add an answer here for people possibly having an issue in those environments as my search brought me to this place and to add an explanation of what appears to be happening in docker.

In Windows or Mac OSX your docker is actually running in a boot2docker VM and only the users directory is actually shared by default. On Windows, this user directory is shared as /c/Users/, however in the MinGW shell shipped with Docker Machine, the drive can be accessed as /C or /c, so this can drive you nuts if you forget the docker commands are actually running against the boot2docker VM and your file paths have to exist on the boot2docker VM and be specified in the manner that they exist there because what appears to be occurring in docker is that instead of giving a warning or error that the directory/file does not exist, docker silently creates the specified source as a directory in the boot2docker VM so there is no ready output to indicate that you are doing anything incorrectly.

So, as in the answer above, if your file is mounting as a directory, then check that you are providing an absolute path. For Windows and Mac OSX check that the absolute path that you are mounting exists in your boot2docker VM.

JDL
  • 1,477
  • 21
  • 31
  • The same seems to be true with Docker for Mac. – Lyle Jun 22 '16 at 02:36
  • This is avery helpful answer for docker toolbox users! If you just want to add a file to a container, the `docker cp` command may be useful, as described [here](http://stackoverflow.com/a/31971697/1747457) – feob Jan 06 '17 at 20:45
5

A case where Docker might not find the file, even though you're sure it exists

As edi9999 pointed out, if you tell the docker daemon to mount a file, it won't look into your current container's filesystem, it will look into the filesystem where the daemon is running.

You might have this problem if your docker daemon is running elsewhere for some reason.

❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock docker
/ # echo "bar" > /foo
/ # docker run --rm -v /foo:/foo ubuntu bash -c 'cat foo'
cat: foo: Is a directory

Docker can't find the /foo file on it's host, so it (helpfully?) creates a directory there so at least you've mounted something.

A Workaround

You can work around this by mounting a host directory into the outer container, and then using that directory for the volume you want to appear in the inner container:

❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v /dev/shm:/dev/shm docker
/ # echo "bar" > /dev/shm/foo
/ # docker run --rm -v /dev/shm/foo:/dev/shm/foo ubuntu bash -c 'cat /dev/shm/foo'
bar

This makes the path /dev/shm/foo refer to the same file in either context, so you can reference the file from the outer container, and the daemon will find it on the the host, which means it will show up as itself in the inner container, rather than as a directory.

MatrixManAtYrService
  • 8,023
  • 1
  • 50
  • 61
2

For "Docker for Mac/Windows" users, make sure the volume you're trying to mount from your host is part of your "File sharing" preferences:

enter image description here

Oliboy50
  • 2,661
  • 3
  • 27
  • 36
1

There is a simple solution for those who use the VirtualBox machine. By default, the C:/User folder is added. If your project is in C:/projects, add this folder to make it available in VB (with automount).

starski
  • 11
  • 1
1

I had the same problem as being discussed here with Docker on my MacBook and none of the suggestions worked for me. Turns out that the issue was that I did not have permissions to the file I was trying to mount (it was owned by root). I copied it to my user path and changed ownership to myself and then the file mounted as a file and not a directory. I think, if you don't have permissions, Docker interprets this as the file simply not existing and then proceeds to mount it as a new directory

JRC
  • 31
  • 2
0

In my case, on MacOS, I had something like this

version: "3.7"

services:
  if_django:
    build: ./web/
    image: if_django
    restart: always
    container_name: cf_django
    command: >
      sh -c "python manage.py collectstatic --noinput 
      && uwsgi --ini core.uwsgi.ini"
    volumes:
      - ./logs/core.log:/code/core.log
      - uwsgi-data:/tmp/uwsgi/
      - web-static:/code/static/
      - web-static:/var/www/core/assets/

  if_nginx:
    build: ./nginx/
    image: if_nginx
    restart: always
    container_name: cf_nginx
    volumes:
      - uwsgi-data:/tmp/uwsgi/
      - web-static:/var/www/core/assets/:ro
      - ./logs:/var/log/nginx/
    ports:
      - 8800:80
    depends_on: 
      - if_django

volumes:
  uwsgi-data:
  web-static:

And ./logs/core.log file was created as a directory which made the container cf_django fail to start up.

My solution?

mkdir -p logs && touch logs/core.log && docker-compose up --build -d

iChux
  • 2,266
  • 22
  • 37
0

In my case, the issue was solved by upgrading colima on mac from 0.5.2 to 0.5.4 using brew upgrade colima.

I got that hint after finding this colima issue Mount using -v does not work

rethab
  • 7,170
  • 29
  • 46
-2

I will share my experience, I tend to change my passwords a lot. I had to "reset credentials" in Docker Desktop For Windows for files to be mounted correctly (of course, you should make sure that the files are in the shared paths)

haiatn
  • 15
  • 3