我正在尝试dockerize一个PHP应用程序。在dockerfile中,我下载存档,提取它,等等。

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

因此,我认为我可以将该文件作为卷挂载,就像对数据库所做的那样。

我尝试了两种方法,用音量和直接路径。

docker-compose:

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创建upload文件夹,然后创建config.php文件夹。不是文件。

或者是否有另一种方法来持久化配置?


当前回答

在远程虚拟机上使用docker上下文操作docker时要小心。在这种情况下,您尝试挂载的文件在目标VM上肯定不存在。这样你不存在的文件将被挂载为文件夹。

其他回答

也许这能帮到别人。

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

我尝试重新启用共享驱动器,Docker抱怨防火墙是活动的。

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

在远程虚拟机上使用docker上下文操作docker时要小心。在这种情况下,您尝试挂载的文件在目标VM上肯定不存在。这样你不存在的文件将被挂载为文件夹。

在windows中, 如果你需要在docker-compose中使用a ${PWD} env变量。Yml,你可以在docker-compose的同一个目录下创建一个。env文件。Yml文件然后手动插入文件夹的位置。

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接受带有“\”的windows路径。

当您想要在windows上共享一个文件时,该文件必须在与容器共享之前存在。

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

就我而言,我是在尝试发行一款单曲。”“Secrets”文件到我的应用程序中,其中只包含本地开发和测试的秘密。在生产环境中,我的应用程序从AWS中获取这些秘密。

如果我使用简写语法将这个文件挂载为卷:

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

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

我通过使用long-hand语法来解决这个问题,使用只读的“bind”卷挂载指定我的secrets文件:

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

现在Docker正确地将我的.secrets文件挂载到容器中,在容器中创建一个文件而不是一个目录。

TL&DR: Docker默认所有挂载点到目录。如果你想确保你的文件被挂载到docker实例中,这个文件必须在docker-compose启动和运行之前已经存在。

解释:

传统上,挂载卷的目的总是意味着将存储位置挂载到目录。然而,现在这种情况正在改变,现在可以共享文件了。从程序员的角度来看,很难知道“/tmp/something”是一个文件还是一个目录。因此,Docker假定所有挂载点首先是一个目录,除非文件已经存在。

在您的示例中,如果您希望挂载一个文件,请确保它已经存在于主机系统中。当Docker看到这个条目已经存在时,它会将这个文件挂载到Docker环境中。