使用Docker Compose将文件复制到容器中

179

我有一个Dockerfile,其中我将现有目录(带有内容)复制到容器中,这很正常:

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 

使用docker exec命令查看目录列表的屏幕截图

但当我使用docker-compose.yml文件时,只有aw3somevideo目录,而在aw3somevideo目录内没有任何内容。

docker-compose.yml

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

空目录截图

也许我没有理解 volumes 的功能,如果是这样,请告诉我如何通过 docker-compose.yml 文件将现有文件复制到容器中。


10
请从docker-compose文件中删除 volumes: 部分。您的镜像已经包含了数据,volumes: 部分只会覆盖数据。同时,请将其迁移至当前的docker-compose格式(版本2)。 - Bernard
@Alkaline 谢谢,那真的是问题所在。但为什么卷没有复制整个目录呢? - TheDoctor
我会以回答的形式回复,这样您就可以关闭此问题了。 - Bernard
我认为主机的文件夹将覆盖容器中的文件夹。我还找到了一些方法将容器的文件夹复制到我的主机机器上。 - chenyu
3
这个问题的标题非常误导人。它说这个主题是关于如何使用docker-compose将文件复制到容器中,但是问题和任何答案实际上都不是关于如何做到这一点的。 - Michael Firth
4个回答

167

鉴于

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

如果 /dir/on/host 不存在,将在主机上创建它,并将空内容挂载到容器中的 /var/www/html。在容器内部之前存在于 /var/www/html 中的任何内容都是不可访问的,直到您卸载该卷;新的挂载会隐藏旧内容。


3
最近的Docker版本中,即使/dir/on/host目录不存在,var/www/html/的内容也不再被复制到其中,这种情况是否可能发生?在第一次启动容器时,有没有一种方法可以强制从Docker容器内部将数据复制到主机上? - Tarator
2
@Tarator 是的,右侧不再复制到主机上了。我会更新答案。至于在容器启动时复制的方法,您可以使用类似这样的命令覆盖启动命令 docker run -v /dir/on/host:/hostdir php sh -c "cp -rp /var/www/html/* /hostdir && exec myapp"。不要忘记使用 exec 来调用最终命令,以便将其分配给 PID1。这将确保 myapp 接收到终止信号(例如 Ctrl-C)。 - Bernard
嘿,伯纳德,在你的回答中,你提到了“_右侧是否指定了命名卷,例如myvolume或主机上的路径”_。你是不是指的左手呢?因为那里是指定卷或主机路径的地方,然后将其映射到rhs上的容器位置?我确实意识到你在谈论Docker如何管理左右之间的文件复制以及它如何改变。 - charlie arehart
1
创建目录的权限是什么?我该如何更改它? - slier
@Bernard 在使用 exec 方面的技巧很棒。 - kaptan
显示剩余3条评论

18

前言:我意识到这个问题很老了,而且提问者可能已经找到了解决方法,但由于我没有看到准确的答案,所以我觉得适当回答一下提问者提出的问题以及任何相关问题。

首先,澄清命名卷绑定挂载之间的区别。前者将允许您从容器外部查看已经存在于容器位置的文件,而后者则不会。实质上,绑定挂载非常类似于在xNIX中挂载卷,这意味着在设备挂载后,挂载位置中已有的任何文件都将被屏蔽-可以将其视为叠加。

接下来,当您指定./Frontend/ :/var/www/html/时,您正在指定一个绑定挂载,这就是为什么当您在主机端查看./Frontend时,您期望看到的所有文件都消失了。如果我正确理解您的最终目标,您想通过容器内的/var/www/html/中的文件,在容器外使用完全相同的位置进行访问。如果是这样,那么您可能需要使用命名卷以及用户指定的挂载点,如下所示:

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

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

请注意,如果没有上述的driver_opts,则命名卷仍将存在,但宿主机侧的位置将在Docker区域内。通常情况下是/var/lib/docker/volumes或类似的路径。确切的位置可以在docker inspect命令的Mounts部分中找到。


示例

这是我PiHole实验室主机上类似的设置。

docker-compose.yml(缩写)

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

使用sudo docker inspect命令的输出,仅包含Mount部分(缩写)

"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",
   }
]

容器文件列表: /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

主机端文件列表:/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

依我个人之见,答案非常棒。这里是官方文档链接:https://docs.docker.com/storage/volumes/ 和 https://docs.docker.com/compose/compose-file/07-volumes/ - 404pio

5

-6
在Dockerfile中将COPY更改为ADD。这是复制目录而不是文件的方法。

3
除非您需要使用ADD支持的某些功能(例如复制和自动提取tar存档),否则几乎总是应该使用COPY而不是ADD。请参阅最佳实践:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy - Thomas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接