How to mount a single file in a volume

DockerDocker Compose

Docker Problem Overview


I am trying to dockerize a PHP application. In the dockerfile, I download the archive, extract it, etc.

Everything works fine. However, if a new version gets released and I update the dockerfile, I have to reinstall the application, because the config.php gets overwritten.

So I thought I can mount the file as a volume, like I do with the database.

I tried it two ways, with a volume and a direct path.

docker-compose:

version: '2'
services:
  app:
    build: src
    ports:
      - "8080:80"
    depends_on:
      - mysql
    volumes:
      -  app-conf:/var/www/html/upload
      -  app-conf:/var/www/html/config.php
    environment:
      DB_TYPE: mysql
      DB_MANAGER: MysqlManager

  mysql:
    image: mysql:5.6
    container_name: mysql
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE:
      MYSQL_USER:
      MYSQL_PASSWORD:

volumes:
  mysqldata:
  app-conf:

Which results in the error:

And I tried it with a given path, as a mounted volume.

/src/docker/myapp/upload:/var/www/html/upload
/src/docker/myapp/upload:/var/www/html/config.php

However, both ways are not working. With the mounted volume, I see that upload gets created.

But then it fails with:

> /var/www/html/config.php\" caused \"not a directory\"""

If I try it with

/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.

Or is there another way to persist the config?

Docker Solutions


Solution 1 - Docker

> # 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) :

    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

Solution 2 - Docker

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.

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.

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.

Even if I create config.py in docker host. $(pwd)/config.py just overwirte /root/app/config.py not exporting /root/app/config.py.

Solution 3 - Docker

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: https://stackoverflow.com/questions/54657370/mount-single-file-from-volume-using-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

Solution 4 - Docker

Use mount (--mount) instead volume (-v)

More info: https://docs.docker.com/storage/bind-mounts/

Example:

Ensure /tmp/a.txt exists on docker host

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh

Solution 5 - Docker

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

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.

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'".

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.

Solution 6 - Docker

For anyone using Windows container like me, know that you CANNOT bind or mount single files using windows container.

> 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

Solution 7 - Docker

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.

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

Solution 8 - Docker

You can also use a relative path in your docker-compose.yml file like this (tested on Windows host, Linux container):

volumes:
    - ./test.conf:/fluentd/etc/test.conf

Solution 9 - Docker

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.

In this example, I am mounting env-commands file which already exists in my working directory

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"

Solution 10 - Docker

I had the same issue, docker-compose was creating a directory instead of a file, then crashing mid-way.

what i did :

  1. run the container without mapping the file

  2. copy the config file to the host location :

    docker cp containername:/var/www/html/config.php ./config.php

  3. remove the container (docker-compose down)

  4. 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.

Solution 11 - Docker

In compose I am using a relative path and it works:

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: 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.

see storage bind mounts

>For Visual Studio Code Users make sure you are running the %cd% command in a Command Prompt Terminal, not PowerShell.

Solution 12 - Docker

For me, the issue was that I had a broken symbolic link on the file I was trying to mount into the container

Solution 13 - Docker

I had the same issue on Windows, Docker 18.06.1-ce-win73 (19507).

Removing and re-adding the shared drive via the Docker settings panel and everything worked again.

Solution 14 - 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.

CMD (pwd_var.bat) :

echo PWD=%cd% >> .env

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 "\".

When you want to share a file on windows, the file must exist before sharing it with the container.

Solution 15 - Docker

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.

After disabling the firewall all was working fine.

Solution 16 - Docker

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.

Solution 17 - Docker

2022 answer, on Mac with Minikube/Hyperkit docker and Docker Compose

Since I'm not using Docker Desktop any longer, I've experienced numerous issues similar to "docker in docker (dind)" paradigm with minikube...

  1. mount minikube
  2. use absolute path

e.g., easiest way was to mount the exact home path...

minikube mount $HOME:/Users/<you>

... keeps running...

docker-compose.yaml

volumes:
      - /Users/<you>/path/to/file.yaml:/somedir/file.yaml

Solution 18 - Docker

I have same issue on my 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.

But when I did cd /c/Users/alex/ (not Users capitalized) and called docker-compose up from there, it worked.

In my system both Users dir and Alex dir are capitalized, though it seems like only Users dir matter.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJakub JuszczakView Question on Stackoverflow
Solution 1 - DockerBlackStorkView Answer on Stackoverflow
Solution 2 - DockerSangminKimView Answer on Stackoverflow
Solution 3 - DockerTetraDevView Answer on Stackoverflow
Solution 4 - DockerSubbu MView Answer on Stackoverflow
Solution 5 - DockerCarlton DuffettView Answer on Stackoverflow
Solution 6 - DockerJustin LessardView Answer on Stackoverflow
Solution 7 - DockerTheEhsanSarsharView Answer on Stackoverflow
Solution 8 - DockerDanielView Answer on Stackoverflow
Solution 9 - DockerAravind GVView Answer on Stackoverflow
Solution 10 - DockerChtiwi MalekView Answer on Stackoverflow
Solution 11 - DockerAffes SalemView Answer on Stackoverflow
Solution 12 - DockerjlaView Answer on Stackoverflow
Solution 13 - DockerPoolView Answer on Stackoverflow
Solution 14 - DockerCallMarlView Answer on Stackoverflow
Solution 15 - DockerJosef SáblView Answer on Stackoverflow
Solution 16 - DockerRobert JView Answer on Stackoverflow
Solution 17 - DockerrambossaView Answer on Stackoverflow
Solution 18 - DockerAlex VelickiyView Answer on Stackoverflow