user568021
user568021

Reputation: 1476

Docker COPY command not mounting a directory

Host OS: Linux
Container OS: Linux

I'm trying to learn how to use docker. I use docker-compose and I'm successfully building images and running containers.

Now if I want to mount some directory inside the container the documentation says that I should use the COPY command inside Dockerfile.

COPY /path/to/my/addons/ /path/to/directory/inside/container

Sadly when I compose this container the COPY command is ignored and my stuff from /path/to/my/addons doesn't make it to the container.

I've also tried with ADD command, but same problem.

Upvotes: 2

Views: 1817

Answers (3)

Bilal Ali Jafri
Bilal Ali Jafri

Reputation: 986

Take your addon folder to location where your Dockerfile is and then run

mkdir -p /path/to/directory/inside/container
COPY ./addons/* /path/to/directory/inside/container

Upvotes: 0

Lion
Lion

Reputation: 17879

Absolute paths

First, you can't use absolute paths for COPY. All paths must be inside the context of the build, which means relative to the Dockerfile. If the folder structure on your host is like this

my-docker-directory
-- Dockerfile
-- docker-compose.yml
-- addons

then you're able to use COPY addons /path/to/directory/inside/container. For all subsequent explanations, I assume that you have an addons folder relative to the Dockerfile.

Mounting a directory

COPY doesn't simply mount a folder to the container at runtime. It doesn't really mount the directory at all. Instead, addons is copied to /path/to/directory/inside/container inside the image. It's important to understand, that this process happens unidirectional (host > image) and only happens when the image is build.

COPY is designed to add dependencies to the image that were required during buildtime like source code that got compiled to binaries. That's the reason why you can't absolute paths. A Dockerfile usually is placed together with source code/config files at the top level area.

The build process of an image happens only on the first run, except you force it using docker-compose up --build. But it doesn't seem that this is what you want. To mount a directory from the host at runtime, use a volume in the docker-compose file:

version: '3'
services:
  test:
    build: .
    volumes:
      - ./addons/:/path/to/directory/inside/container

When to use COPY and when volumes?

It's important to realize that COPY and ADD will copy the stuff into the image at buildtime, where volumes mount them from the host at runtume (without including them in the image). So you usually copy general things to the image, that the users needs like default configuration files.

Volumes are required to include files from the host like customized configuration files. Or persistent things as the data-directory of a database. Without volumes those containers work, but are not persistent. So all content would get lost when the container restarts.

Please note that one doesn't exclude the other. It's fine to COPY a default configuration for some application in the image, where the user may override this with volumes to modify them. Especially during development this can make things easier because you don't have to rebuild the entire image for a single changed config file*

* Altough it's a good practice to optimize Dockerfiles for the integrated caching mechanism. If a Dockerfile is well written, rebuilding small config changes often doesn't take too long. But that's another topic out of this scope.

More detailled explanation with example

Basic setup with COPY in Dockerfile

As simple example, we create a Dockerfile from the nginx webserver image and copy html in it

FROM nginx:alpine
COPY my-html /usr/share/nginx/html

Lets create the folder with demo content

mkdir my-html
echo "Dockerfile content" > my-html/index.html

and add a minimalistic docker-compose.yml

version: '3'
services:
  test:
    build: .

If we run it for the first time using docker-compose up -d, the image got build and our test page is served:

root@server2:~/docker-so-example# docker-compose up -d
Creating network "docker-so-example_default" with the default driver
Creating docker-so-example_test_1 ... done

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Dockerfile content

Let's manipulate our testfile:

echo "NEW Modified content" > my-html/index.html

If we request our server with curl again, we get the old response:

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Dockerfile content

To apply our content, a rebuild is required:

docker-compose down && docker-compose up -d --build

Now we can see our changes:

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
NEW Modified content

Use volumes in docker-compose

To show the difference, we use volumes by modifing our docker-compose.yml file like this:

version: '3'
services:
  test:
    build: .
    volumes:
      - ./my-html:/usr/share/nginx/html

Now restart the containers using docker-compose down && docker-compose up -d and try it again:

root@server2:~/docker-so-example# echo "Again changed content" > my-html/index.html
root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
NEW Modified content
root@server2:~/docker-so-example# echo "Some content" > my-html/index.html
root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Some content

Notice that we didn't re-build the image and our modifications apply immediately. Using volumes, the files are not included in the image.

Upvotes: 6

error404
error404

Reputation: 2823

COPY command inside a docker file copies the content to the image while building. mounting a volume is a different thing. for mounting you need to use

docker run -v <volume_name>:<volume_name> ...

what exactly you want to achieve ? Do you want to see the folders inside containers in your host ?

Upvotes: 0

Related Questions