如何在卷中装载单个文件


255

我正在尝试将php应用程序码头化。在dockerfile中,我下载了存档,将其解压缩等。

一切正常,但是如果发布了新版本,并且我更新了dockerfile,则必须重新安装应用程序,因为config.php被覆盖了。

因此,我以为可以像将数据库一样将文件挂载为卷。

我尝试了两种方式,分别是体积和直接路径。

码头工人组成:

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:

导致错误:

我尝试使用给定的路径(已安装的卷)进行尝试。

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

但是,这两种方式均无效。使用已装载的卷,我看到已创建上传。

但随后失败

/var/www/html/config.php \\“导致\\”不是目录\\“ \”“

如果我尝试

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

Docker创建上载文件夹,然后创建config.php文件夹。不是文件。

还是有另一种方法来保留配置?


就我而言,我很简单地在创建容器/卷之前先“触摸”一个空文件。如果文件不存在,则会创建一个目录。
FreeSoftwareServers

Answers:


310

TL; DR /通知:

如果遇到正在创建的目录来代替要挂载的文件,则可能无法提供有效绝对的路径。这是一个无声且令人困惑的故障模式的常见错误。

在docker中以这种方式完成文件卷(绝​​对路径示例(可以使用env变量),并且您需要提及文件名):

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

您也可以这样做:

    volumes:
      - ${PWD}/upload:/var/www/html/upload
      - ${PWD}/upload/config.php:/var/www/html/config.php

如果您从/src/docker/myapp文件夹中触发docker-compose


81
就像我说的,如果我尝试/src/docker/myapp/upload/config.php:/var/www/html/config.php Docker将创建上载文件夹,然后创建config.php文件夹。不是文件。
雅库布·尤斯扎克

9
在您的帖子中,您撰写的内容有所不同。如果文件存在,则应将其挂载为文件。
BlackStork

16
为了使它起作用,我必须提供一条绝对路径。在这里,使用PWD的技巧很有帮助,谢谢!
史蒂夫·史密斯

4
对我来说,创建的是文件夹而不是文件,但是我认为,由于该文件后来在该路径中复制,因此无论如何都会推迟绑定?
eKelvin

18
如果主机docker中不存在/src/docker/myapp/upload/config.php,则会创建一个文件夹...我正在做的是创建一个脚本,该脚本在运行docker run之前会创建一个空文件-理想如果我可以指示docker通过cmd行参数为我完成操作。
—cercerbero

78

我一直在遭受类似的问题。我试图将配置文件导入到我的容器中,以便我可以在每次需要时进行修复,而无需重新构建映像。

我的意思是我认为以下命令将以文件形式$(pwd)/config.py从Docker主机映射/root/app/config.py到容器。

docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image

但是,它始终创建一个名为的目录config.py,而不是文件。

在寻找线索时,我找到了原因(从这里开始

如果使用-v或--volume绑定安装Docker主机上尚不存在的文件或目录,则-v将为您创建端点。 始终将其创建为目录

因此,始终将其创建为目录,因为我的Docker主机没有$(pwd)/config.py

即使我在Docker主机中创建config.py。 $(pwd)/config.py只是/root/app/config.py不愿意不出口/root/app/config.py


16
我只是在中添加了一个touch path/to/fileDockerfile以便在挂载时它仍是一个文件(不是已创建的目录)
shadi

8
的左侧:必须是完整路径。它是这样工作的
sdkks

touch就是答案,在Dockerfile中执行该操作,然后您的docker-compose卷挂载将正确运行而无需创建目录
ctrlbrk

27

使用mount--mount)代替volume-v

更多信息:https : //docs.docker.com/storage/bind-mounts/

例:

确保Docker主机上存在/tmp/a.txt

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

谢谢Subbu,@ Jakub Juszczak,这应该是公认的答案,它是唯一可以回答这个问题的答案,它对我
有用-neokyle

2
这并不能真正回答问题。也可以正常工作(因为问题出在绝对路径上)。--mount和之间的唯一区别-v是卷的主机部分尚不存在时的行为。按照您的链接:>如果使用-v或--volume绑定安装Docker主机上尚不存在的文件或目录,则-v为您创建端点。始终将其创建为目录。
教父

2
我不知道如何将其转换为docker-compose。'有什么帮助吗?
msanford

@msanford我在答案中添加了一个docker-compose示例。
sebisnow

10

对于像我这样使用Windows容器的任何人,请知道您不能使用Windows容器绑定或装入单个文件。

使用基于Windows的容器时,以下示例将失败,因为容器内的卷或绑定安装的目的地必须是以下位置之一:不存在或空目录;或C:以外的驱动器。此外,绑定安装的源必须是本地目录,而不是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 ...

很难发现,但是在那里

链接到有关将文件映射到Windows容器的Github问题



6

您还可以docker-compose.yml像这样使用文件的相对路径(在Windows主机,Linux容器上测试):

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

1
version: '3.7'docker-compose.ymldocker-compose版本1.24.1,build 4667896b文件中指定的Mac上对此进行了测试,并且可以正常工作。
Acumenus

6
我仍然得到目录而不是文件。
chovy

6

从docker-compose文件3.2版开始,您可以指定类型为“ bind”的卷挂载(而不是默认类型的“ volume”),该卷挂载可将单个文件安装到容器中。在docker-compose卷docs中搜索“ bind mount”:https : //docs.docker.com/compose/compose-file/#volumes

就我而言,我试图将单个“ .secrets”文件装载到应用程序中,该文件只包含用于本地开发和测试的机密。在生产中,我的应用程序改为从AWS获取这些机密。

如果我使用简写语法将此文件安装为卷:

volumes:
 - ./.secrets:/data/app/.secrets

Docker会在容器内部创建一个“ .secrets” 目录,而不是映射到容器外部的文件。然后,我的代码将引发类似“ IsADirectoryError:[Errno 21]是目录:'。secrets'”的错误。

我改用了长语法来解决此问题,并使用只读的“绑定”卷安装指定了我的秘密文件:

volumes:
 - type: bind
   source: ./.secrets
   target: /data/app/.secrets
   read_only: true

现在,Docker将我的.secrets文件正确地安装到了容器中,在容器内创建了一个文件,而不是目录。希望其他人对此示例有所帮助!


谢谢你,先生!那是我需要能够挂载我的WordPress wp-config.php文件(并停止将其创建为目录)的解决方案
Jono

0

对我来说,问题是我试图装入容器的文件上的符号链接损坏了


0

我在Windows上遇到了同样的问题Docker 18.06.1-ce-win73 (19507)

通过Docker设置面板删除并重新添加共享驱动器,一切再次正常。


0

在Windows中,如果您需要在docker-compose.yml中使用$ {PWD} env变量,则可以在与docker-compose.yml文件相同的目录中创建一个.env文件,然后手动插入文件夹的位置。

CMD(pwd_var.bat):

echo PWD=%cd% >> .env

Powershell(pwd_var.ps1):

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env

docker-compose .env变量还有更多不错的功能:https ://docs.docker.com/compose/reference/envvars/, 尤其是COMPOSE_CONVERT_WINDOWS_PATHSenv变量,它允许docker compose接受带有baskslash的Windows路径"\"

如果要在Windows上共享文件,则在与容器共享文件之前,该文件必须存在。


您不能将PowerShell与docker结合使用,它会造成供应商锁定,并会伤害社区...
Matej'Yin'Gagyi

0

也许这可以帮助某人。

我遇到了这个问题,并尝试了一切。卷绑定看起来很好,即使我挂载了目录(不是文件),我在挂载的目录中也有正确的文件名,但是挂载为dirs。

我试图重新启用共享驱动器,而Docker抱怨防火墙处于活动状态。

禁用防火墙后,一切正常。


谢谢你!您的帖子使我意识到我的selinux已设置为强制执行,这引起了我的所有麻烦。不知道为什么你是向下投_(ツ)_ /¯
屋大维

0

您可以挂载文件或目录/文件夹,这完全取决于源文件或目录。另外,您还需要提供完整路径,或者如果不确定是否可以使用PWD。这是一个简单的工作示例。

在此示例中,我将挂载工作目录中已经存在的env-commands文件

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

-1

我在Windows 8.1上也有同样的问题

事实证明,这是由于路径的大小写敏感所致。我docker-compose up从目录中调用,cd /c/users/alex/并在容器内将文件转换为目录。

但是当我这样做cd /c/Users/alex/(而不是将用户大写)并docker-compose up从那里打电话时,它奏效了。

在我的系统中,User dir和Alex dir都大写,尽管看起来只有Users dir很重要。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.