project
└───app
│ │ ...
│ │ Dockerfile
│ │
└───prod.env
└───docker-compose.yml
我的码头组合看起来是这样的:
services:
app:
build:
context: .\app
args:
ARG1: val1
ARG2: val2
env_file:
- prod.env
但我也试过这个:
services:
app:
build:
context: .\app
args:
ARG1: ${ARG1}
ARG2: ${ARG2}
env_file:
- prod.env
我的prod.env文件如下所示:
ARG1 = 'val1'
ARG2 = 'val2'
但我也试过这个:
ARG1=val1
ARG2=val2
我希望将args的值或prod.env文件中的值传递给dockerfile。
这就是我想要得到的:
ARG ARG1
ARG ARG2
RUN echo ${ARG1}
RUN echo ${ARG2}
ENV ARG1 ${ARG1}
ENV ARG2 ${ARG2}
RUN echo ${ARG1}
RUN echo ${ARG2}
ENV ARG1 "new val2"
ENV ARG2 "new val2"
RUN echo ${ARG1}
RUN echo ${ARG2}
它始终以空值结束。
任何帮助都将不胜感激。当我尝试的时候,我觉得其他帖子的答案都没有奏效。
为了构建,我使用了docker-compose --env-file prod.env build
谢谢
更新塞尔吉奥·圣地亚哥问我是否可以运行docker-compose config
并显示结果。
以下是我在此测试中使用的最终文件。
Docker-撰写:
services:
app:
build:
context: .\app
args:
ARG1: val1
ARG2: val2
env_file:
- prod.env
Prod.env:
ARG3 = 'val3'
ARG4 = 'val4'
下面是docker-compose --env-file prod.env config
的输出
networks:
demo-net: {}
services:
app:
build:
args:
ARG1: val1
ARG2: val2
context: C:\project\app
environment:
ENV: prod.env
ARG3: val3
ARG4: val4
我想明确地补充一点,从这里将变量从.env文件获取到docker-compose文件不是问题。我还在容器上运行了一个FASK应用程序,并且通过os.environ它能够使用.env文件中的变量。我就是想不出怎么才能给Dockerfile同样的访问权限。
更新2关于ErikMD答案的更多具体信息
Prod.env
DOMAIN = 'actualdomain.com'
ENV = 'prod.env'
ENV_NUM = 1
ARG1 = 'value1'
Dev.env
DOMAIN = 'localhost'
ENV = 'dev.env'
ENV_NUM = 0
ARG1 = 'value1'
请注意,ARG1的值相同,但其他值不同。
Docker-compose.yml
version: "3.7"
services:
home:
image: home-${ENV_NUM}
build:
context: .\home
args:
ARG1: "${ARG1}"
networks:
- demo-net
env_file:
- ${ENV}
labels:
- traefik.enable=true
- traefik.http.routers.home.rule=Host(`${DOMAIN}`)
- traefik.http.routers.home.entrypoints=web
volumes:
- g:\:c:\sharedrive
...
...
reverse-proxy:
restart: always
image: traefik:v2.6.1-windowsservercore-1809
command:
- --api.insecure=true
- --providers.docker=true
- --entrypoints.web.address=:80
- --providers.docker.endpoint=npipe:////./pipe/docker_engine
ports:
- 80:80
- 443:443
- 8080:8080
networks:
- demo-net
volumes:
- source: \\.\pipe\docker_engine\
target: \\.\pipe\docker_engine\
type: npipe
networks:
demo-net:
这些圆点代表了其他与Home格式相同的应用程序。
扩展坞文件
FROM python:3.10.3
ARG ARG1="default"
ENV ARG1="${ARG1}"
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
RUN echo "This is argument 1 -> ${ARG1}"
docker-compose --env-file prod.env config
的输出
networks:
demo-net: {}
services:
home:
build:
args:
ARG1: value1
context: C:\MIS-Web-App\home
environment:
DOMAIN: actualdomain.com
ENV: prod.env
ENV_NUM: '1'
ARG1: value1
image: home-1
labels:
traefik.enable: "true"
traefik.http.routers.home.entrypoints: web
traefik.http.routers.home.rule: Host(`mis.canaras.net`)
networks:
demo-net: null
volumes:
- g:\:c:\sharedrive:rw
...
...
然后我运行docker-compose --env-file prod.env build
或docker-compose --env-file dev.env build
构建的输出
Step 9/23 : RUN echo "This is argument 1 -> ${ARG1}"
---> Running in 5142850de365
This
is
argument
1
->
Removing intermediate container 5142850de365
现在,我在命令和实际文件中传递env_file,因为其中有我的docker组成文件需要的变量和flaskapp需要的变量。而且肯定有重叠。
从prod.env或dev.env文件中获取值以进行docker-compose不是问题。把它放到我的FASK应用程序上也不是。问题是如何将这些值保存到dockerfile中。
3条答案
按热度按时间yyhrrdl81#
我的解决方案很烦人,这就是为什么我花了这么长时间才弄明白的原因。我的dockerfile使用的是Windows服务器上的PowerShell,因此我必须对每个参数执行以下操作:
这看起来很合适,特别是因为在Windows服务器上使用Windows容器不是我的第一选择,所以如果您有环境文件之类的问题,请查看@ErikMD的答案。
vq8itlhq2#
我发布了一个新的答案,以强调与OP的问题相关的各种假设,特别是
".env"
唯一文件名和*.env
文件(env_file:
的参数)之间存在细微差异的事实。但除了这一微妙之处,将参数从
docker-compose.yml
传递到docker build -f Dockerfile .
和/或docker run -e …
的过程很简单,如下面的综合示例所示。最小工作示例
让我们考虑给定目录中的以下文件,比如
./docker
。文件
docker-compose.yml
:**备注:**即使我们使用
build:
字段,添加image:
字段来自动标记构建的镜像似乎也是一个好主意;但请注意,这些镜像名称必须成对不同。文件
.env
:文件
var.env
:文件
Dockerfile
:实验一
首先,正如@SergioSantiago在评论中所建议的,在插入之后预览有效的
docker-compose.yml
文件的一个非常方便的命令是docker-compose config
:在这里,正如警告所指出的,我们看到,尽管
var.env
提到了这个变量,但是对ENV_FILE_NUM
进行内插存在问题。原因是**env_file
s行只是为底层的docker run -e …
命令添加了新的环境变量,但没有在docker-compose.yml
中插入任何内容**。相反,人们可以注意到,取自**
".env"
**的值ARG1=.env/ARG1
被内插在docker-compose.yml
的args:
字段内。输出行:官方文档的这一页描述了
".env"
与env_file
的这种截然不同的语义。实验二
接下来,让我们运行:
在这里,我们可以再次看到
".env"
和file_env: [ filename.env ]
的值扮演着不同的角色,这些角色不会重叠。此外:
ENV ARG3="${ARG3}"
,Build-ArgARG3
的值不会在运行时传播(请参阅上面输出中的ARG3=
行)。docker-compose.yml
文件的environment:
或env_file:
部分中定义/覆盖了该值,则无论如何都可以在运行时将其导出(请参见上面输出中的ARG3=var.env/ARG3
行)。有关更多详细信息,请参阅
ARG
指令的文档。docker-compose --env-file
选项用例备注正如OP所提到的,
docker-compose
还享有一个有用的CLI选项--env-file
(其名称与完全不同的env-file:
字段的命名方式完全相同,这很不幸,但没关系)。此选项支持以下用例(摘自OP的代码):
文件
docker-compose.yml
:文件
prod.env
:文件
dev.env
:然后运行:
docker-compose --env-file prod.env build
,docker-compose --env-file dev.env build
顺便说一句,即使到目前为止这个答案的大部分内容都相当于说明
".env"
文件名和env_file:
文件享有非常不同的语义…确实,按照操作人员的建议,它们也可以以这种方式“很好地”结合在一起,以实现这个用例。顺便说一句,**
docker-compose config
**也适用于对编写规范进行调试:docker-compose --env-file prod.env config
,docker-compose --env-file dev.env config
。现在,关于最后一个问题:
将
prod.env
或dev.env
文件中的值获取到docker-compose
不是问题。问题是如何将这些值传递给Dockerfile
。首先可以注意到,有两种不同的情况:
1.两个不同的部署环境(
prod.env
和dev.env
)可以共享同一个镜像,所以区别只在于运行时环境变量(而不是docker构建参数)。1.或者,根据为
--env-file
传递的文件,图像应该不同(然后确实需要docker-compose --env-file … build
)。似乎在大多数情况下,情况1.是可以实现的(在问题的配置中也是如此,因为
prod.env
和dev.env
中的ARG1
值是相同的),并且出于重现性的原因可以被视为更有趣(因为我们确信“prod”图像将与“dev”图像相同)。然而,有时不可能做到这一点,而我们是“在情况2”。例如,如果
Dockerfile
有一个特定的步骤,可能与测试或其他相关,则必须启用该步骤(Resp.禁用)。那么现在,让我们假设我们是在案例2中。我们如何才能传递从
--env-file
到Dockerfile
的“一切”呢?只有一个解决方案,即扩展docker-compose.yml
的args:
Map,并包含您感兴趣的每个变量,例如:即使没有其他解决方案可以在构建时传递参数(从
docker-compose
传递到底层的docker build -f Dockerfile …
),这也具有“声明性”的优势(只有args:
中提到的变量才会实际传递给Dockerfile
)。退款?
我看到的唯一缺点是在运行时可能会有不需要的额外环境变量(从
docker-compose
到底层的docker run -e …
),比如ENV=prod.env
。如果这是一个问题,您可能希望拆分
".env"
文件,如下所示:文件
prod.env
:文件
prod-run.env
:(假设您只想在运行时导出这两个环境变量)。
或者,为了更好地遵循通常的不重复自己规则,删除
prod-run.env
,然后将这些值作为docker-compose
构建参数传递,如前所述:和写入
Dockerfile
:我已经在**“实验会话2”一节中给出了这些
Dockerfile
指令的示例。**(很抱歉,这个答案太长了,BTW:)
lb3vh1jj3#
您可以使用docker Compose中的.env文件,以便使用您在服务定义中定义的相同时间:
通过这种方式,两者可以共享相同的env文件,但仍然存在将变量重新定义为占位符的缺点。
这是一个建议,选择一个更适合你的