我正在尝试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文件夹。不是文件。
或者是否有另一种方法来持久化配置?
TL;博士/注意:
如果您遇到在您试图挂载的文件的位置创建了一个目录,那么您可能无法提供有效的绝对路径。这是沉默和令人困惑的失败模式的常见错误。
文件卷在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
我也曾有过类似的问题。我试图将我的配置文件导入到我的容器中,这样我就可以在每次需要时修复它,而无需重新构建映像。
我的意思是,我认为下面的命令会将$(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。
在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上共享一个文件时,该文件必须在与容器共享之前存在。
对于像我这样使用Windows容器的人来说,要知道不能使用Windows容器绑定或挂载单个文件。
The following examples will fail when using Windows-based containers, as the destination of a volume or bind mount inside the container must be one of: a non-existing or empty directory; or a drive other than C:. Further, the source of a bind mount must be a local directory, not a 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问题
从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文件挂载到容器中,在容器中创建一个文件而不是一个目录。
在合成中,我使用了一个相对路径,它工作:
version: "3.7"
services:
svc1:
volumes:
# Current dir is parent of src
- "./src/file.conf:/path/in/container/file.conf
使用docker run命令绑定挂载文件会产生:
docker: Error response from daemon: invalid mount config for type "bind": invalid mount path: 'path/file.conf' mount path must be absolute.
See 'docker run --help'.
显然,这样做的唯一方法是指定一个绝对挂载路径,就像这样:
docker run -it --rm --mount type=bind,source="/path/to/file.conf",target=/file.conf alpine sh
对于Windows用户使用“%cd%”,对于Linux用户使用“$(pwd)”也是一种处理绝对路径的方法。
参见存储绑定挂载
对于Visual Studio Code用户,请确保您在命令提示符终端中运行%cd%命令,而不是PowerShell。