Copying files to a container with Docker Compose
Asked Answered
T

4

181

I have a Dockerfile where I copy an existing directory (with content) to the container which works fine:

Dockerfile

FROM php:7.0-apache
COPY Frontend/ /var/www/html/aw3somevideo/
COPY Frontend/ /var/www/html/

RUN ls -al /var/www/html
RUN chown -R www-data:www-data /var/www/html 
RUN chmod -R 755 /var/www/html 

Screenshot of directory listing with docker exec

But when I use a docker-compose.yml file there is only the directory aw3somevideo and inside aw3somevideo there is nothing.

docker-compose.yml:

 php:
    build: php/
    volumes:
      - ./Frontend/ :/var/www/html/
      - ./Frontend/index.php :/var/www/html/
    ports:
      - 8100:80

Screenshot of empty directory listing

Maybe I do not understand the function of volumes and if that's the case please tell me how to copy my existing files to the container via a docker-compose.yml file.

Tuft answered 27/8, 2016 at 1:13 Comment(5)
Remove your volumes: section from your docker-compose file. Your image already has the data. The volumes: section just overwrites the data. Also move to the current docker-compose format (version 2).Palladio
@Alkaline thx that really was the problem. But why didn't volumes copy the whole directory?Tuft
I'll reply as an answer so you close this issue.Palladio
I think host machine‘folder will cover folder in container.I also find some way to copy container'folder to my host machine.Augsburg
The title of this question is very misleading. It says that the topic is about copying files to a container with docker-compose, but neither the question nor any of the answers is actually about how to do this.Foggy
P
170

Given

    volumes:
      - /dir/on/host:/var/www/html

if /dir/on/host doesn't exist, it is created on the host and the empty content is mounted in the container at /var/www/html. Whatever content you had before in /var/www/html inside the container is inaccessible, until you unmount the volume; the new mount is hiding the old content.

Palladio answered 27/8, 2016 at 13:7 Comment(7)
Is it possible, that with recent docker versions the content of var/www/html/ is not copied anymore to /dir/on/host even when it doesn't exist? Is there a way to force-copy the data from within the docker-container to the host when atarting a container the first time?Duster
@Duster yes indeed, the right hand side is not copied to the host anymore. I'll update the answer. As for a way to copy on container start, you can override the startup command with something like this docker run -v /dir/on/host:/hostdir php sh -c "cp -rp /var/www/html/* /hostdir && exec myapp". Don't forget to use exec to invoke the final command so that it is assigned PID1. That will make sure that myapp receives termination signals (Ctrl-C for instance).Palladio
Hi, I'm also trying to the same thing with docker-compose but getting an error, Can you please have a look at it...#45574331Dilute
Hey, Bernard, in your answer you refer to "whether the right hand side specifies a named volume like myvolume or a path on the host". Didn't you mean "left hand" there, since that's where one designates either a volume or host path, which is then mapped to the container location on the rhs? I do realize you're talking about how Docker may manage file copying between the left and right, and how it's changed.Salvatore
@charliearehart You're right. I'll fix that mistake now.Palladio
what is the permission of created directory? and how can i change it?Tackett
This is only good if you plan to keep /dir/on/host after deploy, which is not given. In general, there's no answer for the question but for a different one.Medorra
B
19

Preface: I realize this question is quite old and that the OP may have found a workaround but because I do not see an accurate answer, I felt it appropriate to address the questions posed by the OP as well as any related issues.

First, clarifying the distinction between named volumes and bind mounts. The former will allow you to see, from outside the container, files that already exist in the container location whereas the latter will not. In essence, bind mounts operate very much like when mounting a volume in xNIX meaning that any files already in the mount location will be masked after a device is mounted - think of it as an overlay.

Next, when you specify ./Frontend/ :/var/www/html/, you are specifying a bind mount which is why when you look in ./Frontend on the host-side, all of the files you expect to see are gone. If I understand your end-goal correctly, you want to have the files in /var/www/html/ within the container be accessible via the exact same location outside of the container. If so, then you probably want to use a named volume along with a user-specified mount point as follows:

volumes:
  Frontend:
    driver: local
    driver_opts:
      type: 'none'
      o: 'bind'
      device: '/var/www/html'

php:
    build: php/
    volumes:
      - Frontend:/var/www/html/

Be aware that without the driver_opts listed above, the named volume will still exist but the host-side location will be in the Docker area. This is typically something like /var/lib/docker/volumes or similar. The exact location can be found in the Mounts section of the docker inspect command.


Example

Here is a similar setup on my PiHole lab host.

docker-compose.yml (abbreviated)

volumes:
  etc-pihole:
  etc-dnsmasq.d:
  etc-unbound:
    driver: local
    driver_opts:
      type: 'none'
      o: 'bind'
      device: '/home/dockeruser/ct5/etc-unbound'

services:
  pihole:
    container_name: asbuilt_ct5
    hostname: pb-asbuilt-5
    volumes:
         - './etc-pihole:/etc/pihole/'
         - './etc-dnsmasq.d:/etc/dnsmasq.d/'
         - 'etc-unbound:/etc/unbound/'

Output of sudo docker inspect, Mount section only (abbreviated)

"Mounts": [
   {
      "Type": "bind",
      "Source": "/home/dockeruser/ct5/etc-dnsmasq.d",
      "Destination": "/etc/dnsmasq.d",
   },
   {
      "Type": "bind",
      "Source": "/home/dockeruser/ct5/etc-pihole",
      "Destination": "/etc/pihole",
   },
   {
      "Type": "volume",
      "Name": "ct5_etc-unbound",
      "Source": "/var/lib/docker/volumes/ct5_etc-unbound/_data",
      "Destination": "/etc/unbound",
      "Driver": "local",
   }
]

Container file list: /etc/unbound

root@pb-asbuilt-5:/# ls /etc/unbound
unbound.conf  unbound.conf.d  unbound_control.key  unbound_control.pem  unbound_server.key  unbound_server.pem

Host-side file list: /home/dockeruser/ct5/etc-unbound

[dockertest-srv1] > ls /home/dockeruser/ct5/etc-unbound
unbound.conf  unbound.conf.d  unbound_control.key  unbound_control.pem  unbound_server.key  unbound_server.pem
Bearded answered 6/9, 2021 at 23:49 Comment(2)
IMHO awesome answer. And here is official documentation: docs.docker.com/storage/volumes and docs.docker.com/compose/compose-file/07-volumesAbamp
If you are keeping files host-side after you ran docker-compose you have already lost. The whole point of Docker is not having unrelated files lying around in host FS.Medorra
M
9

There is no functionality in Docker Compose to copy files from host to a container during deploy. You are restricted to use of bind mounts, with several possible issues arising from that (if the destination already exists in the container it will be shadowed, if the source is removed after the deployment then container will run normally but fail upon restart).

Paper trail of the copy file feature being rejected by Compose project:

https://github.com/docker/compose/issues/2105

https://github.com/docker/compose/issues/5523

Medorra answered 19/7, 2023 at 9:15 Comment(0)
T
-6

On the Dockerfile change COPY to ADD. it is the way to copy directories and not files

Tabathatabb answered 29/4, 2021 at 21:4 Comment(1)
COPY should almost always be used over ADD, unless you specifically need something that only ADD supports (like copying and auto extracting a tar archive). See best practices: docs.docker.com/develop/develop-images/…Wideman

© 2022 - 2024 — McMap. All rights reserved.