如何在卷中装入单个文件

时间:2017-02-15 11:33:28

标签: docker docker-compose

我正在尝试将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文件夹。不是档案。

或者还有其他方法可以保留配置吗?

16 个答案:

答案 0 :(得分:164)

  

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

答案 1 :(得分:60)

我一直在遭遇类似的问题。我试图将配置文件导入我的容器,这样我就可以在每次需要时修复它而无需重新构建图像。

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

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

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

在寻找线索时,我找到了原因(来自here

  

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

因此,它始终作为目录创建,因为我的泊坞主机没有$(pwd)/config.py

即使我在docker host中创建config.py也是如此。 $(pwd)/config.py只是覆盖/root/app/config.py而不是导出/root/app/config.py

答案 2 :(得分:14)

从docker-compose文件版本3.2开始,您可以指定类型为“ bind”的卷挂载(而不是默认类型的“ volume”),该挂载允许您将单个文件挂载到容器。在docker-compose卷文档中搜索“ 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文件正确地安装到容器中,并在容器中创建文件而不是目录。

答案 3 :(得分:8)

以上所有答案都是正确的。

但我发现真正有用的一件事是挂载的文件应该提前存在于 docker 主机中 否则 docker 将创建一个目录。

例如:

/a/file/inside/host/hostFile.txt:/a/file/inside/container/containerFile.txt

hostFile.txt 应该提前存在。 否则您将收到此错误:containerFile.txt is a directory

答案 4 :(得分:7)

对我有用的方法是使用bind坐骑

  version: "3.7"    
  services:
  app:
    image: app:latest
    volumes:
      - type: bind
        source: ./sourceFile.yaml
        target: /location/targetFile.yaml

感谢迈克的品种在Mount single file from volume using docker-compose

给出的答案

您需要使用“长语法”表示bind挂载:https://docs.docker.com/compose/compose-file/#long-syntax

答案 5 :(得分:2)

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

  

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

     

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 there

Link to the Github issue regarding mapping files into Windows container

答案 6 :(得分:1)

您还可以像这样使用trace(mlogit:::model.matrix.mFormula, edit=TRUE)文件的相对路径(在Windows主机,Linux容器上测试):

docker-compose.yml

答案 7 :(得分:0)

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

答案 8 :(得分:0)

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

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

答案 9 :(得分:0)

使用安装代替卷(-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高山sh

答案 10 :(得分: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_PATHS env变量,该变量允许docker compose接受带有baskslash "\"的Windows路径。

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

答案 11 :(得分: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"

答案 12 :(得分:0)

我遇到了同样的问题,docker-compose正在创建目录而不是文件,然后在中途崩溃。

我做了什么:

  1. 运行容器而不映射文件

  2. 将配置文件复制到主机位置:

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

  3. 删除容器(docker-compose下来)

  4. 放回映射并重新安装容器

docker compose将找到配置文件,并将其映射,而不是尝试创建目录。

答案 13 :(得分:0)

对于使用Mac的Docker桌面的用户: 如果文件存在于本地文件系统中,但已作为目录挂载在容器内,则可能是您未与Docker Desktop共享文件/目录。 您需要检查Docker Desktop文件共享设置:

  1. 转到“首选项”->“资源”->“文件共享”。
  2. 如果缺少具有所需文件的目录,请向包含您的文件的目录添加路径。

注意!不要将根目录或任何系统目录添加到文件共享设置中,因为这会加载CPU。 Github中对此问题进行了描述,this comment提供了一种解决方法。

答案 14 :(得分:-1)

我在Windows 8.1上遇到相同的问题

原来,这是由于路径的大小写敏感所致。 我从目录docker-compose up调用了cd /c/users/alex/,然后在容器中将文件转换为目录。

但是当我做cd /c/Users/alex/(不是大写的用户)并从那里打电话给docker-compose up时,它起作用了。

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

答案 15 :(得分:-2)

也许这可以帮助某人。

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

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

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